[systemd-commits] Makefile.am src/libsystemd

Tom Gundersen tomegun at kemper.freedesktop.org
Tue Jan 21 05:41:36 PST 2014


 Makefile.am                                       |  154 
 src/libsystemd/.gitignore                         |    1 
 src/libsystemd/DIFFERENCES                        |   28 
 src/libsystemd/GVARIANT-SERIALIZATION             |   63 
 src/libsystemd/PORTING-DBUS1                      |  550 --
 src/libsystemd/bus-bloom.c                        |   99 
 src/libsystemd/bus-bloom.h                        |   29 
 src/libsystemd/bus-container.c                    |  241 
 src/libsystemd/bus-container.h                    |   27 
 src/libsystemd/bus-control.c                      | 1217 ----
 src/libsystemd/bus-control.h                      |   30 
 src/libsystemd/bus-convenience.c                  |  442 -
 src/libsystemd/bus-creds.c                        |  904 ---
 src/libsystemd/bus-creds.h                        |   75 
 src/libsystemd/bus-dump.c                         |  417 -
 src/libsystemd/bus-dump.h                         |   31 
 src/libsystemd/bus-error-mapping.gperf            |   49 
 src/libsystemd/bus-error.c                        |  504 --
 src/libsystemd/bus-error.h                        |   42 
 src/libsystemd/bus-gvariant.c                     |  249 
 src/libsystemd/bus-gvariant.h                     |   26 
 src/libsystemd/bus-internal.c                     |  305 -
 src/libsystemd/bus-internal.h                     |  328 -
 src/libsystemd/bus-introspect.c                   |  212 
 src/libsystemd/bus-introspect.h                   |   42 
 src/libsystemd/bus-kernel.c                       | 1348 -----
 src/libsystemd/bus-kernel.h                       |   81 
 src/libsystemd/bus-match.c                        | 1078 ----
 src/libsystemd/bus-match.h                        |   93 
 src/libsystemd/bus-message.c                      | 5535 ----------------------
 src/libsystemd/bus-message.h                      |  244 
 src/libsystemd/bus-objects.c                      | 2507 ---------
 src/libsystemd/bus-objects.h                      |   26 
 src/libsystemd/bus-protocol.h                     |  147 
 src/libsystemd/bus-signature.c                    |  160 
 src/libsystemd/bus-signature.h                    |   31 
 src/libsystemd/bus-socket.c                       | 1105 ----
 src/libsystemd/bus-socket.h                       |   39 
 src/libsystemd/bus-type.c                         |  179 
 src/libsystemd/bus-type.h                         |   36 
 src/libsystemd/bus-util.c                         | 1232 ----
 src/libsystemd/bus-util.h                         |  180 
 src/libsystemd/busctl.c                           |  514 --
 src/libsystemd/event-util.h                       |   30 
 src/libsystemd/kdbus.h                            |  900 ---
 src/libsystemd/resolve-util.h                     |   29 
 src/libsystemd/rtnl-internal.h                    |   99 
 src/libsystemd/rtnl-message.c                     |  887 ---
 src/libsystemd/rtnl-util.c                        |  100 
 src/libsystemd/rtnl-util.h                        |   36 
 src/libsystemd/sd-bus.c                           | 3032 ------------
 src/libsystemd/sd-bus/.gitignore                  |    1 
 src/libsystemd/sd-bus/DIFFERENCES                 |   28 
 src/libsystemd/sd-bus/GVARIANT-SERIALIZATION      |   63 
 src/libsystemd/sd-bus/Makefile                    |    1 
 src/libsystemd/sd-bus/PORTING-DBUS1               |  550 ++
 src/libsystemd/sd-bus/bus-bloom.c                 |   99 
 src/libsystemd/sd-bus/bus-bloom.h                 |   29 
 src/libsystemd/sd-bus/bus-container.c             |  241 
 src/libsystemd/sd-bus/bus-container.h             |   27 
 src/libsystemd/sd-bus/bus-control.c               | 1217 ++++
 src/libsystemd/sd-bus/bus-control.h               |   30 
 src/libsystemd/sd-bus/bus-convenience.c           |  442 +
 src/libsystemd/sd-bus/bus-creds.c                 |  904 +++
 src/libsystemd/sd-bus/bus-creds.h                 |   75 
 src/libsystemd/sd-bus/bus-dump.c                  |  417 +
 src/libsystemd/sd-bus/bus-dump.h                  |   31 
 src/libsystemd/sd-bus/bus-error-mapping.gperf     |   49 
 src/libsystemd/sd-bus/bus-error.c                 |  504 ++
 src/libsystemd/sd-bus/bus-error.h                 |   42 
 src/libsystemd/sd-bus/bus-gvariant.c              |  249 
 src/libsystemd/sd-bus/bus-gvariant.h              |   26 
 src/libsystemd/sd-bus/bus-internal.c              |  305 +
 src/libsystemd/sd-bus/bus-internal.h              |  328 +
 src/libsystemd/sd-bus/bus-introspect.c            |  212 
 src/libsystemd/sd-bus/bus-introspect.h            |   42 
 src/libsystemd/sd-bus/bus-kernel.c                | 1348 +++++
 src/libsystemd/sd-bus/bus-kernel.h                |   81 
 src/libsystemd/sd-bus/bus-match.c                 | 1078 ++++
 src/libsystemd/sd-bus/bus-match.h                 |   93 
 src/libsystemd/sd-bus/bus-message.c               | 5535 ++++++++++++++++++++++
 src/libsystemd/sd-bus/bus-message.h               |  244 
 src/libsystemd/sd-bus/bus-objects.c               | 2507 +++++++++
 src/libsystemd/sd-bus/bus-objects.h               |   26 
 src/libsystemd/sd-bus/bus-protocol.h              |  147 
 src/libsystemd/sd-bus/bus-signature.c             |  160 
 src/libsystemd/sd-bus/bus-signature.h             |   31 
 src/libsystemd/sd-bus/bus-socket.c                | 1105 ++++
 src/libsystemd/sd-bus/bus-socket.h                |   39 
 src/libsystemd/sd-bus/bus-type.c                  |  179 
 src/libsystemd/sd-bus/bus-type.h                  |   36 
 src/libsystemd/sd-bus/bus-util.c                  | 1232 ++++
 src/libsystemd/sd-bus/bus-util.h                  |  180 
 src/libsystemd/sd-bus/busctl.c                    |  514 ++
 src/libsystemd/sd-bus/kdbus.h                     |  900 +++
 src/libsystemd/sd-bus/sd-bus.c                    | 3032 ++++++++++++
 src/libsystemd/sd-bus/sd-memfd.c                  |  220 
 src/libsystemd/sd-bus/test-bus-chat.c             |  581 ++
 src/libsystemd/sd-bus/test-bus-cleanup.c          |   80 
 src/libsystemd/sd-bus/test-bus-creds.c            |   46 
 src/libsystemd/sd-bus/test-bus-error.c            |  115 
 src/libsystemd/sd-bus/test-bus-gvariant.c         |  201 
 src/libsystemd/sd-bus/test-bus-introspect.c       |   66 
 src/libsystemd/sd-bus/test-bus-kernel-benchmark.c |  303 +
 src/libsystemd/sd-bus/test-bus-kernel-bloom.c     |  115 
 src/libsystemd/sd-bus/test-bus-kernel.c           |  175 
 src/libsystemd/sd-bus/test-bus-marshal.c          |  324 +
 src/libsystemd/sd-bus/test-bus-match.c            |  145 
 src/libsystemd/sd-bus/test-bus-memfd.c            |  174 
 src/libsystemd/sd-bus/test-bus-objects.c          |  500 +
 src/libsystemd/sd-bus/test-bus-server.c           |  224 
 src/libsystemd/sd-bus/test-bus-signature.c        |  163 
 src/libsystemd/sd-bus/test-bus-zero-copy.c        |  197 
 src/libsystemd/sd-event.c                         | 2224 --------
 src/libsystemd/sd-event/Makefile                  |    1 
 src/libsystemd/sd-event/event-util.h              |   30 
 src/libsystemd/sd-event/sd-event.c                | 2224 ++++++++
 src/libsystemd/sd-event/test-event.c              |  248 
 src/libsystemd/sd-memfd.c                         |  220 
 src/libsystemd/sd-resolve.c                       | 1130 ----
 src/libsystemd/sd-resolve/Makefile                |    1 
 src/libsystemd/sd-resolve/resolve-util.h          |   29 
 src/libsystemd/sd-resolve/sd-resolve.c            | 1130 ++++
 src/libsystemd/sd-resolve/test-resolve.c          |  160 
 src/libsystemd/sd-rtnl.c                          |  870 ---
 src/libsystemd/sd-rtnl/Makefile                   |    1 
 src/libsystemd/sd-rtnl/rtnl-internal.h            |   99 
 src/libsystemd/sd-rtnl/rtnl-message.c             |  887 +++
 src/libsystemd/sd-rtnl/rtnl-util.c                |  100 
 src/libsystemd/sd-rtnl/rtnl-util.h                |   36 
 src/libsystemd/sd-rtnl/sd-rtnl.c                  |  870 +++
 src/libsystemd/sd-rtnl/test-rtnl.c                |  330 +
 src/libsystemd/sd-utf8.c                          |   36 
 src/libsystemd/sd-utf8/Makefile                   |    1 
 src/libsystemd/sd-utf8/sd-utf8.c                  |   36 
 src/libsystemd/test-bus-chat.c                    |  581 --
 src/libsystemd/test-bus-cleanup.c                 |   80 
 src/libsystemd/test-bus-creds.c                   |   46 
 src/libsystemd/test-bus-error.c                   |  115 
 src/libsystemd/test-bus-gvariant.c                |  201 
 src/libsystemd/test-bus-introspect.c              |   66 
 src/libsystemd/test-bus-kernel-benchmark.c        |  303 -
 src/libsystemd/test-bus-kernel-bloom.c            |  115 
 src/libsystemd/test-bus-kernel.c                  |  175 
 src/libsystemd/test-bus-marshal.c                 |  324 -
 src/libsystemd/test-bus-match.c                   |  145 
 src/libsystemd/test-bus-memfd.c                   |  174 
 src/libsystemd/test-bus-objects.c                 |  500 -
 src/libsystemd/test-bus-server.c                  |  224 
 src/libsystemd/test-bus-signature.c               |  163 
 src/libsystemd/test-bus-zero-copy.c               |  197 
 src/libsystemd/test-event.c                       |  248 
 src/libsystemd/test-resolve.c                     |  160 
 src/libsystemd/test-rtnl.c                        |  330 -
 154 files changed, 34269 insertions(+), 34262 deletions(-)

New commits:
commit 607553f9306286fdccf0b356bc3d1087adfe21c4
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Jan 21 14:10:18 2014 +0100

    libsystemd: split up into subdirs
    
    We still only produce on .so, but let's keep the sources separate to make things a bit
    less messy.

diff --git a/Makefile.am b/Makefile.am
index 8a897cd..935a195 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -189,7 +189,9 @@ AM_CPPFLAGS = \
 	-I $(top_srcdir)/src/udev \
 	-I $(top_srcdir)/src/udev/net \
 	-I $(top_builddir)/src/udev \
-	-I $(top_srcdir)/src/libsystemd \
+	-I $(top_srcdir)/src/libsystemd/sd-bus \
+	-I $(top_srcdir)/src/libsystemd/sd-event \
+	-I $(top_srcdir)/src/libsystemd/sd-rtnl \
 	$(OUR_CPPFLAGS)
 
 AM_CFLAGS = $(OUR_CFLAGS)
@@ -1984,56 +1986,56 @@ libsystemd_la_SOURCES = \
 	src/systemd/sd-event.h \
 	src/systemd/sd-rtnl.h \
 	src/systemd/sd-resolve.h \
-	src/libsystemd/sd-bus.c \
-	src/libsystemd/bus-control.c \
-	src/libsystemd/bus-control.h \
-	src/libsystemd/bus-error.c \
-	src/libsystemd/bus-error.h \
-	src/libsystemd/bus-internal.c \
-	src/libsystemd/bus-internal.h \
-	src/libsystemd/bus-socket.c \
-	src/libsystemd/bus-socket.h \
-	src/libsystemd/bus-kernel.c \
-	src/libsystemd/bus-kernel.h \
-	src/libsystemd/bus-container.c \
-	src/libsystemd/bus-container.h \
-	src/libsystemd/bus-message.c \
-	src/libsystemd/bus-message.h \
-	src/libsystemd/bus-creds.c \
-	src/libsystemd/bus-creds.h \
-	src/libsystemd/bus-signature.c \
-	src/libsystemd/bus-signature.h \
-	src/libsystemd/bus-type.c \
-	src/libsystemd/bus-type.h \
-	src/libsystemd/bus-match.c \
-	src/libsystemd/bus-match.h \
-	src/libsystemd/bus-bloom.c \
-	src/libsystemd/bus-bloom.h \
-	src/libsystemd/bus-introspect.c \
-	src/libsystemd/bus-introspect.h \
-	src/libsystemd/bus-objects.c \
-	src/libsystemd/bus-objects.h \
-	src/libsystemd/bus-gvariant.c \
-	src/libsystemd/bus-gvariant.h \
-	src/libsystemd/bus-convenience.c \
-	src/libsystemd/kdbus.h \
-	src/libsystemd/sd-memfd.c \
-	src/libsystemd/bus-util.c \
-	src/libsystemd/bus-util.h \
-	src/libsystemd/sd-utf8.c \
-	src/libsystemd/sd-event.c \
-	src/libsystemd/event-util.h \
-	src/libsystemd/bus-protocol.h \
-	src/libsystemd/sd-rtnl.c \
-	src/libsystemd/rtnl-internal.h \
-	src/libsystemd/rtnl-message.c \
-	src/libsystemd/rtnl-util.h \
-	src/libsystemd/rtnl-util.c \
-	src/libsystemd/sd-resolve.c \
-	src/libsystemd/resolve-util.h
+	src/libsystemd/sd-bus/sd-bus.c \
+	src/libsystemd/sd-bus/bus-control.c \
+	src/libsystemd/sd-bus/bus-control.h \
+	src/libsystemd/sd-bus/bus-error.c \
+	src/libsystemd/sd-bus/bus-error.h \
+	src/libsystemd/sd-bus/bus-internal.c \
+	src/libsystemd/sd-bus/bus-internal.h \
+	src/libsystemd/sd-bus/bus-socket.c \
+	src/libsystemd/sd-bus/bus-socket.h \
+	src/libsystemd/sd-bus/bus-kernel.c \
+	src/libsystemd/sd-bus/bus-kernel.h \
+	src/libsystemd/sd-bus/bus-container.c \
+	src/libsystemd/sd-bus/bus-container.h \
+	src/libsystemd/sd-bus/bus-message.c \
+	src/libsystemd/sd-bus/bus-message.h \
+	src/libsystemd/sd-bus/bus-creds.c \
+	src/libsystemd/sd-bus/bus-creds.h \
+	src/libsystemd/sd-bus/bus-signature.c \
+	src/libsystemd/sd-bus/bus-signature.h \
+	src/libsystemd/sd-bus/bus-type.c \
+	src/libsystemd/sd-bus/bus-type.h \
+	src/libsystemd/sd-bus/bus-match.c \
+	src/libsystemd/sd-bus/bus-match.h \
+	src/libsystemd/sd-bus/bus-bloom.c \
+	src/libsystemd/sd-bus/bus-bloom.h \
+	src/libsystemd/sd-bus/bus-introspect.c \
+	src/libsystemd/sd-bus/bus-introspect.h \
+	src/libsystemd/sd-bus/bus-objects.c \
+	src/libsystemd/sd-bus/bus-objects.h \
+	src/libsystemd/sd-bus/bus-gvariant.c \
+	src/libsystemd/sd-bus/bus-gvariant.h \
+	src/libsystemd/sd-bus/bus-convenience.c \
+	src/libsystemd/sd-bus/bus-util.c \
+	src/libsystemd/sd-bus/bus-util.h \
+	src/libsystemd/sd-bus/bus-protocol.h \
+	src/libsystemd/sd-bus/kdbus.h \
+	src/libsystemd/sd-bus/sd-memfd.c \
+	src/libsystemd/sd-utf8/sd-utf8.c \
+	src/libsystemd/sd-event/sd-event.c \
+	src/libsystemd/sd-event/event-util.h \
+	src/libsystemd/sd-rtnl/sd-rtnl.c \
+	src/libsystemd/sd-rtnl/rtnl-internal.h \
+	src/libsystemd/sd-rtnl/rtnl-message.c \
+	src/libsystemd/sd-rtnl/rtnl-util.h \
+	src/libsystemd/sd-rtnl/rtnl-util.c \
+	src/libsystemd/sd-resolve/sd-resolve.c \
+	src/libsystemd/sd-resolve/resolve-util.h
 
 nodist_libsystemd_la_SOURCES = \
-	src/libsystemd/bus-error-mapping.c
+	src/libsystemd/sd-bus/bus-error-mapping.c
 
 libsystemd_la_LIBADD = \
 	libsystemd-id128-internal.la \
@@ -2054,13 +2056,13 @@ pkgconfiglib_DATA += \
 	src/libsystemd/libsystemd.pc
 
 EXTRA_DIST += \
-	src/libsystemd/bus-error-mapping.gperf \
-	src/libsystemd/libsystemd.pc.in \
-	src/libsystemd/DIFFERENCES \
-	src/libsystemd/GVARIANT-SERIALIZATION
+	src/libsystemd/sd-bus/bus-error-mapping.gperf \
+	src/libsystemd/sd-bus/DIFFERENCES \
+	src/libsystemd/sd-bus/GVARIANT-SERIALIZATION \
+	src/libsystemd/libsystemd.pc.in
 
 CLEANFILES += \
-	src/libsystemd/bus-error-mapping.c
+	src/libsystemd/sd-bus/bus-error-mapping.c
 
 lib_LTLIBRARIES += \
 	libsystemd.la
@@ -2078,8 +2080,8 @@ noinst_LTLIBRARIES += \
 	libsystemd-internal.la
 
 libsystemd_dump_la_SOURCES = \
-	src/libsystemd/bus-dump.c \
-	src/libsystemd/bus-dump.h
+	src/libsystemd/sd-bus/bus-dump.c \
+	src/libsystemd/sd-bus/bus-dump.h
 
 libsystemd_dump_la_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -2113,7 +2115,7 @@ bin_PROGRAMS += \
 	busctl
 
 test_bus_marshal_SOURCES = \
-	src/libsystemd/test-bus-marshal.c
+	src/libsystemd/sd-bus/test-bus-marshal.c
 
 test_bus_marshal_LDADD = \
 	libsystemd-internal.la \
@@ -2133,14 +2135,14 @@ test_bus_marshal_CFLAGS = \
 	$(CAP_CFLAGS)
 
 test_bus_signature_SOURCES = \
-	src/libsystemd/test-bus-signature.c
+	src/libsystemd/sd-bus/test-bus-signature.c
 
 test_bus_signature_LDADD = \
 	libsystemd-shared.la \
 	libsystemd-internal.la
 
 test_bus_chat_SOURCES = \
-	src/libsystemd/test-bus-chat.c
+	src/libsystemd/sd-bus/test-bus-chat.c
 
 test_bus_chat_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -2153,7 +2155,7 @@ test_bus_chat_LDADD = \
 	libsystemd-shared.la
 
 test_bus_cleanup_SOURCES = \
-	src/libsystemd/test-bus-cleanup.c
+	src/libsystemd/sd-bus/test-bus-cleanup.c
 
 test_bus_cleanup_LDADD = \
 	libsystemd-internal.la \
@@ -2162,7 +2164,7 @@ test_bus_cleanup_LDADD = \
 	libsystemd-shared.la
 
 test_bus_server_SOURCES = \
-	src/libsystemd/test-bus-server.c
+	src/libsystemd/sd-bus/test-bus-server.c
 
 test_bus_server_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -2175,7 +2177,7 @@ test_bus_server_LDADD = \
 	libsystemd-shared.la
 
 test_bus_objects_SOURCES = \
-	src/libsystemd/test-bus-objects.c
+	src/libsystemd/sd-bus/test-bus-objects.c
 
 test_bus_objects_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -2192,7 +2194,7 @@ test_bus_objects_LDADD = \
 	$(CAP_LIBS)
 
 test_bus_error_SOURCES = \
-	src/libsystemd/test-bus-error.c
+	src/libsystemd/sd-bus/test-bus-error.c
 
 test_bus_error_LDADD = \
 	libsystemd-internal.la \
@@ -2201,7 +2203,7 @@ test_bus_error_LDADD = \
 	libsystemd-shared.la
 
 test_bus_gvariant_SOURCES = \
-	src/libsystemd/test-bus-gvariant.c
+	src/libsystemd/sd-bus/test-bus-gvariant.c
 
 test_bus_gvariant_LDADD = \
 	libsystemd-internal.la \
@@ -2219,7 +2221,7 @@ test_bus_gvariant_CFLAGS = \
 	$(CAP_CFLAGS)
 
 test_bus_creds_SOURCES = \
-	src/libsystemd/test-bus-creds.c
+	src/libsystemd/sd-bus/test-bus-creds.c
 
 test_bus_creds_LDADD = \
 	libsystemd-internal.la \
@@ -2230,7 +2232,7 @@ test_bus_creds_LDADD = \
 	libsystemd-capability.la
 
 test_bus_match_SOURCES = \
-	src/libsystemd/test-bus-match.c
+	src/libsystemd/sd-bus/test-bus-match.c
 
 test_bus_match_LDADD = \
 	libsystemd-internal.la \
@@ -2239,7 +2241,7 @@ test_bus_match_LDADD = \
 	libsystemd-shared.la
 
 test_bus_kernel_SOURCES = \
-	src/libsystemd/test-bus-kernel.c
+	src/libsystemd/sd-bus/test-bus-kernel.c
 
 test_bus_kernel_LDADD = \
 	libsystemd-internal.la \
@@ -2255,7 +2257,7 @@ test_bus_kernel_CFLAGS = \
 	$(CAP_CFLAGS)
 
 test_bus_kernel_bloom_SOURCES = \
-	src/libsystemd/test-bus-kernel-bloom.c
+	src/libsystemd/sd-bus/test-bus-kernel-bloom.c
 
 test_bus_kernel_bloom_LDADD = \
 	libsystemd-internal.la \
@@ -2264,7 +2266,7 @@ test_bus_kernel_bloom_LDADD = \
 	libsystemd-shared.la
 
 test_bus_kernel_benchmark_SOURCES = \
-	src/libsystemd/test-bus-kernel-benchmark.c
+	src/libsystemd/sd-bus/test-bus-kernel-benchmark.c
 
 test_bus_kernel_benchmark_LDADD = \
 	libsystemd-internal.la \
@@ -2273,14 +2275,14 @@ test_bus_kernel_benchmark_LDADD = \
 	libsystemd-shared.la
 
 test_bus_memfd_SOURCES = \
-	src/libsystemd/test-bus-memfd.c
+	src/libsystemd/sd-bus/test-bus-memfd.c
 
 test_bus_memfd_LDADD = \
 	libsystemd-internal.la \
 	libsystemd-shared.la
 
 test_bus_zero_copy_SOURCES = \
-	src/libsystemd/test-bus-zero-copy.c
+	src/libsystemd/sd-bus/test-bus-zero-copy.c
 
 test_bus_zero_copy_LDADD = \
 	libsystemd-internal.la \
@@ -2296,14 +2298,14 @@ test_bus_zero_copy_CFLAGS = \
 	$(CAP_CFLAGS)
 
 test_bus_introspect_SOURCES = \
-	src/libsystemd/test-bus-introspect.c
+	src/libsystemd/sd-bus/test-bus-introspect.c
 
 test_bus_introspect_LDADD = \
 	libsystemd-shared.la \
 	libsystemd-internal.la
 
 test_event_SOURCES = \
-	src/libsystemd/test-event.c
+	src/libsystemd/sd-event/test-event.c
 
 test_event_LDADD = \
 	libsystemd-internal.la \
@@ -2312,7 +2314,7 @@ test_event_LDADD = \
 	libsystemd-shared.la
 
 test_rtnl_SOURCES = \
-	src/libsystemd/test-rtnl.c
+	src/libsystemd/sd-rtnl/test-rtnl.c
 
 test_rtnl_LDADD = \
 	libsystemd-internal.la \
@@ -2322,7 +2324,7 @@ test_rtnl_LDADD = \
 
 test_resolve_SOURCES = \
 	src/systemd/sd-resolve.h \
-	src/libsystemd/test-resolve.c
+	src/libsystemd/sd-resolve/test-resolve.c
 
 test_resolve_LDADD = \
 	libsystemd-internal.la \
@@ -2333,7 +2335,7 @@ test_resolve_CFLAGS = \
 	-pthread
 
 busctl_SOURCES = \
-	src/libsystemd/busctl.c
+	src/libsystemd/sd-bus/busctl.c
 
 busctl_LDADD = \
 	libsystemd-internal.la \
diff --git a/src/libsystemd/.gitignore b/src/libsystemd/.gitignore
index 613b05c..50a1692 100644
--- a/src/libsystemd/.gitignore
+++ b/src/libsystemd/.gitignore
@@ -1,2 +1 @@
 /libsystemd.pc
-/bus-error-mapping.c
diff --git a/src/libsystemd/DIFFERENCES b/src/libsystemd/DIFFERENCES
deleted file mode 100644
index fd7506b..0000000
--- a/src/libsystemd/DIFFERENCES
+++ /dev/null
@@ -1,28 +0,0 @@
-Known differences between dbus1 and kdbus:
-
-- NameAcquired/NameLost is gone entirely on kdbus backends if
-  libsystemd is used. It is still added in by systemd-bus-proxyd
-  for old dbus1 clients, and it is available if libsystemd is used
-  against the classic dbus1 daemon. If you want to write compatible
-  code with libsystem-bus you need to explicitly subscribe to
-  NameOwnerChanged signals and just ignore NameAcquired/NameLost
-
-- Applications have to deal with spurious signals they didn't expect,
-  due to the probabilistic bloom filters. They need to handle this
-  anyway, given that any client can send anything to arbitrary clients
-  anyway, even in dbus1, so not much changes.
-
-- clients of the system bus when kdbus is used must roll their own
-  security. Only legacy dbus1 clients get the old XML policy enforced,
-  which is implemented by systemd-bus-proxyd.
-
-- Serial numbers of synthesized messages are always (uint32_t) -1.
-
-- The org.freedesktop.DBus "driver" service is not special on
-  kdbus. It is a bus activated service like any other with its own
-  unique name.
-
-- NameOwnerChanged is a synthetic message, generated locally and not
-  by the driver.
-
-- There's no standard per-session bus anymore. Only a per-user bus.
diff --git a/src/libsystemd/GVARIANT-SERIALIZATION b/src/libsystemd/GVARIANT-SERIALIZATION
deleted file mode 100644
index 5dffc25..0000000
--- a/src/libsystemd/GVARIANT-SERIALIZATION
+++ /dev/null
@@ -1,63 +0,0 @@
-How we use GVariant for serializing D-Bus messages
---------------------------------------------------
-
-We stay as close to the original dbus1 framing as possible. dbus1 has
-the following framing:
-
-    1. A fixed header of "yyyyuu"
-    2. Additional header fields of "a(yv)"
-    3. Padding with NUL bytes to pad up to next 8byte boundary
-    4. The body
-
-Note that the body is not padded at the end, the complete message
-hence might have a non-aligned size. Reading multiple messages at once
-will hence result in possibly unaligned messages in memory.
-
-The header consists of the following:
-
-    y  Endianness, 'l' or 'B'
-    y  Message Type
-    y  Flags
-    y  Protocol version, '1'
-    u  Length of the body, i.e. the length of part 4 above
-    u  Serial number
-
-    = 12 bytes
-
-When using GVariant we keep the basic structure in place, only
-slightly extend the header, and define protocol version '2'. The new
-header:
-
-    y  Endianness, 'l' or 'B'
-    y  Message Type
-    y  Flags
-    y  Protocol version, '2'
-    u  Length of the body, i.e. the length of part 4 above
-    u  Serial number
-    u  Length of the additional header fields array
-
-    = 16 bytes
-
-This has the nice benefit that the beginning of the additional header
-fields array is aligned to an 8 byte boundary. Also, in dbus1
-marshalling arrays start with a length value of 32bit, which means in
-both dbus1 and gvariant marshallings the size of the header fields
-array will be at the same location between bytes 12 and 16. To
-visualize that:
-
-              0               4               8               12              16
-      Common: | E | T | F | V | Body Length   | Serial        | Fields Length |
-
-       dbus1: |                            ... (as above) ... | Fields array ...
-
-    gvariant: |                            ... (as above) ... | Fields Length | Fields array ...
-
-And that's already it.
-
-Note: on kdbus only native endian messages marshalled in gvariant may
-      be sent. If a client receives a message in non-native endianness
-      or in dbus1 marshalling it shall ignore the message.
-
-Note: The GVariant "MAYBE" type is not supported, so that messages can
-      be fully converted forth and back between dbus1 and gvariant
-      representations.
diff --git a/src/libsystemd/PORTING-DBUS1 b/src/libsystemd/PORTING-DBUS1
deleted file mode 100644
index 67af277..0000000
--- a/src/libsystemd/PORTING-DBUS1
+++ /dev/null
@@ -1,550 +0,0 @@
-A few hints on supporting kdbus as backend in your favorite D-Bus library.
-
-~~~
-
-Before you read this, have a look at the DIFFERENCES and
-GVARIANT_SERIALIZATION texts you find in the same directory where you
-found this.
-
-We invite you to port your favorite D-Bus protocol implementation
-over to kdbus. However, there are a couple of complexities
-involved. On kdbus we only speak GVariant marshaling, kdbus clients
-ignore traffic in dbus1 marshaling. Thus, you need to add a second,
-GVariant compatible marshaler to your library first.
-
-After you have done that: here's the basic principle how kdbus works:
-
-You connect to a bus by opening its bus node in /dev/kdbus/. All
-buses have a device node there, it starts with a numeric UID of the
-owner of the bus, followed by a dash and a string identifying the
-bus. The system bus is thus called /dev/kdbus/0-system, and for user
-buses the device node is /dev/kdbus/1000-user (if 1000 is your user
-id).
-
-(Before we proceed, please always keep a copy of libsystemd next
-to you, ultimately that's where the details are, this document simply
-is a rough overview to help you grok things.)
-
-CONNECTING
-
-To connect to a bus, simply open() its device node and issue the
-KDBUS_CMD_HELLO call. That's it. Now you are connected. Do not send
-Hello messages or so (as you would on dbus1), that does not exist for
-kdbus.
-
-The structure you pass to the ioctl will contain a couple of
-parameters that you need to know, to operate on the bus.
-
-There are two flags fields, one indicating features of the kdbus
-kernel side ("conn_flags"), the other one ("bus_flags") indicating
-features of the bus owner (i.e. systemd). Both flags fields are 64bit
-in width.
-
-When calling into the ioctl, you need to place your own supported
-feature bits into these fields. This tells the kernel about the
-features you support. When the ioctl returns, it will contain the
-features the kernel supports.
-
-If any of the higher 32bit are set on the two flags fields and your
-client does not know what they mean, it must disconnect. The upper
-32bit are used to indicate "incompatible" feature additions on the bus
-system, the lower 32bit indicate "compatible" feature additions. A
-client that does not support a "compatible" feature addition can go on
-communicating with the bus, however a client that does not support an
-"incompatible" feature must not proceed with the connection.
-
-The hello structure also contains another flags field "attach_flags"
-which indicates metadata that is optionally attached to all incoming
-messages. You probably want to set KDBUS_ATTACH_NAMES unconditionally
-in it. This has the effect that all well-known names of a sender are
-attached to all incoming messages. You need this information to
-implement matches that match on a message sender name correctly. Of
-course, you should only request the attachment of as little metadata
-fields as you need.
-
-The kernel will return in the "id" field your unique id. This is a
-simple numeric value. For compatibility with classic dbus1 simply
-format this as string and prefix ":0.".
-
-The kernel will also return the bloom filter size used for the signal
-broadcast bloom filter (see below).
-
-The kernel will also return the bus ID of the bus in a 128bit field.
-
-The pool size field specifies the size of the memory mapped buffer.
-After the calling the hello ioctl, you should memory map the kdbus
-fd. In this memory mapped region, the kernel will place all your incoming
-messages.
-
-SENDING MESSAGES
-
-Use the MSG_SEND ioctl to send a message to another peer. The ioctl
-takes a structure that contains a variety of fields:
-
-The flags field corresponds closely to the old dbus1 message header
-flags field, though the DONT_EXPECT_REPLY field got inverted into
-EXPECT_REPLY.
-
-The dst_id/src_id field contains the unique id of the destination and
-the sender. The sender field is overridden by the kernel usually, hence
-you shouldn't fill it in. The destination field can also take the
-special value KDBUS_DST_ID_BROADCAST for broadcast messages. For
-messages intended to a well-known name set the field to
-KDBUS_DST_ID_NAME, and attach the name in a special "items" entry to
-the message (see below).
-
-The payload field indicates the payload. For all dbus traffic it
-should carry the value 0x4442757344427573ULL. (Which encodes
-'DBusDBus').
-
-The cookie field corresponds with the "serial" field of classic
-dbus1. We simply renamed it here (and extended it to 64bit) since we
-didn't want to imply the monotonicity of the assignment the way the
-word "serial" indicates it.
-
-When sending a message that expects a reply, you need to set the
-EXPECT_REPLY flag in the message flag field. In this case you should
-also fill out the "timeout_ns" value which indicates the timeout in
-nsec for this call. If the peer does not respond in this time you will
-get a notification of a timeout. Note that this is also used for
-security purposes: a single reply messages is only allowed through the
-bus as long as the timeout has not ended. With this timeout value you
-hence "open a time window" in which the peer might respond to your
-request and the policy allows the response to go through.
-
-When sending a message that is a reply, you need to fill in the
-cookie_reply field, which is similar to the reply_serial field of
-dbus1. Note that a message cannot have EXPECT_REPLY and a reply_serial
-at the same time!
-
-This pretty much explains the ioctl header. The actual payload of the
-data is now referenced in additional items that are attached to this
-ioctl header structure at the end. When sending a message, you attach
-items of the type PAYLOAD_VEC, PAYLOAD_MEMFD, FDS, BLOOM, DST_NAME to
-it:
-
-   KDBUS_ITEM_PAYLOAD_VEC: contains a pointer + length pair for
-   referencing arbitrary user memory. This is how you reference most
-   of your data. It's a lot like the good old iovec structure of glibc.
-
-   KDBUS_ITEM_PAYLOAD_MEMFD: for large data blocks it is preferable
-   to send prepared "memfds" (see below) over. This item contains an
-   fd for a memfd plus a size.
-
-   KDBUS_ITEM_PAYLOAD_FDS: for sending over fds attach an item of this
-   type with an array of fds.
-
-   KDBUS_ITEM_BLOOM: the calculated bloom filter of this message, only
-   for undirected (broadcast) message.
-
-   KDBUS_DST_NAME: for messages that are directed to a well-known name
-   (instead of a unique name), this item contains the well-known name
-   field.
-
-A single message may consists of no, one or more payload items of type
-PAYLOAD_VEC or PAYLOAD_MEMFD. D-Bus protocol implementations should
-treat them as a single block that just happens to be split up into
-multiple items. Some restrictions apply however:
-
-   The message header in its entirety must be contained in a single
-   PAYLOAD_VEC item.
-
-   You may only split your message up right in front of each GVariant
-   contained in the payload, as well is immediately before framing of a
-   Gvariant, as well after as any padding bytes if there are any. The
-   padding bytes must be wholly contained in the preceding
-   PAYLOAD_VEC/PAYLOAD_MEMFD item. You may not split up simple types
-   nor arrays of trivial types. The latter is necessary to allow APIs
-   to return direct pointers to linear chunks of fixed size trivial
-   arrays. Examples: The simple types "u", "s", "t" have to be in the
-   same payload item. The array of simple types "ay", "ai" have to be
-   fully in contained in the same payload item. For an array "as" or
-   "a(si)" the only restriction however is to keep each string
-   individually in an uninterrupted item, to keep the framing of each
-   element and the array in a single uninterrupted item, however the
-   various strings might end up in different items.
-
-Note again, that splitting up messages into separate items is up to the
-implementation. Also note that the kdbus kernel side might merge
-separate items if it deems this to be useful. However, the order in
-which items are contained in the message is left untouched.
-
-PAYLOAD_MEMFD items allow zero-copy data transfer (see below regarding
-the memfd concept). Note however that the overhead of mapping these
-makes them relatively expensive, and only worth the trouble for memory
-blocks > 128K (this value appears to be quite universal across
-architectures, as we tested). Thus we recommend sending PAYLOAD_VEC
-items over for small messages and restore to PAYLOAD_MEMFD items for
-messages > 128K. Since while building up the message you might not
-know yet whether it will grow beyond this boundary a good approach is
-to simply build the message unconditionally in a memfd
-object. However, when the message is sealed to be sent away check for
-the size limit. If the size of the message is < 128K, then simply send
-the data as PAYLOAD_VEC and reuse the memfd. If it is >= 128K, seal
-the memfd and send it as PAYLOAD_MEMFD, and allocate a new memfd for
-the next message.
-
-RECEIVING MESSAGES
-
-Use the MSG_RECV ioctl to read a message from kdbus. This will return
-an offset into the pool memory map, relative to its beginning.
-
-The received message structure more or less follows the structure of
-the message originally sent. However, certain changes have been
-made. In the header the src_id field will be filled in.
-
-The payload items might have gotten merged and PAYLOAD_VEC items are
-not used. Instead, you will only find PAYLOAD_OFF and PAYLOAD_MEMFD
-items. The former contain an offset and size into your memory mapped
-pool where you find the payload.
-
-If during the HELLO ioctl you asked for getting metadata attached to
-your message, you will find additional KDBUS_ITEM_CREDS,
-KDBUS_ITEM_PID_COMM, KDBUS_ITEM_TID_COMM, KDBUS_ITEM_TIMESTAMP,
-KDBUS_ITEM_EXE, KDBUS_ITEM_CMDLINE, KDBUS_ITEM_CGROUP,
-KDBUS_ITEM_CAPS, KDBUS_ITEM_SECLABEL, KDBUS_ITEM_AUDIT items that
-contain this metadata. This metadata will be gathered from the sender
-at the point in time it sends the message. This information is
-uncached, and since it is appended by the kernel, trustable. The
-KDBUS_ITEM_SECLABEL item usually contains the SELinux security label,
-if it is used.
-
-After processing the message you need to call the KDBUS_CMD_FREE
-ioctl, which releases the message from the pool, and allows the kernel
-to store another message there. Note that the memory used by the pool
-is ordinary anonymous, swappable memory that is backed by tmpfs. Hence
-there is no need to copy the message out of it quickly, instead you
-can just leave it there as long as you need it and release it via the
-FREE ioctl only after that's done.
-
-BLOOM FILTERS
-
-The kernel does not understand dbus marshaling, it will not look into
-the message payload. To allow clients to subscribe to specific subsets
-of the broadcast matches we employ bloom filters.
-
-When broadcasting messages, a bloom filter needs to be attached to the
-message in a KDBUS_ITEM_BLOOM item (and only for broadcasting
-messages!). If you don't know what bloom filters are, read up now on
-Wikipedia. In short: they are a very efficient way how to
-probabilistically check whether a certain word is contained in a
-vocabulary. It knows no false negatives, but it does know false
-positives.
-
-The bloom filter that needs to be included has the parameters m=512
-(bits in the filter), k=8 (nr of hash functions). The underlying hash
-function is SipHash-2-4. We calculate two hash values for an input
-strings, one with the hash key b9660bf0467047c18875c49c54b9bd15 (this
-is supposed to be read as a series of 16 hexadecimal formatted
-bytes), and one with the hash key
-aaa154a2e0714b39bfe1dd2e9fc54a3b. This results in two 64bit hash
-values, A and B. The 8 hash functions for the bloom filter require a 9
-bit output each (since m=512=2^9), to generate these we XOR combine
-the first 8 bit of A shifted to the left by 1, with the first 8 bit of
-B. Then, for the next hash function we use the second 8 bit pair, and
-so on.
-
-For each message to send across the bus we populate the bloom filter
-with all possible matchable strings. If a client then wants to
-subscribe to messages of this type, it simply tells the kernel to test
-its own calculated bit mask against the bloom filter of each message.
-
-More specifically, the following strings are added to the bloom filter
-of each message that is broadcasted:
-
-  The string "interface:" suffixed by the interface name
-
-  The string "member:" suffixed by the member name
-
-  The string "path:" suffixed by the path name
-
-  The string "path-slash-prefix:" suffixed with the path name, and
-  also all prefixes of the path name (cut off at "/"), also prefixed
-  with "path-slash-prefix".
-
-  The string "message-type:" suffixed with the strings "signal",
-  "method_call", "error" or "method_return" for the respective message
-  type of the message.
-
-  If the first argument of the message is a string, "arg0:" suffixed
-  with the first argument.
-
-  If the first argument of the message is a string, "arg0-dot-prefix"
-  suffixed with the first argument, and also all prefixes of the
-  argument (cut off at "."), also prefixed with "arg0-dot-prefix".
-
-  If the first argument of the message is a string,
-  "arg0-slash-prefix" suffixed with the first argument, and also all
-  prefixes of the argument (cut off at "/"), also prefixed with
-  "arg0-slash-prefix".
-
-  Similar for all further arguments that are strings up to 63, for the
-  arguments and their "dot" and "slash" prefixes. On the first
-  argument that is not a string, addition to the bloom filter should be
-  stopped however.
-
-(Note that the bloom filter does not contain sender nor receiver
-names!)
-
-When a client wants to subscribe to messages matching a certain
-expression, it should calculate the bloom mask following the same
-algorithm. The kernel will then simply test the mask against the
-attached bloom filters.
-
-Note that bloom filters are probabilistic, which means that clients
-might get messages they did not expect. Your bus protocol
-implementation must be capable of dealing with these unexpected
-messages (which it needs to anyway, given that transfers are
-relatively unrestricted on kdbus and people can send you all kinds of
-non-sense).
-
-INSTALLING MATCHES
-
-To install matches for broadcast messages, use the KDBUS_CMD_ADD_MATCH
-ioctl. It takes a structure that contains an encoded match expression,
-and that is followed by one or more items, which are combined in an
-AND way. (Meaning: a message is matched exactly when all items
-attached to the original ioctl struct match).
-
-To match against other user messages add a KDBUS_ITEM_BLOOM item in
-the match (see above). Note that the bloom filter does not include
-matches to the sender names. To additionally check against sender
-names, use the KDBUS_ITEM_ID (for unique id matches) and
-KDBUS_ITEM_NAME (for well-known name matches) item types.
-
-To match against kernel generated messages (see below) you should add
-items of the same type as the kernel messages include,
-i.e. KDBUS_ITEM_NAME_ADD, KDBUS_ITEM_NAME_REMOVE,
-KDBUS_ITEM_NAME_CHANGE, KDBUS_ITEM_ID_ADD, KDBUS_ITEM_ID_REMOVE and
-fill them out. Note however, that you have some wildcards in this
-case, for example the .id field of KDBUS_ITEM_ADD/KDBUS_ITEM_REMOVE
-structures may be set to 0 to match against any id addition/removal.
-
-Note that dbus match strings do no map 1:1 to these ioctl() calls. In
-many cases (where the match string is "underspecified") you might need
-to issue up to six different ioctl() calls for the same match. For
-example, the empty match (which matches against all messages), would
-translate into one KDBUS_ITEM_BLOOM ioctl, one KDBUS_ITEM_NAME_ADD,
-one KDBUS_ITEM_NAME_CHANGE, one KDBUS_ITEM_NAME_REMOVE, one
-KDBUS_ITEM_ID_ADD and one KDBUS_ITEM_ID_REMOVE.
-
-When creating a match, you may attach a "cookie" value to them, which
-is used for deleting this match again. The cookie can be selected freely
-by the client. When issuing KDBUS_CMD_REMOVE_MATCH, simply pass the
-same cookie as before and all matches matching the same "cookie" value
-will be removed. This is particularly handy for the case where multiple
-ioctl()s are added for a single match strings.
-
-MEMFDS
-
-The "memfd" concept is used for zero-copy data transfers (see
-above). memfds are file descriptors to memory chunks of arbitrary
-sizes. If you have a memfd you can mmap() it to get access to the data
-it contains or write to it. They are comparable to file descriptors to
-unlinked files on a tmpfs, or to anonymous memory that one may refer
-to with an fd. They have one particular property: they can be
-"sealed". A memfd that is "sealed" is protected from alteration. Only
-memfds that are currently not mapped and to which a single fd refers
-may be sealed (they may also be unsealed in that case).
-
-The concept of "sealing" makes memfds useful for using them as
-transport for kdbus messages: only when the receiver knows that the
-message it has received cannot change while looking at, it can safely
-parse it without having to copy it to a safe memory area. memfds can also
-be reused in multiple messages. A sender may send the same memfd to
-multiple peers, and since it is sealed, it can be sure that the receiver
-will not be able to modify it. "Sealing" hence provides both sides of
-a transaction with the guarantee that the data stays constant and is
-reusable.
-
-memfds are a generic concept that can be used outside of the immediate
-kdbus usecase. You can send them across AF_UNIX sockets too, sealed or
-unsealed. In kdbus themselves, they can be used to send zero-copy
-payloads, but may also be sent as normal fds.
-
-memfds are allocated with the KDBUS_CMD_MEMFD_NEW ioctl. After allocation,
-simply memory map them and write to them. To set their size, use
-KDBUS_CMD_MEMFD_SIZE_SET. Note that memfds will be increased in size
-automatically if you touch previously unallocated pages. However, the
-size will only be increased in multiples of the page size in that
-case. Thus, in almost all cases, an explicit KDBUS_CMD_MEMFD_SIZE_SET
-is necessary, since it allows setting memfd sizes in finer
-granularity. To seal a memfd use the KDBUS_CMD_MEMFD_SEAL_SET ioctl
-call. It will only succeed if the caller has the only fd reference to
-the memfd open, and if the memfd is currently unmapped.
-
-If memfds are shared, keep in mind that the file pointer used by
-write/read/seek is shared too, only pread/pwrite are safe to use
-in that case.
-
-memfds may be sent across kdbus via KDBUS_ITEM_PAYLOAD_MEMFD items
-attached to messages. If this is done, the data included in the memfd
-is considered part of the payload stream of a message, and are treated
-the same way as KDBUS_ITEM_PAYLOAD_VEC by the receiving side. It is
-possible to interleave KDBUS_ITEM_PAYLOAD_MEMFD and
-KDBUS_ITEM_PAYLOAD_VEC items freely, by the reader they will be
-considered a single stream of bytes in the order these items appear in
-the message, that just happens to be split up at various places
-(regarding rules how they may be split up, see above). The kernel will
-refuse taking KDBUS_ITEM_PAYLOAD_MEMFD items that refer to memfds that
-are not sealed.
-
-Note that sealed memfds may be unsealed again if they are not mapped
-you have the only fd reference to them.
-
-Alternatively to sending memfds as KDBUS_ITEM_PAYLOAD_MEMFD items
-(where they are just a part of the payload stream of a message) you can
-also simply attach any memfd to a message using
-KDBUS_ITEM_PAYLOAD_FDS. In this case, the memfd contents is not
-considered part of the payload stream of the message, but simply fds
-like any other, that happen to be attached to the message.
-
-MESSAGES FROM THE KERNEL
-
-A couple of messages previously generated by the dbus1 bus driver are
-now generated by the kernel. Since the kernel does not understand the
-payload marshaling, they are generated by the kernel  in a different
-format. This is indicated with the "payload type" field of the
-messages set to 0. Library implementations should take these messages
-and synthesize traditional driver messages for them on reception.
-
-More specifically:
-
-   Instead of the NameOwnerChanged, NameLost, NameAcquired signals
-   there are kernel messages containing KDBUS_ITEM_NAME_ADD,
-   KDBUS_ITEM_NAME_REMOVE, KDBUS_ITEM_NAME_CHANGE, KDBUS_ITEM_ID_ADD,
-   KDBUS_ITEM_ID_REMOVE items are generated (each message will contain
-   exactly one of these items). Note that in libsystemd we have
-   obsoleted NameLost/NameAcquired messages, since they are entirely
-   redundant to NameOwnerChanged. This library will hence only
-   synthesize NameOwnerChanged messages from these kernel messages,
-   and never generate NameLost/NameAcquired. If your library needs to
-   stay compatible to the old dbus1 userspace, you possibly might need
-   to synthesize both a NameOwnerChanged and NameLost/NameAcquired
-   message from the same kernel message.
-
-   When a method call times out, a KDBUS_ITEM_REPLY_TIMEOUT message is
-   generated. This should be synthesized into a method error reply
-   message to the original call.
-
-   When a method call fails because the peer terminated the connection
-   before responding, a KDBUS_ITEM_REPLY_DEAD message is
-   generated. Similarly, it should be synthesized into a method error
-   reply message.
-
-For synthesized messages we recommend setting the cookie field to
-(uint32_t) -1 (and not (uint64_t) -1!), so that the cookie is not 0
-(which the dbus1 spec does not allow), but clearly recognizable as
-synthetic.
-
-Note that the KDBUS_ITEM_NAME_XYZ messages will actually inform you
-about all kinds of names, including activatable ones. Classic dbus1
-NameOwnerChanged messages OTOH are only generated when a name is
-really acquired on the bus and not just simply activatable. This means
-you must explicitly check for the case where an activatable name
-becomes acquired or an acquired name is lost and returns to be
-activatable.
-
-NAME REGISTRY
-
-To acquire names on the bus, use the KDBUS_CMD_NAME_ACQUIRE ioctl(). It
-takes a flags field similar to dbus1's RequestName() bus driver call,
-however the NO_QUEUE flag got inverted into a QUEUE flag instead.
-
-To release a previously acquired name use the KDBUS_CMD_NAME_RELEASE
-ioctl().
-
-To list acquired names use the KDBUS_CMD_CONN_INFO ioctl. It may be
-used to list unique names, well known names as well as activatable
-names and clients currently queuing for ownership of a well-known
-name. The ioctl will return an offset into the memory pool. After
-reading all the data you need, you need to release this via the
-KDBUS_CMD_FREE ioctl(), similar how you release a received message.
-
-CREDENTIALS
-
-kdbus can optionally attach various kinds of metadata about the sender at
-the point of time of sending ("credentials") to messages, on request
-of the receiver. This is both supported on directed and undirected
-(broadcast) messages. The metadata to attach is selected at time of
-the HELLO ioctl of the receiver via a flags field (see above). Note
-that clients must be able to handle that messages contain more
-metadata than they asked for themselves, to simplify implementation of
-broadcasting in the kernel. The receiver should not rely on this data
-to be around though, even though it will be correct if it happens to
-be attached. In order to avoid programming errors in applications, we
-recommend though not passing this data on to clients that did not
-explicitly ask for it.
-
-Credentials may also be queried for a well-known or unique name. Use
-the KDBUS_CMD_CONN_INFO for this. It will return an offset to the pool
-area again, which will contain the same credential items as messages
-have attached. Note that when issuing the ioctl, you can select a
-different set of credentials to gather, than what was originally requested
-for being attached to incoming messages.
-
-Credentials are always specific to the sender namespace that was
-current at the time of sending, and of the process that opened the
-bus connection at the time of opening it. Note that this latter data
-is cached!
-
-POLICY
-
-The kernel enforces only very limited policy on names. It will not do
-access filtering by userspace payload, and thus not by interface or
-method name.
-
-This ultimately means that most fine-grained policy enforcement needs
-to be done by the receiving process. We recommend using PolicyKit for
-any more complex checks. However, libraries should make simple static
-policy decisions regarding privileged/unprivileged method calls
-easy. We recommend doing this by enabling KDBUS_ATTACH_CAPS and
-KDBUS_ATTACH_CREDS for incoming messages, and then discerning client
-access by some capability, or if sender and receiver UIDs match.
-
-BUS ADDRESSES
-
-When connecting to kdbus use the "kernel:" protocol prefix in DBus
-address strings. The device node path is encoded in its "path="
-parameter.
-
-Client libraries should use the following connection string when
-connecting to the system bus:
-
-   kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket
-
-This will ensure that kdbus is preferred over the legacy AF_UNIX
-socket, but compatibility is kept. For the user bus use:
-
-   kernel:path=/dev/kdbus/$UID-user/bus;unix:path=$XDG_RUNTIME_DIR/bus
-
-With $UID replaced by the callers numer user ID, and $XDG_RUNTIME_DIR
-following the XDG basedir spec.
-
-Of course the $DBUS_SYSTEM_BUS_ADDRESS and $DBUS_SESSION_BUS_ADDRESS
-variables should still take precedence.
-
-DBUS SERVICE FILES
-
-Activatable services for kdbus may not use classic dbus1 service
-activation files. Instead, programs should drop in native systemd
-.service and .busname unit files, so that they are treated uniformly
-with other types of units and activation of the system.
-
-Note that this results in a major difference to classic dbus1:
-activatable bus names can be established at any time in the boot process.
-This is unlike dbus1 where activatable names are unconditionally available
-as long as dbus-daemon is running. Being able to control when
-activatable names are established is essential to allow usage of kdbus
-during early boot and in initrds, without the risk of triggering
-services too early.
-
-DISCLAIMER
-
-This all is so far just the status quo. We are putting this together, because
-we are quite confident that further API changes will be smaller, but
-to make this very clear: this is all subject to change, still!
-
-We invite you to port over your favorite dbus library to this new
-scheme, but please be prepared to make minor changes when we still
-change these interfaces!
diff --git a/src/libsystemd/bus-bloom.c b/src/libsystemd/bus-bloom.c
deleted file mode 100644
index 9e51334..0000000
--- a/src/libsystemd/bus-bloom.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-*- 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 "util.h"
-#include "siphash24.h"
-#include "bus-bloom.h"
-
-static inline void set_bit(uint64_t filter[], unsigned b) {
-        filter[b >> 6] |= 1ULL << (b & 63);
-}
-
-#define HASH_KEY1 SD_ID128_MAKE(b9,66,0b,f0,46,70,47,c1,88,75,c4,9c,54,b9,bd,15)
-#define HASH_KEY2 SD_ID128_MAKE(aa,a1,54,a2,e0,71,4b,39,bf,e1,dd,2e,9f,c5,4a,3b)
-
-static void bloom_add_data(uint64_t filter[BLOOM_SIZE/8], const void *data, size_t n) {
-        uint8_t a[8], b[8];
-        unsigned k = 0;
-
-        /*
-         * Our bloom filter has the following parameters:
-         *
-         * m=512   (bits in the filter)
-         * k=8     (hash functions)
-         *
-         * We calculate a two 64bit SipHash values (for two fixed but
-         * randomly generated hash keys) of which we use 8 parts of 9 bits
-         * as individual hash functions.
-         *
-         */
-
-        siphash24(a, data, n, HASH_KEY1.bytes);
-        siphash24(b, data, n, HASH_KEY2.bytes);
-
-        assert_cc(BLOOM_SIZE*8 == 512);
-
-        for (k = 0; k < 8; k++)
-                set_bit(filter, ((uint16_t) a[k] << 1) ^ (uint16_t) b[k]);
-
-        /* log_debug("bloom: adding <%.*s>", (int) n, (char*) data); */
-}
-
-void bloom_add_pair(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b) {
-        size_t n;
-        char *c;
-
-        assert(filter);
-        assert(a);
-        assert(b);
-
-        n = strlen(a) + 1 + strlen(b);
-        c = alloca(n + 1);
-        strcpy(stpcpy(stpcpy(c, a), ":"), b);
-
-        bloom_add_data(filter, c, n);
-}
-
-void bloom_add_prefixes(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b, char sep) {
-        size_t n;
-        char *c, *p;
-
-        assert(filter);
-        assert(a);
-        assert(b);
-
-        n = strlen(a) + 1 + strlen(b);
-        c = alloca(n + 1);
-
-        p = stpcpy(stpcpy(c, a), ":");
-        strcpy(p, b);
-
-        for (;;) {
-                char *e;
-
-                e = strrchr(p, sep);
-                if (!e || e == p)
-                        break;
-
-                *e = 0;
-                bloom_add_data(filter, c, e - c);
-        }
-}
diff --git a/src/libsystemd/bus-bloom.h b/src/libsystemd/bus-bloom.h
deleted file mode 100644
index 422eb4e..0000000
--- a/src/libsystemd/bus-bloom.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- 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 <sys/types.h>
-
-#define BLOOM_SIZE 64
-
-void bloom_add_pair(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b);
-void bloom_add_prefixes(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b, char sep);
diff --git a/src/libsystemd/bus-container.c b/src/libsystemd/bus-container.c
deleted file mode 100644
index d330363..0000000
--- a/src/libsystemd/bus-container.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*-*- 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 <unistd.h>
-#include <fcntl.h>
-
-#include "util.h"
-#include "fileio.h"
-#include "bus-internal.h"
-#include "bus-socket.h"
-#include "bus-container.h"
-
-int bus_container_connect_socket(sd_bus *b) {
-        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
-        pid_t leader, child;
-        siginfo_t si;
-        int r;
-
-        assert(b);
-        assert(b->input_fd < 0);
-        assert(b->output_fd < 0);
-
-        r = container_get_leader(b->machine, &leader);
-        if (r < 0)
-                return r;
-
-        r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd);
-        if (r < 0)
-                return r;
-
-        b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (b->input_fd < 0)
-                return -errno;
-
-        b->output_fd = b->input_fd;
-
-        bus_socket_setup(b);
-
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
-                pid_t grandchild;
-
-                r = namespace_enter(pidnsfd, mntnsfd, rootfd);
-                if (r < 0)
-                        _exit(255);
-
-                /* We just changed PID namespace, however it will only
-                 * take effect on the children we now fork. Hence,
-                 * let's fork another time, and connect from this
-                 * grandchild, so that SO_PEERCRED of our connection
-                 * comes from a process from within the container, and
-                 * not outside of it */
-
-                grandchild = fork();
-                if (grandchild < 0)
-                        _exit(255);
-
-                if (grandchild == 0) {
-
-                        r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
-                        if (r < 0) {
-                                if (errno == EINPROGRESS)
-                                        _exit(1);
-
-                                _exit(255);
-                        }
-
-                        _exit(EXIT_SUCCESS);
-                }
-
-                r = wait_for_terminate(grandchild, &si);
-                if (r < 0)
-                        _exit(255);
-
-                if (si.si_code != CLD_EXITED)
-                        _exit(255);
-
-                _exit(si.si_status);
-        }
-
-        r = wait_for_terminate(child, &si);
-        if (r < 0)
-                return r;
-
-        if (si.si_code != CLD_EXITED)
-                return -EIO;
-
-        if (si.si_status == 1)
-                return 1;
-
-        if (si.si_status != EXIT_SUCCESS)
-                return -EIO;
-
-        return bus_socket_start_auth(b);
-}
-
-int bus_container_connect_kernel(sd_bus *b) {
-        _cleanup_close_pipe_ int pair[2] = { -1, -1 };
-        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
-        struct msghdr mh = {
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-        };
-        struct cmsghdr *cmsg;
-        pid_t leader, child;
-        siginfo_t si;
-        int r;
-        _cleanup_close_ int fd = -1;
-
-        assert(b);
-        assert(b->input_fd < 0);
-        assert(b->output_fd < 0);
-
-        r = container_get_leader(b->machine, &leader);
-        if (r < 0)
-                return r;
-
-        r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd);
-        if (r < 0)
-                return r;
-
-        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
-                return -errno;
-
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
-                pid_t grandchild;
-
-                close_nointr_nofail(pair[0]);
-                pair[0] = -1;
-
-                r = namespace_enter(pidnsfd, mntnsfd, rootfd);
-                if (r < 0)
-                        _exit(EXIT_FAILURE);
-
-                /* We just changed PID namespace, however it will only
-                 * take effect on the children we now fork. Hence,
-                 * let's fork another time, and connect from this
-                 * grandchild, so that kdbus only sees the credentials
-                 * of this process which comes from within the
-                 * container, and not outside of it */
-
-                grandchild = fork();
-                if (grandchild < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (grandchild == 0) {
-
-                        fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
-                        if (fd < 0)
-                                _exit(EXIT_FAILURE);
-
-                        cmsg = CMSG_FIRSTHDR(&mh);
-                        cmsg->cmsg_level = SOL_SOCKET;
-                        cmsg->cmsg_type = SCM_RIGHTS;
-                        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-                        memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
-                        mh.msg_controllen = cmsg->cmsg_len;
-
-                        if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
-                                _exit(EXIT_FAILURE);
-
-                        _exit(EXIT_SUCCESS);
-                }
-
-                r = wait_for_terminate(grandchild, &si);
-                if (r < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (si.si_code != CLD_EXITED)
-                        _exit(EXIT_FAILURE);
-
-                _exit(si.si_status);
-        }
-
-        close_nointr_nofail(pair[1]);
-        pair[1] = -1;
-
-        r = wait_for_terminate(child, &si);
-        if (r < 0)
-                return r;
-
-        if (si.si_code != CLD_EXITED)
-                return -EIO;
-
-        if (si.si_status != EXIT_SUCCESS)
-                return -EIO;
-
-        if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
-                return -errno;
-
-        for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
-                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
-                        int *fds;
-                        unsigned n_fds;
-
-                        fds = (int*) CMSG_DATA(cmsg);
-                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
-                        if (n_fds != 1) {
-                                close_many(fds, n_fds);
-                                return -EIO;
-                        }
-
-                        fd = fds[0];
-                }
-
-        b->input_fd = b->output_fd = fd;
-        fd = -1;
-
-        return bus_kernel_take_fd(b);
-}
diff --git a/src/libsystemd/bus-container.h b/src/libsystemd/bus-container.h
deleted file mode 100644
index c6f757a..0000000
--- a/src/libsystemd/bus-container.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- 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-bus.h"
-
-int bus_container_connect_socket(sd_bus *b);
-int bus_container_connect_kernel(sd_bus *b);
diff --git a/src/libsystemd/bus-control.c b/src/libsystemd/bus-control.c
deleted file mode 100644
index e7e9ba0..0000000
--- a/src/libsystemd/bus-control.c
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*-*- 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/>.
-***/
-
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
-
-#include <stddef.h>
-#include <errno.h>
-
-#include "strv.h"
-#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-control.h"
-#include "bus-bloom.h"
-#include "bus-util.h"
-#include "cgroup-util.h"
-
-_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(unique, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = bus_ensure_running(bus);
-        if (r < 0)
-                return r;
-
-        *unique = bus->unique_name;
-        return 0;
-}
-
-static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
-        struct kdbus_cmd_name *n;
-        size_t size, l;
-        int r;
-
-        assert(bus);
-        assert(name);
-
-        l = strlen(name);
-        size = offsetof(struct kdbus_cmd_name, name) + l + 1;
-        n = alloca0(size);
-        n->size = size;
-        kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
-        memcpy(n->name, name, l+1);
-
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-        VALGRIND_MAKE_MEM_DEFINED(n, n->size);
-#endif
-
-        r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
-        if (r < 0)
-                return -errno;
-
-        if (n->flags & KDBUS_NAME_IN_QUEUE)
-                return 0;
-
-        return 1;
-}
-
-static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        uint32_t ret, param = 0;
-        int r;
-
-        assert(bus);
-        assert(name);
-
-        if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
-                param |= BUS_NAME_ALLOW_REPLACEMENT;
-        if (flags & SD_BUS_NAME_REPLACE_EXISTING)
-                param |= BUS_NAME_REPLACE_EXISTING;
-        if (!(flags & SD_BUS_NAME_QUEUE))
-                param |= BUS_NAME_DO_NOT_QUEUE;
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "RequestName",
-                        NULL,
-                        &reply,
-                        "su",
-                        name,
-                        param);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read(reply, "u", &ret);
-        if (r < 0)
-                return r;
-
-        if (ret == BUS_NAME_ALREADY_OWNER)
-                return -EALREADY;
-        else if (ret == BUS_NAME_EXISTS)
-                return -EEXIST;
-        else if (ret == BUS_NAME_IN_QUEUE)
-                return 0;
-        else if (ret == BUS_NAME_PRIMARY_OWNER)
-                return 1;
-
-        return -EIO;
-}
-
-_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
-        assert_return(bus, -EINVAL);
-        assert_return(name, -EINVAL);
-        assert_return(bus->bus_client, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
-        assert_return(service_name_is_valid(name), -EINVAL);
-        assert_return(name[0] != ':', -EINVAL);
-
-        if (bus->is_kernel)
-                return bus_request_name_kernel(bus, name, flags);
-        else
-                return bus_request_name_dbus1(bus, name, flags);
-}
-
-static int bus_release_name_kernel(sd_bus *bus, const char *name) {
-        struct kdbus_cmd_name *n;
-        size_t l;
-        int r;
-
-        assert(bus);
-        assert(name);
-
-        l = strlen(name);
-        n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
-        n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
-        memcpy(n->name, name, l+1);
-
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-        VALGRIND_MAKE_MEM_DEFINED(n, n->size);
-#endif
-        r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
-        if (r < 0)
-                return -errno;
-
-        return n->flags;
-}
-
-static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        uint32_t ret;
-        int r;
-
-        assert(bus);
-        assert(name);
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "ReleaseName",
-                        NULL,
-                        &reply,
-                        "s",
-                        name);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read(reply, "u", &ret);
-        if (r < 0)
-                return r;
-        if (ret == BUS_NAME_NON_EXISTENT)
-                return -ESRCH;
-        if (ret == BUS_NAME_NOT_OWNER)
-                return -EADDRINUSE;
-        if (ret == BUS_NAME_RELEASED)
-                return 0;
-
-        return -EINVAL;
-}
-
-_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
-        assert_return(bus, -EINVAL);
-        assert_return(name, -EINVAL);
-        assert_return(bus->bus_client, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(service_name_is_valid(name), -EINVAL);
-        assert_return(name[0] != ':', -EINVAL);
-
-        if (bus->is_kernel)
-                return bus_release_name_kernel(bus, name);
-        else
-                return bus_release_name_dbus1(bus, name);
-}
-
-static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
-        struct kdbus_cmd_name_list cmd = {};
-        struct kdbus_name_list *name_list;
-        struct kdbus_cmd_name *name;
-        uint64_t previous_id = 0;
-        int r;
-
-        /* Caller will free half-constructed list on failure... */
-
-        cmd.flags = flags;
-
-        r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
-        if (r < 0)
-                return -errno;
-
-        name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
-
-        KDBUS_ITEM_FOREACH(name, name_list, names) {
-
-                if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
-                        char *n;
-
-                        if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0)
-                                return -ENOMEM;
-
-                        r = strv_push(x, n);
-                        if (r < 0) {
-                                free(n);
-                                return -ENOMEM;
-                        }
-
-                        previous_id = name->owner_id;
-                }
-
-                if (name->size > sizeof(*name) && service_name_is_valid(name->name)) {
-                        r = strv_extend(x, name->name);
-                        if (r < 0)
-                                return -ENOMEM;
-                }
-        }
-
-        r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
-        _cleanup_strv_free_ char **x = NULL, **y = NULL;
-        int r;
-
-        if (acquired) {
-                r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
-                if (r < 0)
-                        return r;
-        }
-
-        if (activatable) {
-                r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
-                if (r < 0)
-                        return r;
-
-                *activatable = y;
-                y = NULL;
-        }
-
-        if (acquired) {
-                *acquired = x;
-                x = NULL;
-        }
-
-        return 0;
-}
-
-static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_strv_free_ char **x = NULL, **y = NULL;
-        int r;
-
-        if (acquired) {
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.DBus",
-                                "/org/freedesktop/DBus",
-                                "org.freedesktop.DBus",
-                                "ListNames",
-                                NULL,
-                                &reply,
-                                NULL);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_read_strv(reply, &x);
-                if (r < 0)
-                        return r;
-
-                reply = sd_bus_message_unref(reply);
-        }
-
-        if (activatable) {
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.DBus",
-                                "/org/freedesktop/DBus",
-                                "org.freedesktop.DBus",
-                                "ListActivatableNames",
-                                NULL,
-                                &reply,
-                                NULL);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_read_strv(reply, &y);
-                if (r < 0)
-                        return r;
-
-                *activatable = y;
-                y = NULL;
-        }
-
-        if (acquired) {
-                *acquired = x;
-                x = NULL;
-        }
-
-        return 0;
-}
-
-_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
-        assert_return(bus, -EINVAL);
-        assert_return(acquired || activatable, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (bus->is_kernel)
-                return bus_list_names_kernel(bus, acquired, activatable);
-        else
-                return bus_list_names_dbus1(bus, acquired, activatable);
-}
-
-static int bus_get_owner_kdbus(
-                sd_bus *bus,
-                const char *name,
-                uint64_t mask,
-                sd_bus_creds **creds) {
-
-        _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
-        struct kdbus_cmd_conn_info *cmd;
-        struct kdbus_conn_info *conn_info;
-        struct kdbus_item *item;
-        size_t size;
-        uint64_t m, id;
-        int r;
-
-        r = bus_kernel_parse_unique_name(name, &id);
-        if (r < 0)
-                return r;
-        if (r > 0) {
-                size = offsetof(struct kdbus_cmd_conn_info, name);
-                cmd = alloca0(size);
-                cmd->id = id;
-        } else {
-                size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
-                cmd = alloca0(size);
-                strcpy(cmd->name, name);
-        }
-        cmd->flags = KDBUS_ATTACH_NAMES;
-
-        cmd->size = size;
-        r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
-        if (r < 0)
-                return -errno;
-
-        conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
-
-        /* Non-activated names are considered not available */
-        if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
-                return name[0] == ':' ? -ENXIO : -ENOENT;
-
-        c = bus_creds_new();
-        if (!c)
-                return -ENOMEM;
-
-        if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
-                if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
-                        return -ENOMEM;
-
-                c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
-        }
-
-        KDBUS_ITEM_FOREACH(item, conn_info, items) {
-
-                switch (item->type) {
-
-                case KDBUS_ITEM_CREDS:
-                        m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask;
-
-                        if (m) {
-                                c->uid = (uid_t) item->creds.uid;
-                                c->pid = (pid_t) item->creds.pid;
-                                c->gid = (gid_t) item->creds.gid;
-                                c->mask |= m;
-                        }
-
-                        if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) {
-                                c->tid = (pid_t) item->creds.tid;
-                                c->mask |= SD_BUS_CREDS_TID;
-                        }
-
-                        if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) {
-                                c->pid_starttime = item->creds.starttime;
-                                c->mask |= SD_BUS_CREDS_PID_STARTTIME;
-                        }
-
-                        break;
-
-                case KDBUS_ITEM_PID_COMM:
-                        if (mask & SD_BUS_CREDS_COMM) {
-                                c->comm = strdup(item->str);
-                                if (!c->comm) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= SD_BUS_CREDS_COMM;
-                        }
-                        break;
-
-                case KDBUS_ITEM_TID_COMM:
-                        if (mask & SD_BUS_CREDS_TID_COMM) {
-                                c->tid_comm = strdup(item->str);
-                                if (!c->tid_comm) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= SD_BUS_CREDS_TID_COMM;
-                        }
-                        break;
-
-                case KDBUS_ITEM_EXE:
-                        if (mask & SD_BUS_CREDS_EXE) {
-                                c->exe = strdup(item->str);
-                                if (!c->exe) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= SD_BUS_CREDS_EXE;
-                        }
-                        break;
-
-                case KDBUS_ITEM_CMDLINE:
-                        if (mask & SD_BUS_CREDS_CMDLINE) {
-                                c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
-                                c->cmdline = memdup(item->data, c->cmdline_size);
-                                if (!c->cmdline) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= SD_BUS_CREDS_CMDLINE;
-                        }
-                        break;
-
-                case KDBUS_ITEM_CGROUP:
-                        m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
-                             SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
-                             SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
-
-                        if (m) {
-                                c->cgroup = strdup(item->str);
-                                if (!c->cgroup) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                if (!bus->cgroup_root) {
-                                        r = cg_get_root_path(&bus->cgroup_root);
-                                        if (r < 0)
-                                                goto fail;
-                                }
-
-                                c->cgroup_root = strdup(bus->cgroup_root);
-                                if (!c->cgroup_root) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= m;
-                        }
-                        break;
-
-                case KDBUS_ITEM_CAPS:
-                        m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
-                             SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
-
-                        if (m) {
-                                c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE;
-                                c->capability = memdup(item->data, c->capability_size);
-                                if (!c->capability) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= m;
-                        }
-                        break;
-
-                case KDBUS_ITEM_SECLABEL:
-                        if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
-                                c->label = strdup(item->str);
-                                if (!c->label) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
-                        }
-                        break;
-
-                case KDBUS_ITEM_AUDIT:
-                        m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
-
-                        if (m) {
-                                c->audit_session_id = item->audit.sessionid;
-                                c->audit_login_uid = item->audit.loginuid;
-                                c->mask |= m;
-                        }
-                        break;
-
-                case KDBUS_ITEM_NAME:
-                        if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
-                                r = strv_extend(&c->well_known_names, item->name.name);
-                                if (r < 0)
-                                        goto fail;
-
-                                c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
-                        }
-                        break;
-                }
-        }
-
-        if (creds) {
-                *creds = c;
-                c = NULL;
-        }
-
-        r = 0;
-
-fail:
-        ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
-        return r;
-}
-
-static int bus_get_owner_dbus1(
-                sd_bus *bus,
-                const char *name,
-                uint64_t mask,
-                sd_bus_creds **creds) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
-        _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
-        const char *unique = NULL;
-        pid_t pid = 0;
-        int r;
-
-        /* Only query the owner if the caller wants to know it or if
-         * the caller just wants to check whether a name exists */
-        if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.DBus",
-                                "/org/freedesktop/DBus",
-                                "org.freedesktop.DBus",
-                                "GetNameOwner",
-                                NULL,
-                                &reply_unique,
-                                "s",
-                                name);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_read(reply_unique, "s", &unique);
-                if (r < 0)
-                        return r;
-        }
-
-        if (mask != 0) {
-                c = bus_creds_new();
-                if (!c)
-                        return -ENOMEM;
-
-                if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
-                        c->unique_name = strdup(unique);
-                        if (!c->unique_name)
-                                return -ENOMEM;
-
-                        c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
-                }
-
-                if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
-                            SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
-                            SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
-                            SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
-                            SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
-                        uint32_t u;
-
-                        r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.DBus",
-                                        "/org/freedesktop/DBus",
-                                        "org.freedesktop.DBus",
-                                        "GetConnectionUnixProcessID",
-                                        NULL,
-                                        &reply,
-                                        "s",
-                                        unique ? unique : name);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_read(reply, "u", &u);
-                        if (r < 0)
-                                return r;
-
-                        pid = u;
-                        if (mask & SD_BUS_CREDS_PID) {
-                                c->pid = u;
-                                c->mask |= SD_BUS_CREDS_PID;
-                        }
-
-                        reply = sd_bus_message_unref(reply);
-                }
-
-                if (mask & SD_BUS_CREDS_UID) {
-                        uint32_t u;
-
-                        r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.DBus",
-                                        "/org/freedesktop/DBus",
-                                        "org.freedesktop.DBus",
-                                        "GetConnectionUnixUser",
-                                        NULL,
-                                        &reply,
-                                        "s",
-                                        unique ? unique : name);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_read(reply, "u", &u);
-                        if (r < 0)
-                                return r;
-
-                        c->uid = u;
-                        c->mask |= SD_BUS_CREDS_UID;
-
-                        reply = sd_bus_message_unref(reply);
-                }
-
-                if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
-                        const void *p;
-                        size_t sz;
-
-                        r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.DBus",
-                                        "/org/freedesktop/DBus",
-                                        "org.freedesktop.DBus",
-                                        "GetConnectionSELinuxSecurityContext",
-                                        NULL,
-                                        &reply,
-                                        "s",
-                                        unique ? unique : name);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_read_array(reply, 'y', &p, &sz);
-                        if (r < 0)
-                                return r;
-
-                        c->label = strndup(p, sz);
-                        if (!c->label)
-                                return -ENOMEM;
-
-                        c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
-                }
-
-                r = bus_creds_add_more(c, mask, pid, 0);
-                if (r < 0)
-                        return r;
-        }
-
-        if (creds) {
-                *creds = c;
-                c = NULL;
-        }
-
-        return 0;
-}
-
-_public_ int sd_bus_get_owner(
-                sd_bus *bus,
-                const char *name,
-                uint64_t mask,
-                sd_bus_creds **creds) {
-
-        assert_return(bus, -EINVAL);
-        assert_return(name, -EINVAL);
-        assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
-        assert_return(mask == 0 || creds, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(service_name_is_valid(name), -EINVAL);
-        assert_return(bus->bus_client, -ENODATA);
-
-        if (bus->is_kernel)
-                return bus_get_owner_kdbus(bus, name, mask, creds);
-        else
-                return bus_get_owner_dbus1(bus, name, mask, creds);
-}
-
-static int add_name_change_match(sd_bus *bus,
-                                 uint64_t cookie,
-                                 const char *name,
-                                 const char *old_owner,
-                                 const char *new_owner) {
-
-        uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
-        int is_name_id = -1, r;
-        struct kdbus_item *item;
-
-        assert(bus);
-
-        /* If we encounter a match that could match against
-         * NameOwnerChanged messages, then we need to create
-         * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
-         * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
-         * multiple if the match is underspecified.
-         *
-         * The NameOwnerChanged signals take three parameters with
-         * unique or well-known names, but only some forms actually
-         * exist:
-         *
-         * WELLKNOWN, "", UNIQUE       → KDBUS_ITEM_NAME_ADD
-         * WELLKNOWN, UNIQUE, ""       → KDBUS_ITEM_NAME_REMOVE
-         * WELLKNOWN, UNIQUE, UNIQUE   → KDBUS_ITEM_NAME_CHANGE
-         * UNIQUE, "", UNIQUE          → KDBUS_ITEM_ID_ADD
-         * UNIQUE, UNIQUE, ""          → KDBUS_ITEM_ID_REMOVE
-         *
-         * For the latter two the two unique names must be identical.
-         *
-         * */
-
-        if (name) {
-                is_name_id = bus_kernel_parse_unique_name(name, &name_id);
-                if (is_name_id < 0)
-                        return 0;
-        }
-
-        if (!isempty(old_owner)) {
-                r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
-                if (r < 0)
-                        return 0;
-                if (r == 0)
-                        return 0;
-                if (is_name_id > 0 && old_owner_id != name_id)
-                        return 0;
-        } else
-                old_owner_id = KDBUS_MATCH_ID_ANY;
-
-        if (!isempty(new_owner)) {
-                r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return 0;
-                if (is_name_id > 0 && new_owner_id != name_id)
-                        return 0;
-        } else
-                new_owner_id = KDBUS_MATCH_ID_ANY;
-
-        if (is_name_id <= 0) {
-                struct kdbus_cmd_match *m;
-                size_t sz, l;
-
-                /* If the name argument is missing or is a well-known
-                 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
-                 * matches for it */
-
-                l = name ? strlen(name) + 1 : 0;
-
-                sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
-                            offsetof(struct kdbus_item, name_change) +
-                            offsetof(struct kdbus_notify_name_change, name) +
-                            l);
-
-                m = alloca0(sz);
-                m->size = sz;
-                m->cookie = cookie;
-
-                item = m->items;
-                item->size =
-                        offsetof(struct kdbus_item, name_change) +
-                        offsetof(struct kdbus_notify_name_change, name) +
-                        l;
-
-                item->name_change.old.id = old_owner_id;
-                item->name_change.new.id = new_owner_id;
-
-                if (name)
-                        memcpy(item->name_change.name, name, l);
-
-                /* If the old name is unset or empty, then
-                 * this can match against added names */
-                if (!old_owner || old_owner[0] == 0) {
-                        item->type = KDBUS_ITEM_NAME_ADD;
-
-                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
-                        if (r < 0)
-                                return -errno;
-                }
-
-                /* If the new name is unset or empty, then
-                 * this can match against removed names */
-                if (!new_owner || new_owner[0] == 0) {
-                        item->type = KDBUS_ITEM_NAME_REMOVE;
-
-                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
-                        if (r < 0)
-                                return -errno;
-                }
-
-                /* The CHANGE match we need in either case, because
-                 * what is reported as a name change by the kernel
-                 * might just be an owner change between starter and
-                 * normal clients. For userspace such a change should
-                 * be considered a removal/addition, hence let's
-                 * subscribe to this unconditionally. */
-                item->type = KDBUS_ITEM_NAME_CHANGE;
-                r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
-                if (r < 0)
-                        return -errno;
-        }
-
-        if (is_name_id != 0) {
-                struct kdbus_cmd_match *m;
-                uint64_t sz;
-
-                /* If the name argument is missing or is a unique
-                 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
-                 * for it */
-
-                sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
-                            offsetof(struct kdbus_item, id_change) +
-                            sizeof(struct kdbus_notify_id_change));
-
-                m = alloca0(sz);
-                m->size = sz;
-                m->cookie = cookie;
-
-                item = m->items;
-                item->size =
-                        offsetof(struct kdbus_item, id_change) +
-                        sizeof(struct kdbus_notify_id_change);
-                item->id_change.id = name_id;
-
-                /* If the old name is unset or empty, then this can
-                 * match against added ids */
-                if (!old_owner || old_owner[0] == 0) {
-                        item->type = KDBUS_ITEM_ID_ADD;
-
-                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
-                        if (r < 0)
-                                return -errno;
-                }
-
-                /* If thew new name is unset or empty, then this can
-                 * match against removed ids */
-                if (!new_owner || new_owner[0] == 0) {
-                        item->type = KDBUS_ITEM_ID_REMOVE;
-
-                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
-                        if (r < 0)
-                                return -errno;
-                }
-        }
-
-        return 0;
-}
-
-int bus_add_match_internal_kernel(
-                sd_bus *bus,
-                uint64_t id,
-                struct bus_match_component *components,
-                unsigned n_components,
-                uint64_t cookie) {
-
-        struct kdbus_cmd_match *m;
-        struct kdbus_item *item;
-        uint64_t bloom[BLOOM_SIZE/8];
-        size_t sz;
-        const char *sender = NULL;
-        size_t sender_length = 0;
-        uint64_t src_id = KDBUS_MATCH_ID_ANY;
-        bool using_bloom = false;
-        unsigned i;
-        bool matches_name_change = true;
-        const char *name_change_arg[3] = {};
-        int r;
-
-        assert(bus);
-
-        zero(bloom);
-
-        sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
-
-        for (i = 0; i < n_components; i++) {
-                struct bus_match_component *c = &components[i];
-
-                switch (c->type) {
-
-                case BUS_MATCH_SENDER:
-                        if (!streq(c->value_str, "org.freedesktop.DBus"))
-                                matches_name_change = false;
-
-                        r = bus_kernel_parse_unique_name(c->value_str, &src_id);
-                        if (r < 0)
-                                return r;
-                        else if (r > 0)
-                                sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
-                        else  {
-                                sender = c->value_str;
-                                sender_length = strlen(sender);
-                                sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
-                        }
-
-                        break;
-
-                case BUS_MATCH_MESSAGE_TYPE:
-                        if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
-                                matches_name_change = false;
-
-                        bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
-                        using_bloom = true;
-                        break;
-
-                case BUS_MATCH_INTERFACE:
-                        if (!streq(c->value_str, "org.freedesktop.DBus"))
-                                matches_name_change = false;
-
-                        bloom_add_pair(bloom, "interface", c->value_str);
-                        using_bloom = true;
-                        break;
-
-                case BUS_MATCH_MEMBER:
-                        if (!streq(c->value_str, "NameOwnerChanged"))
-                                matches_name_change = false;
-
-                        bloom_add_pair(bloom, "member", c->value_str);
-                        using_bloom = true;
-                        break;
-
-                case BUS_MATCH_PATH:
-                        if (!streq(c->value_str, "/org/freedesktop/DBus"))
-                                matches_name_change = false;
-
-                        bloom_add_pair(bloom, "path", c->value_str);
-                        using_bloom = true;
-                        break;
-
-                case BUS_MATCH_PATH_NAMESPACE:
-                        if (!streq(c->value_str, "/")) {
-                                bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
-                                using_bloom = true;
-                        }
-                        break;
-
-                case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
-                        char buf[sizeof("arg")-1 + 2 + 1];
-
-                        if (c->type - BUS_MATCH_ARG < 3)
-                                name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
-
-                        snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
-                        bloom_add_pair(bloom, buf, c->value_str);
-                        using_bloom = true;
-                        break;
-                }
-
-                case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
-                        char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
-
-                        snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
-                        bloom_add_pair(bloom, buf, c->value_str);
-                        using_bloom = true;
-                        break;
-                }
-
-                case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
-                        char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
-
-                        snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
-                        bloom_add_pair(bloom, buf, c->value_str);
-                        using_bloom = true;
-                        break;
-                }
-
-                case BUS_MATCH_DESTINATION:
-                        /* The bloom filter does not include
-                           the destination, since it is only
-                           available for broadcast messages
-                           which do not carry a destination
-                           since they are undirected. */
-                        break;
-
-                case BUS_MATCH_ROOT:
-                case BUS_MATCH_VALUE:
-                case BUS_MATCH_LEAF:
-                case _BUS_MATCH_NODE_TYPE_MAX:
-                case _BUS_MATCH_NODE_TYPE_INVALID:
-                        assert_not_reached("Invalid match type?");
-                }
-        }
-
-        if (using_bloom)
-                sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
-
-        m = alloca0(sz);
-        m->size = sz;
-        m->cookie = cookie;
-        m->owner_id = id;
-
-        item = m->items;
-
-        if (src_id != KDBUS_MATCH_ID_ANY) {
-                item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
-                item->type = KDBUS_ITEM_ID;
-                item->id = src_id;
-                item = KDBUS_ITEM_NEXT(item);
-        }
-
-        if (using_bloom) {
-                item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
-                item->type = KDBUS_ITEM_BLOOM;
-                memcpy(item->data64, bloom, BLOOM_SIZE);
-                item = KDBUS_ITEM_NEXT(item);
-        }
-
-        if (sender) {
-                item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
-                item->type = KDBUS_ITEM_NAME;
-                memcpy(item->str, sender, sender_length + 1);
-        }
-
-        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
-        if (r < 0)
-                return -errno;
-
-        if (matches_name_change) {
-
-                /* If this match could theoretically match
-                 * NameOwnerChanged messages, we need to
-                 * install a second non-bloom filter explitly
-                 * for it */
-
-                r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int bus_add_match_internal_dbus1(
-                sd_bus *bus,
-                const char *match) {
-
-        assert(bus);
-        assert(match);
-
-        return sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "AddMatch",
-                        NULL,
-                        NULL,
-                        "s",
-                        match);
-}
-
-int bus_add_match_internal(
-                sd_bus *bus,
-                const char *match,
-                struct bus_match_component *components,
-                unsigned n_components,
-                uint64_t cookie) {
-
-        assert(bus);
-        assert(match);
-
-        if (bus->is_kernel)
-                return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
-        else
-                return bus_add_match_internal_dbus1(bus, match);
-}
-
-int bus_remove_match_internal_kernel(
-                sd_bus *bus,
-                uint64_t id,
-                uint64_t cookie) {
-
-        struct kdbus_cmd_match m;
-        int r;
-
-        assert(bus);
-
-        zero(m);
-        m.size = offsetof(struct kdbus_cmd_match, items);
-        m.cookie = cookie;
-        m.owner_id = id;
-
-        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int bus_remove_match_internal_dbus1(
-                sd_bus *bus,
-                const char *match) {
-
-        assert(bus);
-        assert(match);
-
-        return sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "RemoveMatch",
-                        NULL,
-                        NULL,
-                        "s",
-                        match);
-}
-
-int bus_remove_match_internal(
-                sd_bus *bus,
-                const char *match,
-                uint64_t cookie) {
-
-        assert(bus);
-        assert(match);
-
-        if (bus->is_kernel)
-                return bus_remove_match_internal_kernel(bus, 0, cookie);
-        else
-                return bus_remove_match_internal_dbus1(bus, match);
-}
-
-_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
-        const char *mid;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(name, -EINVAL);
-        assert_return(machine, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(service_name_is_valid(name), -EINVAL);
-
-        if (streq_ptr(name, bus->unique_name))
-                return sd_id128_get_machine(machine);
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        name,
-                        "/",
-                        "org.freedesktop.DBus.Peer",
-                        "GetMachineId", &m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_set_no_auto_start(m, true);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_call(bus, m, 0, NULL, &reply);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read(reply, "s", &mid);
-        if (r < 0)
-                return r;
-
-        return sd_id128_from_string(mid, machine);
-}
diff --git a/src/libsystemd/bus-control.h b/src/libsystemd/bus-control.h
deleted file mode 100644
index b610bef..0000000
--- a/src/libsystemd/bus-control.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- 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-bus.h"
-
-int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
-int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
-
-int bus_add_match_internal_kernel(sd_bus *bus, uint64_t id, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
-int bus_remove_match_internal_kernel(sd_bus *bus, uint64_t id, uint64_t cookie);
diff --git a/src/libsystemd/bus-convenience.c b/src/libsystemd/bus-convenience.c
deleted file mode 100644
index 3964960..0000000
--- a/src/libsystemd/bus-convenience.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/*-*- 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 "bus-internal.h"
-#include "bus-message.h"
-#include "bus-signature.h"
-#include "bus-util.h"
-#include "bus-type.h"
-
-_public_ int sd_bus_emit_signal(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *member,
-                const char *types, ...) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_message_new_signal(bus, path, interface, member, &m);
-        if (r < 0)
-                return r;
-
-        if (!isempty(types)) {
-                va_list ap;
-
-                va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
-                va_end(ap);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_send(bus, m, NULL);
-}
-
-_public_ int sd_bus_call_method(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_error *error,
-                sd_bus_message **reply,
-                const char *types, ...) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
-        if (r < 0)
-                return r;
-
-        if (!isempty(types)) {
-                va_list ap;
-
-                va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
-                va_end(ap);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_call(bus, m, 0, error, reply);
-}
-
-_public_ int sd_bus_reply_method_return(
-                sd_bus_message *call,
-                const char *types, ...) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert_return(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(call->bus), -ECHILD);
-
-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
-                return 0;
-
-        r = sd_bus_message_new_method_return(call, &m);
-        if (r < 0)
-                return r;
-
-        if (!isempty(types)) {
-                va_list ap;
-
-                va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
-                va_end(ap);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_send(call->bus, m, NULL);
-}
-
-_public_ int sd_bus_reply_method_error(
-                sd_bus_message *call,
-                const sd_bus_error *e) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert_return(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(sd_bus_error_is_set(e), -EINVAL);
-        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(call->bus), -ECHILD);
-
-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
-                return 0;
-
-        r = sd_bus_message_new_method_error(call, e, &m);
-        if (r < 0)
-                return r;
-
-        return sd_bus_send(call->bus, m, NULL);
-}
-
-_public_ int sd_bus_reply_method_errorf(
-                sd_bus_message *call,
-                const char *name,
-                const char *format,
-                ...) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        va_list ap;
-
-        assert_return(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(call->bus), -ECHILD);
-
-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
-                return 0;
-
-        va_start(ap, format);
-        bus_error_setfv(&error, name, format, ap);
-        va_end(ap);
-
-        return sd_bus_reply_method_error(call, &error);
-}
-
-_public_ int sd_bus_reply_method_errno(
-                sd_bus_message *call,
-                int error,
-                const sd_bus_error *p) {
-
-        _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
-
-        assert_return(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(call->bus), -ECHILD);
-
-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
-                return 0;
-
-        if (sd_bus_error_is_set(p))
-                return sd_bus_reply_method_error(call, p);
-
-        sd_bus_error_set_errno(&berror, error);
-
-        return sd_bus_reply_method_error(call, &berror);
-}
-
-_public_ int sd_bus_reply_method_errnof(
-                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(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(call->bus), -ECHILD);
-
-        if (call->header->flags & 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(call, &berror);
-}
-
-_public_ int sd_bus_get_property(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_error *error,
-                sd_bus_message **reply,
-                const char *type) {
-
-        sd_bus_message *rep = NULL;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(reply, -EINVAL);
-        assert_return(signature_is_single(type, false), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(rep, 'v', type);
-        if (r < 0) {
-                sd_bus_message_unref(rep);
-                return r;
-        }
-
-        *reply = rep;
-        return 0;
-}
-
-_public_ int sd_bus_get_property_trivial(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_error *error,
-                char type, void *ptr) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(bus_type_is_trivial(type), -EINVAL);
-        assert_return(ptr, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read_basic(reply, type, ptr);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-_public_ int sd_bus_get_property_string(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_error *error,
-                char **ret) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        const char *s;
-        char *n;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(reply, 'v', "s");
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read_basic(reply, 's', &s);
-        if (r < 0)
-                return r;
-
-        n = strdup(s);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 0;
-}
-
-_public_ int sd_bus_get_property_strv(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_error *error,
-                char ***ret) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(reply, 'v', NULL);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read_strv(reply, ret);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-_public_ int sd_bus_set_property(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_error *error,
-                const char *type, ...) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        va_list ap;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(signature_is_single(type, false), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append(m, "ss", strempty(interface), member);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_open_container(m, 'v', type);
-        if (r < 0)
-                return r;
-
-        va_start(ap, type);
-        r = bus_message_append_ap(m, type, ap);
-        va_end(ap);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_close_container(m);
-        if (r < 0)
-                return r;
-
-        return sd_bus_call(bus, m, 0, error, NULL);
-}
-
-_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
-        sd_bus_creds *c;
-
-        assert_return(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(call->bus), -ECHILD);
-
-        c = sd_bus_message_get_creds(call);
-
-        /* All data we need? */
-        if (c && (mask & ~c->mask) == 0) {
-                *creds = sd_bus_creds_ref(c);
-                return 0;
-        }
-
-        /* No data passed? Or not enough data passed to retrieve the missing bits? */
-        if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
-                /* We couldn't read anything from the call, let's try
-                 * to get it from the sender or peer */
-
-                if (call->sender)
-                        return sd_bus_get_owner(call->bus, call->sender, mask, creds);
-                else
-                        return sd_bus_get_peer_creds(call->bus, mask, creds);
-        }
-
-        return bus_creds_extend_by_pid(c, mask, creds);
-}
diff --git a/src/libsystemd/bus-creds.c b/src/libsystemd/bus-creds.c
deleted file mode 100644
index 52e55fc..0000000
--- a/src/libsystemd/bus-creds.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/*-*- 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 <stdlib.h>
-
-#include "util.h"
-#include "cgroup-util.h"
-#include "fileio.h"
-#include "audit.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "time-util.h"
-#include "strv.h"
-#include "bus-creds.h"
-
-enum {
-        CAP_OFFSET_INHERITABLE = 0,
-        CAP_OFFSET_PERMITTED = 1,
-        CAP_OFFSET_EFFECTIVE = 2,
-        CAP_OFFSET_BOUNDING = 3
-};
-
-void bus_creds_done(sd_bus_creds *c) {
-        assert(c);
-
-        /* For internal bus cred structures that are allocated by
-         * something else */
-
-        free(c->session);
-        free(c->unit);
-        free(c->user_unit);
-        free(c->slice);
-
-        strv_free(c->cmdline_array);
-        strv_free(c->well_known_names);
-}
-
-_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
-        assert_return(c, NULL);
-
-        if (c->allocated) {
-                assert(c->n_ref > 0);
-                c->n_ref++;
-        } else {
-                sd_bus_message *m;
-
-                /* If this is an embedded creds structure, then
-                 * forward ref counting to the message */
-                m = container_of(c, sd_bus_message, creds);
-                sd_bus_message_ref(m);
-        }
-
-        return c;
-}
-
-_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
-
-        if (!c)
-                return NULL;
-
-        if (c->allocated) {
-                assert(c->n_ref > 0);
-                c->n_ref--;
-
-                if (c->n_ref == 0) {
-                        bus_creds_done(c);
-
-                        free(c->comm);
-                        free(c->tid_comm);
-                        free(c->exe);
-                        free(c->cmdline);
-                        free(c->cgroup);
-                        free(c->capability);
-                        free(c->label);
-                        free(c->unique_name);
-                        free(c->cgroup_root);
-                        free(c);
-                }
-        } else {
-                sd_bus_message *m;
-
-                m = container_of(c, sd_bus_message, creds);
-                sd_bus_message_unref(m);
-        }
-
-
-        return NULL;
-}
-
-_public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
-        assert_return(c, 0);
-
-        return c->mask;
-}
-
-sd_bus_creds* bus_creds_new(void) {
-        sd_bus_creds *c;
-
-        c = new0(sd_bus_creds, 1);
-        if (!c)
-                return NULL;
-
-        c->allocated = true;
-        c->n_ref = 1;
-        return c;
-}
-
-_public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
-        sd_bus_creds *c;
-        int r;
-
-        assert_return(pid >= 0, -EINVAL);
-        assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
-        assert_return(ret, -EINVAL);
-
-        if (pid == 0)
-                pid = getpid();
-
-        c = bus_creds_new();
-        if (!c)
-                return -ENOMEM;
-
-        r = bus_creds_add_more(c, mask, pid, 0);
-        if (r < 0) {
-                sd_bus_creds_unref(c);
-                return r;
-        }
-
-        /* Check if the process existed at all, in case we haven't
-         * figured that out already */
-        if (kill(pid, 0) < 0 && errno == ESRCH) {
-                sd_bus_creds_unref(c);
-                return -ESRCH;
-        }
-
-        *ret = c;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
-        assert_return(c, -EINVAL);
-        assert_return(uid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_UID))
-                return -ENODATA;
-
-        *uid = c->uid;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
-        assert_return(c, -EINVAL);
-        assert_return(gid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_UID))
-                return -ENODATA;
-
-        *gid = c->gid;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
-        assert_return(c, -EINVAL);
-        assert_return(pid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_PID))
-                return -ENODATA;
-
-        assert(c->pid > 0);
-        *pid = c->pid;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
-        assert_return(c, -EINVAL);
-        assert_return(tid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_TID))
-                return -ENODATA;
-
-        assert(c->tid > 0);
-        *tid = c->tid;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
-        assert_return(c, -EINVAL);
-        assert_return(usec, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
-                return -ENODATA;
-
-        assert(c->pid_starttime > 0);
-        *usec = c->pid_starttime;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
-        assert_return(c, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
-                return -ENODATA;
-
-        assert(c->label);
-        *ret = c->label;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_COMM))
-                return -ENODATA;
-
-        assert(c->comm);
-        *ret = c->comm;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_TID_COMM))
-                return -ENODATA;
-
-        assert(c->tid_comm);
-        *ret = c->tid_comm;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_EXE))
-                return -ENODATA;
-
-        assert(c->exe);
-        *ret = c->exe;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_CGROUP))
-                return -ENODATA;
-
-        assert(c->cgroup);
-        *ret = c->cgroup;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
-        int r;
-
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_UNIT))
-                return -ENODATA;
-
-        assert(c->cgroup);
-
-        if (!c->unit) {
-                const char *shifted;
-
-                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
-                if (r < 0)
-                        return r;
-
-                r = cg_path_get_unit(shifted, (char**) &c->unit);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = c->unit;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
-        int r;
-
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
-                return -ENODATA;
-
-        assert(c->cgroup);
-
-        if (!c->user_unit) {
-                const char *shifted;
-
-                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
-                if (r < 0)
-                        return r;
-
-                r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = c->user_unit;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
-        int r;
-
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_SLICE))
-                return -ENODATA;
-
-        assert(c->cgroup);
-
-        if (!c->slice) {
-                const char *shifted;
-
-                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
-                if (r < 0)
-                        return r;
-
-                r = cg_path_get_slice(shifted, (char**) &c->slice);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = c->slice;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
-        int r;
-
-        assert_return(c, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_SESSION))
-                return -ENODATA;
-
-        assert(c->cgroup);
-
-        if (!c->session) {
-                const char *shifted;
-
-                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
-                if (r < 0)
-                        return r;
-
-                r = cg_path_get_session(shifted, (char**) &c->session);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = c->session;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
-        const char *shifted;
-        int r;
-
-        assert_return(c, -EINVAL);
-        assert_return(uid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
-                return -ENODATA;
-
-        assert(c->cgroup);
-
-        r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
-        if (r < 0)
-                return r;
-
-        return cg_path_get_owner_uid(shifted, uid);
-}
-
-_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
-        assert_return(c, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_CMDLINE))
-                return -ENODATA;
-
-        assert_return(c->cmdline, -ESRCH);
-        assert(c->cmdline);
-
-        if (!c->cmdline_array) {
-                c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
-                if (!c->cmdline_array)
-                        return -ENOMEM;
-        }
-
-        *cmdline = c->cmdline_array;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
-        assert_return(c, -EINVAL);
-        assert_return(sessionid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
-                return -ENODATA;
-
-        *sessionid = c->audit_session_id;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
-        assert_return(c, -EINVAL);
-        assert_return(uid, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
-                return -ENODATA;
-
-        *uid = c->audit_login_uid;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
-        assert_return(c, -EINVAL);
-        assert_return(unique_name, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
-                return -ENODATA;
-
-        *unique_name = c->unique_name;
-        return 0;
-}
-
-_public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
-        assert_return(c, -EINVAL);
-        assert_return(well_known_names, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
-                return -ENODATA;
-
-        *well_known_names = c->well_known_names;
-        return 0;
-}
-
-static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
-        size_t sz;
-
-        assert(c);
-        assert(c->capability);
-
-        sz = c->capability_size / 4;
-        if ((size_t) capability >= sz*8)
-                return 0;
-
-        return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
-}
-
-_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
-        assert_return(c, -EINVAL);
-        assert_return(capability >= 0, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
-                return -ENODATA;
-
-        return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
-}
-
-_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
-        assert_return(c, -EINVAL);
-        assert_return(capability >= 0, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
-                return -ENODATA;
-
-        return has_cap(c, CAP_OFFSET_PERMITTED, capability);
-}
-
-_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
-        assert_return(c, -EINVAL);
-        assert_return(capability >= 0, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
-                return -ENODATA;
-
-        return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
-}
-
-_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
-        assert_return(c, -EINVAL);
-        assert_return(capability >= 0, -EINVAL);
-
-        if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
-                return -ENODATA;
-
-        return has_cap(c, CAP_OFFSET_BOUNDING, capability);
-}
-
-static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
-        size_t sz;
-        unsigned i;
-
-        assert(c);
-        assert(p);
-
-        p += strspn(p, WHITESPACE);
-
-        sz = strlen(p);
-        if (sz % 2 != 0)
-                return -EINVAL;
-
-        sz /= 2;
-        if (!c->capability) {
-                c->capability = new0(uint8_t, sz * 4);
-                if (!c->capability)
-                        return -ENOMEM;
-
-                c->capability_size = sz * 4;
-        }
-
-        for (i = 0; i < sz; i ++) {
-                int x, y;
-
-                x = unhexchar(p[i*2]);
-                y = unhexchar(p[i*2+1]);
-
-                if (x < 0 || y < 0)
-                        return -EINVAL;
-
-                c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
-        }
-
-        return 0;
-}
-
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
-        uint64_t missing;
-        int r;
-
-        assert(c);
-        assert(c->allocated);
-
-        missing = mask & ~c->mask;
-        if (missing == 0)
-                return 0;
-
-        /* Try to retrieve PID from creds if it wasn't passed to us */
-        if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
-                pid = c->pid;
-
-        if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
-                tid = c->pid;
-
-        /* Without pid we cannot do much... */
-        if (pid <= 0)
-                return 0;
-
-        if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
-                       SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
-                       SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
-
-                _cleanup_fclose_ FILE *f = NULL;
-                char line[LINE_MAX];
-                const char *p;
-
-                p = procfs_file_alloca(pid, "status");
-
-                f = fopen(p, "re");
-                if (!f)
-                        return errno == ENOENT ? -ESRCH : -errno;
-
-                FOREACH_LINE(line, f, return -errno) {
-                        truncate_nl(line);
-
-                        if (missing & SD_BUS_CREDS_UID) {
-                                p = startswith(line, "Uid:");
-                                if (p) {
-                                        unsigned long uid;
-
-                                        p += strspn(p, WHITESPACE);
-                                        if (sscanf(p, "%lu", &uid) != 1)
-                                                return -EIO;
-
-                                        c->uid = (uid_t) uid;
-                                        c->mask |= SD_BUS_CREDS_UID;
-                                        continue;
-                                }
-                        }
-
-                        if (missing & SD_BUS_CREDS_GID) {
-                                p = startswith(line, "Gid:");
-                                if (p) {
-                                        unsigned long gid;
-
-                                        p += strspn(p, WHITESPACE);
-                                        if (sscanf(p, "%lu", &gid) != 1)
-                                                return -EIO;
-
-                                        c->gid = (uid_t) gid;
-                                        c->mask |= SD_BUS_CREDS_GID;
-                                        continue;
-                                }
-                        }
-
-                        if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
-                                p = startswith(line, "CapEff:");
-                                if (p) {
-                                        r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
-                                        if (r < 0)
-                                                return r;
-
-                                        c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
-                                        continue;
-                                }
-                        }
-
-                        if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
-                                p = startswith(line, "CapPrm:");
-                                if (p) {
-                                        r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
-                                        if (r < 0)
-                                                return r;
-
-                                        c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
-                                        continue;
-                                }
-                        }
-
-                        if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
-                                p = startswith(line, "CapInh:");
-                                if (p) {
-                                        r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
-                                        if (r < 0)
-                                                return r;
-
-                                        c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
-                                        continue;
-                                }
-                        }
-
-                        if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
-                                p = startswith(line, "CapBnd:");
-                                if (p) {
-                                        r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
-                                        if (r < 0)
-                                                return r;
-
-                                        c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
-                                        continue;
-                                }
-                        }
-                }
-        }
-
-        if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
-                unsigned long long st;
-
-                r = get_starttime_of_pid(pid, &st);
-                if (r < 0)
-                        return r;
-
-                c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
-                c->mask |= SD_BUS_CREDS_PID_STARTTIME;
-        }
-
-        if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
-                const char *p;
-
-                p = procfs_file_alloca(pid, "attr/current");
-                r = read_one_line_file(p, &c->label);
-                if (r < 0 && r != -ENOENT && r != -EINVAL)
-                        return r;
-                else if (r >= 0)
-                        c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
-        }
-
-        if (missing & SD_BUS_CREDS_COMM) {
-                r = get_process_comm(pid, &c->comm);
-                if (r < 0)
-                        return r;
-
-                c->mask |= SD_BUS_CREDS_COMM;
-        }
-
-        if (missing & SD_BUS_CREDS_EXE) {
-                r = get_process_exe(pid, &c->exe);
-                if (r < 0)
-                        return r;
-
-                c->mask |= SD_BUS_CREDS_EXE;
-        }
-
-        if (missing & SD_BUS_CREDS_CMDLINE) {
-                const char *p;
-
-                p = procfs_file_alloca(pid, "cmdline");
-                r = read_full_file(p, &c->cmdline, &c->cmdline_size);
-                if (r < 0)
-                        return r;
-
-                if (c->cmdline_size == 0) {
-                        free(c->cmdline);
-                        c->cmdline = NULL;
-                } else
-                        c->mask |= SD_BUS_CREDS_CMDLINE;
-        }
-
-        if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
-                _cleanup_free_ char *p = NULL;
-
-                if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
-                        return -ENOMEM;
-
-                r = read_one_line_file(p, &c->tid_comm);
-                if (r < 0)
-                        return r == -ENOENT ? -ESRCH : r;
-
-                c->mask |= SD_BUS_CREDS_TID_COMM;
-        }
-
-        if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
-
-                r = cg_pid_get_path(NULL, pid, &c->cgroup);
-                if (r < 0)
-                        return r;
-
-                r = cg_get_root_path(&c->cgroup_root);
-                if (r < 0)
-                        return r;
-
-                c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
-        }
-
-        if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
-                r = audit_session_from_pid(pid, &c->audit_session_id);
-                if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
-                        return r;
-                else if (r >= 0)
-                        c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
-        }
-
-        if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
-                r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
-                if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
-                        return r;
-                else if (r >= 0)
-                        c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
-        }
-
-        return 0;
-}
-
-int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
-        _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
-        int r;
-
-        assert(c);
-        assert(ret);
-
-        if ((mask & ~c->mask) == 0) {
-                /* There's already all data we need. */
-
-                *ret = sd_bus_creds_ref(c);
-                return 0;
-        }
-
-        n = bus_creds_new();
-        if (!n)
-                return -ENOMEM;
-
-        /* Copy the original data over */
-
-        if (c->mask & mask & SD_BUS_CREDS_UID) {
-                n->uid = c->uid;
-                n->mask |= SD_BUS_CREDS_UID;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_GID) {
-                n->gid = c->gid;
-                n->mask |= SD_BUS_CREDS_GID;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_PID) {
-                n->pid = c->pid;
-                n->mask |= SD_BUS_CREDS_PID;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_TID) {
-                n->tid = c->tid;
-                n->mask |= SD_BUS_CREDS_TID;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
-                n->pid_starttime = c->pid_starttime;
-                n->mask |= SD_BUS_CREDS_PID_STARTTIME;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_COMM) {
-                n->comm = strdup(c->comm);
-                if (!n->comm)
-                        return -ENOMEM;
-
-                n->mask |= SD_BUS_CREDS_COMM;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
-                n->tid_comm = strdup(c->tid_comm);
-                if (!n->tid_comm)
-                        return -ENOMEM;
-
-                n->mask |= SD_BUS_CREDS_TID_COMM;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_EXE) {
-                n->exe = strdup(c->exe);
-                if (!n->exe)
-                        return -ENOMEM;
-
-                n->mask |= SD_BUS_CREDS_EXE;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
-                n->cmdline = memdup(c->cmdline, c->cmdline_size);
-                if (!n->cmdline)
-                        return -ENOMEM;
-
-                n->cmdline_size = c->cmdline_size;
-                n->mask |= SD_BUS_CREDS_CMDLINE;
-        }
-
-        if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) {
-                n->cgroup = strdup(c->cgroup);
-                if (!n->cgroup)
-                        return -ENOMEM;
-
-                n->cgroup_root = strdup(c->cgroup_root);
-                if (!n->cgroup_root)
-                        return -ENOMEM;
-
-                n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID);
-        }
-
-        if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
-                n->capability = memdup(c->capability, c->capability_size);
-                if (!n->capability)
-                        return -ENOMEM;
-
-                n->capability_size = c->capability_size;
-                n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
-                n->audit_session_id = c->audit_session_id;
-                n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
-                n->audit_login_uid = c->audit_login_uid;
-                n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
-                n->unique_name = strdup(c->unique_name);
-                if (!n->unique_name)
-                        return -ENOMEM;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
-                n->well_known_names = strv_copy(c->well_known_names);
-                if (!n->well_known_names)
-                        return -ENOMEM;
-        }
-
-        /* Get more data */
-
-        r = bus_creds_add_more(n, mask,
-                               c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
-                               c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
-        if (r < 0)
-                return r;
-
-        *ret = n;
-        n = NULL;
-        return 0;
-}
diff --git a/src/libsystemd/bus-creds.h b/src/libsystemd/bus-creds.h
deleted file mode 100644
index d8b4aca..0000000
--- a/src/libsystemd/bus-creds.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-*- 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 <stdbool.h>
-
-#include "sd-bus.h"
-#include "time-util.h"
-
-struct sd_bus_creds {
-        bool allocated;
-        unsigned n_ref;
-        uint64_t mask;
-
-        uid_t uid;
-        gid_t gid;
-        pid_t pid;
-        usec_t pid_starttime;
-        pid_t tid;
-
-        char *comm;
-        char *tid_comm;
-        char *exe;
-
-        char *cmdline;
-        size_t cmdline_size;
-        char **cmdline_array;
-
-        char *cgroup;
-        char *session;
-        char *unit;
-        char *user_unit;
-        char *slice;
-
-        uint8_t *capability;
-        size_t capability_size;
-
-        uint32_t audit_session_id;
-        uid_t audit_login_uid;
-
-        char *label;
-
-        char *unique_name;
-
-        char **well_known_names;
-
-        char *cgroup_root;
-};
-
-sd_bus_creds* bus_creds_new(void);
-
-void bus_creds_done(sd_bus_creds *c);
-
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid);
-
-int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret);
diff --git a/src/libsystemd/bus-dump.c b/src/libsystemd/bus-dump.c
deleted file mode 100644
index 78e7597..0000000
--- a/src/libsystemd/bus-dump.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*-*- 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 "util.h"
-#include "capability.h"
-#include "strv.h"
-#include "audit.h"
-
-#include "bus-message.h"
-#include "bus-internal.h"
-#include "bus-type.h"
-#include "bus-dump.h"
-
-static char *indent(unsigned level) {
-        char *p;
-
-        p = new(char, 2 + level + 1);
-        if (!p)
-                return NULL;
-
-        p[0] = p[1] = ' ';
-        memset(p + 2, '\t', level);
-        p[2 + level] = 0;
-
-        return p;
-}
-
-int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
-        unsigned level = 1;
-        int r;
-
-        assert(m);
-
-        if (!f)
-                f = stdout;
-
-        if (with_header) {
-                fprintf(f,
-                        "%s%s%sType=%s%s%s  Endian=%c  Flags=%u  Version=%u",
-                        m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
-                        m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
-                        m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
-                        ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
-                        m->header->endian,
-                        m->header->flags,
-                        m->header->version);
-
-                /* Display synthetic message serial number in a more readable
-                 * format than (uint32_t) -1 */
-                if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
-                        fprintf(f, " Cookie=-1");
-                else
-                        fprintf(f, " Cookie=%lu", (unsigned long) BUS_MESSAGE_COOKIE(m));
-
-                if (m->reply_cookie != 0)
-                        fprintf(f, "  ReplyCookie=%lu", (unsigned long) m->reply_cookie);
-
-                fputs("\n", f);
-
-                if (m->sender)
-                        fprintf(f, "  Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
-                if (m->destination)
-                        fprintf(f, "  Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
-                if (m->path)
-                        fprintf(f, "  Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
-                if (m->interface)
-                        fprintf(f, "  Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
-                if (m->member)
-                        fprintf(f, "  Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
-
-                if (m->sender || m->destination || m->path || m->interface || m->member)
-                        fputs("\n", f);
-
-                if (sd_bus_error_is_set(&m->error))
-                        fprintf(f,
-                                "  ErrorName=%s%s%s"
-                                "  ErrorMessage=%s\"%s\"%s\n",
-                                ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
-                                ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
-
-                if (m->monotonic != 0)
-                        fprintf(f, "  Monotonic=%llu", (unsigned long long) m->monotonic);
-                if (m->realtime != 0)
-                        fprintf(f, "  Realtime=%llu", (unsigned long long) m->realtime);
-
-                if (m->monotonic != 0 || m->realtime != 0)
-                        fputs("\n", f);
-
-                bus_creds_dump(&m->creds, f);
-        }
-
-        r = sd_bus_message_rewind(m, true);
-        if (r < 0) {
-                log_error("Failed to rewind: %s", strerror(-r));
-                return r;
-        }
-
-        fprintf(f, "  MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
-
-        for (;;) {
-                _cleanup_free_ char *prefix = NULL;
-                const char *contents = NULL;
-                char type;
-                union {
-                        uint8_t u8;
-                        uint16_t u16;
-                        int16_t s16;
-                        uint32_t u32;
-                        int32_t s32;
-                        uint64_t u64;
-                        int64_t s64;
-                        double d64;
-                        const char *string;
-                        int i;
-                } basic;
-
-                r = sd_bus_message_peek_type(m, &type, &contents);
-                if (r < 0) {
-                        log_error("Failed to peek type: %s", strerror(-r));
-                        return r;
-                }
-
-                if (r == 0) {
-                        if (level <= 1)
-                                break;
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0) {
-                                log_error("Failed to exit container: %s", strerror(-r));
-                                return r;
-                        }
-
-                        level--;
-
-                        prefix = indent(level);
-                        if (!prefix)
-                                return log_oom();
-
-                        fprintf(f, "%s};\n", prefix);
-                        continue;
-                }
-
-                prefix = indent(level);
-                if (!prefix)
-                        return log_oom();
-
-                if (bus_type_is_container(type) > 0) {
-                        r = sd_bus_message_enter_container(m, type, contents);
-                        if (r < 0) {
-                                log_error("Failed to enter container: %s", strerror(-r));
-                                return r;
-                        }
-
-                        if (type == SD_BUS_TYPE_ARRAY)
-                                fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
-                        else if (type == SD_BUS_TYPE_VARIANT)
-                                fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
-                        else if (type == SD_BUS_TYPE_STRUCT)
-                                fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
-                        else if (type == SD_BUS_TYPE_DICT_ENTRY)
-                                fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
-
-                        level ++;
-
-                        continue;
-                }
-
-                r = sd_bus_message_read_basic(m, type, &basic);
-                if (r < 0) {
-                        log_error("Failed to get basic: %s", strerror(-r));
-                        return r;
-                }
-
-                assert(r > 0);
-
-                switch (type) {
-
-                case SD_BUS_TYPE_BYTE:
-                        fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_BOOLEAN:
-                        fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_INT16:
-                        fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_UINT16:
-                        fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_INT32:
-                        fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_UINT32:
-                        fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_INT64:
-                        fprintf(f, "%sINT64 %s%lli%s;\n", prefix, ansi_highlight(), (long long) basic.s64, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_UINT64:
-                        fprintf(f, "%sUINT64 %s%llu%s;\n", prefix, ansi_highlight(), (unsigned long long) basic.u64, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_DOUBLE:
-                        fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_STRING:
-                        fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_OBJECT_PATH:
-                        fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_SIGNATURE:
-                        fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
-                        break;
-
-                case SD_BUS_TYPE_UNIX_FD:
-                        fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
-                        break;
-
-                default:
-                        assert_not_reached("Unknown basic type.");
-                }
-        }
-
-        fprintf(f, "  };\n\n");
-        return 0;
-}
-
-static void dump_capabilities(
-                sd_bus_creds *c,
-                FILE *f,
-                const char *name,
-                int (*has)(sd_bus_creds *c, int capability)) {
-
-        unsigned long i, last_cap;
-        unsigned n = 0;
-        int r;
-
-        assert(c);
-        assert(f);
-        assert(name);
-        assert(has);
-
-        i = 0;
-        r = has(c, i);
-        if (r < 0)
-                return;
-
-        fprintf(f, "  %s=", name);
-        last_cap = cap_last_cap();
-
-        for (;;) {
-                if (r > 0) {
-                        _cleanup_cap_free_charp_ char *t;
-
-                        if (n > 0)
-                                fputc(' ', f);
-                        if (n % 4 == 3)
-                                fputs("\n          ", f);
-
-                        t = cap_to_name(i);
-                        fprintf(f, "%s", t);
-                        n++;
-                }
-
-                i++;
-
-                if (i > last_cap)
-                        break;
-
-                r = has(c, i);
-        }
-
-        fputs("\n", f);
-}
-
-int bus_creds_dump(sd_bus_creds *c, FILE *f) {
-        bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
-        const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
-        uid_t owner, audit_loginuid;
-        uint32_t audit_sessionid;
-        char **cmdline = NULL, **well_known = NULL;
-        int r;
-
-        assert(c);
-
-        if (!f)
-                f = stdout;
-
-        if (c->mask & SD_BUS_CREDS_PID)
-                fprintf(f, "  PID=%lu", (unsigned long) c->pid);
-        if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
-                fprintf(f, "  PIDStartTime=%llu", (unsigned long long) c->pid_starttime);
-        if (c->mask & SD_BUS_CREDS_TID)
-                fprintf(f, "  TID=%lu", (unsigned long) c->tid);
-        if (c->mask & SD_BUS_CREDS_UID)
-                fprintf(f, "  UID=%lu", (unsigned long) c->uid);
-        r = sd_bus_creds_get_owner_uid(c, &owner);
-        if (r >= 0)
-                fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
-        if (c->mask & SD_BUS_CREDS_GID)
-                fprintf(f, "  GID=%lu", (unsigned long) c->gid);
-
-        if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0)
-                fputs("\n", f);
-
-        if (c->mask & SD_BUS_CREDS_EXE)
-                fprintf(f, "  Exe=%s", c->exe);
-        if (c->mask & SD_BUS_CREDS_COMM)
-                fprintf(f, "  Comm=%s", c->comm);
-        if (c->mask & SD_BUS_CREDS_TID_COMM)
-                fprintf(f, "  TIDComm=%s", c->tid_comm);
-        if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
-                fprintf(f, "  Label=%s", c->label);
-
-        if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_SELINUX_CONTEXT))
-                fputs("\n", f);
-
-        if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
-                char **i;
-
-                fputs("  CommandLine={", f);
-                STRV_FOREACH(i, cmdline) {
-                        if (i != cmdline)
-                                fputc(' ', f);
-
-                        fputs(*i, f);
-                }
-
-                fputs("}\n", f);
-        }
-
-        if (c->mask & SD_BUS_CREDS_CGROUP)
-                fprintf(f, "  CGroup=%s", c->cgroup);
-        sd_bus_creds_get_unit(c, &u);
-        if (u)
-                fprintf(f, "  Unit=%s", u);
-        sd_bus_creds_get_user_unit(c, &uu);
-        if (uu)
-                fprintf(f, "  UserUnit=%s", uu);
-        sd_bus_creds_get_slice(c, &sl);
-        if (sl)
-                fprintf(f, "  Slice=%s", sl);
-        sd_bus_creds_get_session(c, &s);
-        if (s)
-                fprintf(f, "  Session=%s", s);
-
-        if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
-                fputs("\n", f);
-
-        if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
-                audit_loginuid_is_set = true;
-                fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
-        }
-        if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
-                audit_sessionid_is_set = true;
-                fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
-        }
-
-        if (audit_loginuid_is_set || audit_sessionid_is_set)
-                fputs("\n", f);
-
-        if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
-                fprintf(f, "  UniqueName=%s", c->unique_name);
-
-        if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
-                char **i;
-
-                fputs("  WellKnownNames={", f);
-                STRV_FOREACH(i, well_known) {
-                        if (i != well_known)
-                                fputc(' ', f);
-
-                        fputs(*i, f);
-                }
-
-                fputc('}', f);
-        }
-
-        if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
-                fputc('\n', f);
-
-        dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
-        dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
-        dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
-        dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
-
-        return 0;
-}
diff --git a/src/libsystemd/bus-dump.h b/src/libsystemd/bus-dump.h
deleted file mode 100644
index bb1d25d..0000000
--- a/src/libsystemd/bus-dump.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- 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 <stdio.h>
-#include <stdbool.h>
-
-#include "sd-bus.h"
-
-int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header);
-
-int bus_creds_dump(sd_bus_creds *c, FILE *f);
diff --git a/src/libsystemd/bus-error-mapping.gperf b/src/libsystemd/bus-error-mapping.gperf
deleted file mode 100644
index df2c4d4..0000000
--- a/src/libsystemd/bus-error-mapping.gperf
+++ /dev/null
@@ -1,49 +0,0 @@
-%{
-#include <errno.h>
-#include "bus-error.h"
-%}
-name_error_mapping;
-%null_strings
-%language=ANSI-C
-%define slot-name name
-%define hash-function-name bus_error_mapping_hash
-%define lookup-function-name bus_error_mapping_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-org.freedesktop.DBus.Error.Failed,                        EACCES
-org.freedesktop.DBus.Error.NoMemory,                      ENOMEM
-org.freedesktop.DBus.Error.ServiceUnknown,                EHOSTUNREACH
-org.freedesktop.DBus.Error.NameHasNoOwner,                ENXIO
-org.freedesktop.DBus.Error.NoReply,                       ETIMEDOUT
-org.freedesktop.DBus.Error.IOError,                       EIO
-org.freedesktop.DBus.Error.BadAddress,                    EADDRNOTAVAIL
-org.freedesktop.DBus.Error.NotSupported,                  ENOTSUP
-org.freedesktop.DBus.Error.LimitsExceeded,                ENOBUFS
-org.freedesktop.DBus.Error.AccessDenied,                  EACCES
-org.freedesktop.DBus.Error.AuthFailed,                    EACCES
-org.freedesktop.DBus.Error.NoServer,                      EHOSTDOWN
-org.freedesktop.DBus.Error.Timeout,                       ETIMEDOUT
-org.freedesktop.DBus.Error.NoNetwork,                     ENONET
-org.freedesktop.DBus.Error.AddressInUse,                  EADDRINUSE
-org.freedesktop.DBus.Error.Disconnected,                  ECONNRESET
-org.freedesktop.DBus.Error.InvalidArgs,                   EINVAL
-org.freedesktop.DBus.Error.FileNotFound,                  ENOENT
-org.freedesktop.DBus.Error.FileExists,                    EEXIST
-org.freedesktop.DBus.Error.UnknownMethod,                 EBADR
-org.freedesktop.DBus.Error.UnknownObject,                 EBADR
-org.freedesktop.DBus.Error.UnknownInterface,              EBADR
-org.freedesktop.DBus.Error.UnknownProperty,               EBADR
-org.freedesktop.DBus.Error.PropertyReadOnly,              EROFS
-org.freedesktop.DBus.Error.UnixProcessIdUnknown,          ESRCH
-org.freedesktop.DBus.Error.InvalidSignature,              EINVAL
-org.freedesktop.DBus.Error.InconsistentMessage,           EBADMSG
-#
-org.freedesktop.DBus.Error.TimedOut,                      ETIMEDOUT
-org.freedesktop.DBus.Error.MatchRuleInvalid,              EINVAL
-org.freedesktop.DBus.Error.InvalidFileContent,            EINVAL
-org.freedesktop.DBus.Error.MatchRuleNotFound,             ENOENT
-org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown, ESRCH
-org.freedesktop.DBus.Error.ObjectPathInUse,               EBUSY
diff --git a/src/libsystemd/bus-error.c b/src/libsystemd/bus-error.c
deleted file mode 100644
index c2e41fb..0000000
--- a/src/libsystemd/bus-error.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/*-*- 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 <errno.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "util.h"
-#include "errno-list.h"
-
-#include "sd-bus.h"
-#include "bus-error.h"
-
-#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
-#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
-
-static int bus_error_name_to_errno(const char *name) {
-        const char *p;
-        int r;
-        const name_error_mapping *m;
-
-        if (!name)
-                return EINVAL;
-
-        p = startswith(name, "System.Error.");
-        if (p) {
-                r = errno_from_name(p);
-                if (r <= 0)
-                        return EIO;
-
-                return r;
-        }
-
-        m = bus_error_mapping_lookup(name, strlen(name));
-        if (m)
-                return m->code;
-
-        return EIO;
-}
-
-static sd_bus_error errno_to_bus_error_const(int error) {
-
-        if (error < 0)
-                error = -error;
-
-        switch (error) {
-
-        case ENOMEM:
-                return BUS_ERROR_OOM;
-
-        case EPERM:
-        case EACCES:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
-
-        case EINVAL:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
-
-        case ESRCH:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
-
-        case ENOENT:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
-
-        case EEXIST:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
-
-        case ETIMEDOUT:
-        case ETIME:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
-
-        case EIO:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
-
-        case ENETRESET:
-        case ECONNABORTED:
-        case ECONNRESET:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
-
-        case ENOTSUP:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
-
-        case EADDRNOTAVAIL:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
-
-        case ENOBUFS:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
-
-        case EADDRINUSE:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
-
-        case EBADMSG:
-                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
-        }
-
-        return SD_BUS_ERROR_NULL;
-}
-
-static int errno_to_bus_error_name_new(int error, char **ret) {
-        const char *name;
-        char *n;
-
-        if (error < 0)
-                error = -error;
-
-        name = errno_to_name(error);
-        if (!name)
-                return 0;
-
-        n = strappend("System.Error.", name);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 1;
-}
-
-bool bus_error_is_dirty(sd_bus_error *e) {
-        if (!e)
-                return false;
-
-        return e->name || e->message || e->_need_free != 0;
-}
-
-_public_ void sd_bus_error_free(sd_bus_error *e) {
-        if (!e)
-                return;
-
-        if (e->_need_free > 0) {
-                free((void*) e->name);
-                free((void*) e->message);
-        }
-
-        e->name = e->message = NULL;
-        e->_need_free = 0;
-}
-
-_public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
-
-        if (!name)
-                return 0;
-        if (!e)
-                goto finish;
-
-        assert_return(!bus_error_is_dirty(e), -EINVAL);
-
-        e->name = strdup(name);
-        if (!e->name) {
-                *e = BUS_ERROR_OOM;
-                return -ENOMEM;
-        }
-
-        if (message)
-                e->message = strdup(message);
-
-        e->_need_free = 1;
-
-finish:
-        return -bus_error_name_to_errno(name);
-}
-
-int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
-
-        if (!name)
-                return 0;
-        if (!e)
-                goto finish;
-
-        assert_return(!bus_error_is_dirty(e), -EINVAL);
-
-        e->name = strdup(name);
-        if (!e->name) {
-                *e = BUS_ERROR_OOM;
-                return -ENOMEM;
-        }
-
-        if (format)
-                vasprintf((char**) &e->message, format, ap);
-
-        e->_need_free = 1;
-
-finish:
-        return -bus_error_name_to_errno(name);
-}
-
-_public_ 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);
-}
-
-_public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
-
-        if (!sd_bus_error_is_set(e))
-                return 0;
-        if (!dest)
-                goto finish;
-
-        assert_return(!bus_error_is_dirty(dest), -EINVAL);
-
-        /*
-         * _need_free  < 0 indicates that the error is temporarily const, needs deep copying
-         * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
-         * _need_free  > 0 indicates that the error is fully dynamic, needs deep copying
-         */
-
-        if (e->_need_free == 0)
-                *dest = *e;
-        else {
-                dest->name = strdup(e->name);
-                if (!dest->name) {
-                        *dest = BUS_ERROR_OOM;
-                        return -ENOMEM;
-                }
-
-                if (e->message)
-                        dest->message = strdup(e->message);
-
-                dest->_need_free = 1;
-        }
-
-finish:
-        return -bus_error_name_to_errno(e->name);
-}
-
-_public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
-        if (!name)
-                return 0;
-        if (!e)
-                goto finish;
-
-        assert_return(!bus_error_is_dirty(e), -EINVAL);
-
-        *e = SD_BUS_ERROR_MAKE_CONST(name, message);
-
-finish:
-        return -bus_error_name_to_errno(name);
-}
-
-_public_ int sd_bus_error_is_set(const sd_bus_error *e) {
-        if (!e)
-                return 0;
-
-        return !!e->name;
-}
-
-_public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
-        if (!e)
-                return 0;
-
-        return streq_ptr(e->name, name);
-}
-
-_public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
-        if (!e)
-                return 0;
-
-        if (!e->name)
-                return 0;
-
-        return bus_error_name_to_errno(e->name);
-}
-
-static void bus_error_strerror(sd_bus_error *e, int error) {
-        size_t k = 64;
-        char *m;
-
-        assert(e);
-
-        for (;;) {
-                char *x;
-
-                m = new(char, k);
-                if (!m)
-                        return;
-
-                errno = 0;
-                x = strerror_r(error, m, k);
-                if (errno == ERANGE || strlen(x) >= k - 1) {
-                        free(m);
-                        k *= 2;
-                        continue;
-                }
-
-                if (!x || errno) {
-                        free(m);
-                        return;
-                }
-
-                if (x == m) {
-                        if (e->_need_free > 0) {
-                                /* Error is already dynamic, let's just update the message */
-                                free((char*) e->message);
-                                e->message = x;
-
-                        } else {
-                                char *t;
-                                /* Error was const so far, let's make it dynamic, if we can */
-
-                                t = strdup(e->name);
-                                if (!t) {
-                                        free(m);
-                                        return;
-                                }
-
-                                e->_need_free = 1;
-                                e->name = t;
-                                e->message = x;
-                        }
-                } else {
-                        free(m);
-
-                        if (e->_need_free > 0) {
-                                char *t;
-
-                                /* Error is dynamic, let's hence make the message also dynamic */
-                                t = strdup(x);
-                                if (!t)
-                                        return;
-
-                                free((char*) e->message);
-                                e->message = t;
-                        } else {
-                                /* Error is const, hence we can just override */
-                                e->message = x;
-                        }
-                }
-
-                return;
-        }
-}
-
-_public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
-
-        if (error < 0)
-                error = -error;
-
-        if (!e)
-                return -error;
-        if (error == 0)
-                return -error;
-
-        assert_return(!bus_error_is_dirty(e), -EINVAL);
-
-        /* First, try a const translation */
-        *e = errno_to_bus_error_const(error);
-
-        if (!sd_bus_error_is_set(e)) {
-                int k;
-
-                /* If that didn't work, try a dynamic one. */
-
-                k = errno_to_bus_error_name_new(error, (char**) &e->name);
-                if (k > 0)
-                        e->_need_free = 1;
-                else if (k < 0) {
-                        *e = BUS_ERROR_OOM;
-                        return -error;
-                } else
-                        *e = BUS_ERROR_FAILED;
-        }
-
-        /* Now, fill in the message from strerror() if we can */
-        bus_error_strerror(e, error);
-        return -error;
-}
-
-int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
-        int r;
-
-        if (error < 0)
-                error = -error;
-
-        if (!e)
-                return -error;
-        if (error == 0)
-                return 0;
-
-        assert_return(!bus_error_is_dirty(e), -EINVAL);
-
-        /* First, try a const translation */
-        *e = errno_to_bus_error_const(error);
-
-        if (!sd_bus_error_is_set(e)) {
-                int k;
-
-                /* If that didn't work, try a dynamic one */
-
-                k = errno_to_bus_error_name_new(error, (char**) &e->name);
-                if (k > 0)
-                        e->_need_free = 1;
-                else if (k < 0) {
-                        *e = BUS_ERROR_OOM;
-                        return -ENOMEM;
-                } else
-                        *e = BUS_ERROR_FAILED;
-        }
-
-        if (format) {
-                char *m;
-
-                /* First, let's try to fill in the supplied message */
-
-                r = vasprintf(&m, format, ap);
-                if (r >= 0) {
-
-                        if (e->_need_free <= 0) {
-                                char *t;
-
-                                t = strdup(e->name);
-                                if (t) {
-                                        e->_need_free = 1;
-                                        e->name = t;
-                                        e->message = m;
-                                        return -error;
-                                }
-
-                                free(m);
-                        } else {
-                                free((char*) e->message);
-                                e->message = m;
-                                return -error;
-                        }
-                }
-        }
-
-        /* If that didn't work, use strerror() for the message */
-        bus_error_strerror(e, error);
-        return -error;
-}
-
-_public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
-        int r;
-
-        if (error < 0)
-                error = -error;
-
-        if (!e)
-                return -error;
-        if (error == 0)
-                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 (e) {
-                /* Sometimes the D-Bus server is a little bit too verbose with
-                 * its error messages, so let's override them here */
-                if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
-                        return "Access denied";
-
-                if (e->message)
-                        return e->message;
-        }
-
-        if (error < 0)
-                error = -error;
-
-        return strerror(error);
-}
diff --git a/src/libsystemd/bus-error.h b/src/libsystemd/bus-error.h
deleted file mode 100644
index cf0ad9d..0000000
--- a/src/libsystemd/bus-error.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-*- 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 <stdbool.h>
-
-#include "sd-bus.h"
-#include "macro.h"
-
-struct name_error_mapping {
-        const char* name;
-        int code;
-};
-typedef struct name_error_mapping name_error_mapping;
-
-const name_error_mapping* bus_error_mapping_lookup(const char *str, unsigned int len);
-
-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) _printf_(3,0);
-int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) _printf_(3,0);
diff --git a/src/libsystemd/bus-gvariant.c b/src/libsystemd/bus-gvariant.c
deleted file mode 100644
index dc40009..0000000
--- a/src/libsystemd/bus-gvariant.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*-*- 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 "util.h"
-#include "bus-type.h"
-#include "bus-gvariant.h"
-#include "bus-signature.h"
-
-int bus_gvariant_get_size(const char *signature) {
-        const char *p;
-        int sum = 0, r;
-
-        /* For fixed size structs. Fails for variable size structs. */
-
-        p = signature;
-        while (*p != 0) {
-                size_t n;
-
-                r = signature_element_length(p, &n);
-                if (r < 0)
-                        return r;
-                else {
-                        char t[n+1];
-
-                        memcpy(t, p, n);
-                        t[n] = 0;
-
-                        r = bus_gvariant_get_alignment(t);
-                        if (r < 0)
-                                return r;
-
-                        sum = ALIGN_TO(sum, r);
-                }
-
-                switch (*p) {
-
-                case SD_BUS_TYPE_BOOLEAN:
-                case SD_BUS_TYPE_BYTE:
-                        sum += 1;
-                        break;
-
-                case SD_BUS_TYPE_INT16:
-                case SD_BUS_TYPE_UINT16:
-                        sum += 2;
-                        break;
-
-                case SD_BUS_TYPE_INT32:
-                case SD_BUS_TYPE_UINT32:
-                case SD_BUS_TYPE_UNIX_FD:
-                        sum += 4;
-                        break;
-
-                case SD_BUS_TYPE_INT64:
-                case SD_BUS_TYPE_UINT64:
-                case SD_BUS_TYPE_DOUBLE:
-                        sum += 8;
-                        break;
-
-                case SD_BUS_TYPE_STRUCT_BEGIN:
-                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
-                        char t[n-1];
-
-                        memcpy(t, p + 1, n - 2);
-                        t[n - 2] = 0;
-
-                        r = bus_gvariant_get_size(t);
-                        if (r < 0)
-                                return r;
-
-                        sum += r;
-                        break;
-                }
-
-                case SD_BUS_TYPE_STRING:
-                case SD_BUS_TYPE_OBJECT_PATH:
-                case SD_BUS_TYPE_SIGNATURE:
-                case SD_BUS_TYPE_ARRAY:
-                case SD_BUS_TYPE_VARIANT:
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached("Unknown signature type");
-                }
-
-                p += n;
-        }
-
-        r = bus_gvariant_get_alignment(signature);
-        if (r < 0)
-                return r;
-
-        return ALIGN_TO(sum, r);
-}
-
-int bus_gvariant_get_alignment(const char *signature) {
-        size_t alignment = 1;
-        const char *p;
-        int r;
-
-        p = signature;
-        while (*p != 0 && alignment < 8) {
-                size_t n;
-                int a;
-
-                r = signature_element_length(p, &n);
-                if (r < 0)
-                        return r;
-
-                switch (*p) {
-
-                case SD_BUS_TYPE_BYTE:
-                case SD_BUS_TYPE_BOOLEAN:
-                case SD_BUS_TYPE_STRING:
-                case SD_BUS_TYPE_OBJECT_PATH:
-                case SD_BUS_TYPE_SIGNATURE:
-                        a = 1;
-                        break;
-
-                case SD_BUS_TYPE_INT16:
-                case SD_BUS_TYPE_UINT16:
-                        a = 2;
-                        break;
-
-                case SD_BUS_TYPE_INT32:
-                case SD_BUS_TYPE_UINT32:
-                case SD_BUS_TYPE_UNIX_FD:
-                        a = 4;
-                        break;
-
-                case SD_BUS_TYPE_INT64:
-                case SD_BUS_TYPE_UINT64:
-                case SD_BUS_TYPE_DOUBLE:
-                case SD_BUS_TYPE_VARIANT:
-                        a = 8;
-                        break;
-
-                case SD_BUS_TYPE_ARRAY: {
-                        char t[n];
-
-                        memcpy(t, p + 1, n - 1);
-                        t[n - 1] = 0;
-
-                        a = bus_gvariant_get_alignment(t);
-                        break;
-                }
-
-                case SD_BUS_TYPE_STRUCT_BEGIN:
-                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
-                        char t[n-1];
-
-                        memcpy(t, p + 1, n - 2);
-                        t[n - 2] = 0;
-
-                        a = bus_gvariant_get_alignment(t);
-                        break;
-                }
-
-                default:
-                        assert_not_reached("Unknown signature type");
-                }
-
-                if (a < 0)
-                        return a;
-
-                assert(a > 0 && a <= 8);
-                if ((size_t) a > alignment)
-                        alignment = (size_t) a;
-
-                p += n;
-        }
-
-        return alignment;
-}
-
-int bus_gvariant_is_fixed_size(const char *signature) {
-        const char *p;
-        int r;
-
-        assert(signature);
-
-        p = signature;
-        while (*p != 0) {
-                size_t n;
-
-                r = signature_element_length(p, &n);
-                if (r < 0)
-                        return r;
-
-                switch (*p) {
-
-                case SD_BUS_TYPE_STRING:
-                case SD_BUS_TYPE_OBJECT_PATH:
-                case SD_BUS_TYPE_SIGNATURE:
-                case SD_BUS_TYPE_ARRAY:
-                case SD_BUS_TYPE_VARIANT:
-                        return 0;
-
-                case SD_BUS_TYPE_BYTE:
-                case SD_BUS_TYPE_BOOLEAN:
-                case SD_BUS_TYPE_INT16:
-                case SD_BUS_TYPE_UINT16:
-                case SD_BUS_TYPE_INT32:
-                case SD_BUS_TYPE_UINT32:
-                case SD_BUS_TYPE_UNIX_FD:
-                case SD_BUS_TYPE_INT64:
-                case SD_BUS_TYPE_UINT64:
-                case SD_BUS_TYPE_DOUBLE:
-                        break;
-
-                case SD_BUS_TYPE_STRUCT_BEGIN:
-                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
-                        char t[n-1];
-
-                        memcpy(t, p + 1, n - 2);
-                        t[n - 2] = 0;
-
-                        r = bus_gvariant_is_fixed_size(t);
-                        if (r <= 0)
-                                return r;
-                        break;
-                }
-
-                default:
-                        assert_not_reached("Unknown signature type");
-                }
-
-                p += n;
-        }
-
-        return true;
-}
diff --git a/src/libsystemd/bus-gvariant.h b/src/libsystemd/bus-gvariant.h
deleted file mode 100644
index b4bd2a5..0000000
--- a/src/libsystemd/bus-gvariant.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- 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/>.
-***/
-
-int bus_gvariant_get_size(const char *signature) _pure_;
-int bus_gvariant_get_alignment(const char *signature) _pure_;
-int bus_gvariant_is_fixed_size(const char *signature) _pure_;
diff --git a/src/libsystemd/bus-internal.c b/src/libsystemd/bus-internal.c
deleted file mode 100644
index 0bea8ca..0000000
--- a/src/libsystemd/bus-internal.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*-*- 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 "bus-internal.h"
-
-bool object_path_is_valid(const char *p) {
-        const char *q;
-        bool slash;
-
-        if (!p)
-                return false;
-
-        if (p[0] != '/')
-                return false;
-
-        if (p[1] == 0)
-                return true;
-
-        for (slash = true, q = p+1; *q; q++)
-                if (*q == '/') {
-                        if (slash)
-                                return false;
-
-                        slash = true;
-                } else {
-                        bool good;
-
-                        good =
-                                (*q >= 'a' && *q <= 'z') ||
-                                (*q >= 'A' && *q <= 'Z') ||
-                                (*q >= '0' && *q <= '9') ||
-                                *q == '_';
-
-                        if (!good)
-                                return false;
-
-                        slash = false;
-                }
-
-        if (slash)
-                return false;
-
-        return true;
-}
-
-char* object_path_startswith(const char *a, const char *b) {
-        const char *p;
-
-        if (!object_path_is_valid(a) ||
-            !object_path_is_valid(b))
-                return NULL;
-
-        if (streq(b, "/"))
-                return (char*) a + 1;
-
-        p = startswith(a, b);
-        if (!p)
-                return NULL;
-
-        if (*p == 0)
-                return (char*) p;
-
-        if (*p == '/')
-                return (char*) p + 1;
-
-        return NULL;
-}
-
-bool interface_name_is_valid(const char *p) {
-        const char *q;
-        bool dot, found_dot = false;
-
-        if (isempty(p))
-                return false;
-
-        for (dot = true, q = p; *q; q++)
-                if (*q == '.') {
-                        if (dot)
-                                return false;
-
-                        found_dot = dot = true;
-                } else {
-                        bool good;
-
-                        good =
-                                (*q >= 'a' && *q <= 'z') ||
-                                (*q >= 'A' && *q <= 'Z') ||
-                                (!dot && *q >= '0' && *q <= '9') ||
-                                *q == '_';
-
-                        if (!good)
-                                return false;
-
-                        dot = false;
-                }
-
-        if (q - p > 255)
-                return false;
-
-        if (dot)
-                return false;
-
-        if (!found_dot)
-                return false;
-
-        return true;
-}
-
-bool service_name_is_valid(const char *p) {
-        const char *q;
-        bool dot, found_dot = false, unique;
-
-        if (isempty(p))
-                return false;
-
-        unique = p[0] == ':';
-
-        for (dot = true, q = unique ? p+1 : p; *q; q++)
-                if (*q == '.') {
-                        if (dot)
-                                return false;
-
-                        found_dot = dot = true;
-                } else {
-                        bool good;
-
-                        good =
-                                (*q >= 'a' && *q <= 'z') ||
-                                (*q >= 'A' && *q <= 'Z') ||
-                                ((!dot || unique) && *q >= '0' && *q <= '9') ||
-                                *q == '_' || *q == '-';
-
-                        if (!good)
-                                return false;
-
-                        dot = false;
-                }
-
-        if (q - p > 255)
-                return false;
-
-        if (dot)
-                return false;
-
-        if (!found_dot)
-                return false;
-
-        return true;
-}
-
-bool member_name_is_valid(const char *p) {
-        const char *q;
-
-        if (isempty(p))
-                return false;
-
-        for (q = p; *q; q++) {
-                bool good;
-
-                good =
-                        (*q >= 'a' && *q <= 'z') ||
-                        (*q >= 'A' && *q <= 'Z') ||
-                        (*q >= '0' && *q <= '9') ||
-                        *q == '_';
-
-                if (!good)
-                        return false;
-        }
-
-        if (q - p > 255)
-                return false;
-
-        return true;
-}
-
-static bool complex_pattern_check(char c, const char *a, const char *b) {
-        bool separator = false;
-
-        if (!a && !b)
-                return true;
-
-        if (!a || !b)
-                return false;
-
-        for (;;) {
-                if (*a != *b)
-                        return (separator && (*a == 0 || *b == 0)) ||
-                                (*a == 0 && *b == c && b[1] == 0) ||
-                                (*b == 0 && *a == c && a[1] == 0);
-
-                if (*a == 0)
-                        return true;
-
-                separator = *a == c;
-
-                a++, b++;
-        }
-}
-
-bool namespace_complex_pattern(const char *pattern, const char *value) {
-        return complex_pattern_check('.', pattern, value);
-}
-
-bool path_complex_pattern(const char *pattern, const char *value) {
-        return complex_pattern_check('/', pattern, value);
-}
-
-static bool simple_pattern_check(char c, const char *a, const char *b) {
-
-        if (!a && !b)
-                return true;
-
-        if (!a || !b)
-                return false;
-
-        for (;;) {
-                if (*a != *b)
-                        return *a == 0 && *b == c;
-
-                if (*a == 0)
-                        return true;
-
-                a++, b++;
-        }
-}
-
-bool namespace_simple_pattern(const char *pattern, const char *value) {
-        return simple_pattern_check('.', pattern, value);
-}
-
-bool path_simple_pattern(const char *pattern, const char *value) {
-        return simple_pattern_check('/', pattern, value);
-}
-
-int bus_message_type_from_string(const char *s, uint8_t *u) {
-        if (streq(s, "signal"))
-                *u = SD_BUS_MESSAGE_SIGNAL;
-        else if (streq(s, "method_call"))
-                *u = SD_BUS_MESSAGE_METHOD_CALL;
-        else if (streq(s, "error"))
-                *u = SD_BUS_MESSAGE_METHOD_ERROR;
-        else if (streq(s, "method_return"))
-                *u = SD_BUS_MESSAGE_METHOD_RETURN;
-        else
-                return -EINVAL;
-
-        return 0;
-}
-
-const char *bus_message_type_to_string(uint8_t u) {
-        if (u == SD_BUS_MESSAGE_SIGNAL)
-                return "signal";
-        else if (u == SD_BUS_MESSAGE_METHOD_CALL)
-                return "method_call";
-        else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
-                return "error";
-        else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
-                 return "method_return";
-        else
-                return NULL;
-}
-
-char *bus_address_escape(const char *v) {
-        const char *a;
-        char *r, *b;
-
-        r = new(char, strlen(v)*3+1);
-        if (!r)
-                return NULL;
-
-        for (a = v, b = r; *a; a++) {
-
-                if ((*a >= '0' && *a <= '9') ||
-                    (*a >= 'a' && *a <= 'z') ||
-                    (*a >= 'A' && *a <= 'Z') ||
-                    strchr("_-/.", *a))
-                        *(b++) = *a;
-                else {
-                        *(b++) = '%';
-                        *(b++) = hexchar(*a >> 4);
-                        *(b++) = hexchar(*a & 0xF);
-                }
-        }
-
-        *b = 0;
-        return r;
-}
diff --git a/src/libsystemd/bus-internal.h b/src/libsystemd/bus-internal.h
deleted file mode 100644
index 7c92293..0000000
--- a/src/libsystemd/bus-internal.h
+++ /dev/null
@@ -1,328 +0,0 @@
-/*-*- 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 <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <pthread.h>
-
-#include "hashmap.h"
-#include "prioq.h"
-#include "list.h"
-#include "util.h"
-#include "refcnt.h"
-
-#include "sd-bus.h"
-#include "bus-error.h"
-#include "bus-match.h"
-#include "bus-kernel.h"
-#include "kdbus.h"
-
-struct reply_callback {
-        sd_bus_message_handler_t callback;
-        void *userdata;
-        usec_t timeout;
-        uint64_t cookie;
-        unsigned prioq_idx;
-};
-
-struct filter_callback {
-        sd_bus_message_handler_t callback;
-        void *userdata;
-
-        unsigned last_iteration;
-
-        LIST_FIELDS(struct filter_callback, callbacks);
-};
-
-struct node {
-        char *path;
-        struct node *parent;
-        LIST_HEAD(struct node, child);
-        LIST_FIELDS(struct node, siblings);
-
-        LIST_HEAD(struct node_callback, callbacks);
-        LIST_HEAD(struct node_vtable, vtables);
-        LIST_HEAD(struct node_enumerator, enumerators);
-
-        bool object_manager;
-};
-
-struct node_callback {
-        struct node *node;
-
-        bool is_fallback;
-        sd_bus_message_handler_t callback;
-        void *userdata;
-
-        unsigned last_iteration;
-
-        LIST_FIELDS(struct node_callback, callbacks);
-};
-
-struct node_enumerator {
-        struct node *node;
-
-        sd_bus_node_enumerator_t callback;
-        void *userdata;
-
-        unsigned last_iteration;
-
-        LIST_FIELDS(struct node_enumerator, enumerators);
-};
-
-struct node_vtable {
-        struct node *node;
-
-        char *interface;
-        bool is_fallback;
-        const sd_bus_vtable *vtable;
-        void *userdata;
-        sd_bus_object_find_t find;
-
-        unsigned last_iteration;
-
-        LIST_FIELDS(struct node_vtable, vtables);
-};
-
-struct vtable_member {
-        const char *path;
-        const char *interface;
-        const char *member;
-        struct node_vtable *parent;
-        unsigned last_iteration;
-        const sd_bus_vtable *vtable;
-};
-
-enum bus_state {
-        BUS_UNSET,
-        BUS_OPENING,
-        BUS_AUTHENTICATING,
-        BUS_HELLO,
-        BUS_RUNNING,
-        BUS_CLOSING,
-        BUS_CLOSED
-};
-
-static inline bool BUS_IS_OPEN(enum bus_state state) {
-        return state > BUS_UNSET && state < BUS_CLOSING;
-}
-
-enum bus_auth {
-        _BUS_AUTH_INVALID,
-        BUS_AUTH_EXTERNAL,
-        BUS_AUTH_ANONYMOUS
-};
-
-struct sd_bus {
-        /* We use atomic ref counting here since sd_bus_message
-           objects retain references to their originating sd_bus but
-           we want to allow them to be processed in a different
-           thread. We won't provide full thread safety, but only the
-           bare minimum that makes it possible to use sd_bus and
-           sd_bus_message objects independently and on different
-           threads as long as each object is used only once at the
-           same time. */
-        RefCount n_ref;
-
-        enum bus_state state;
-        int input_fd, output_fd;
-        int message_version;
-        int message_endian;
-
-        bool is_kernel:1;
-        bool can_fds:1;
-        bool bus_client:1;
-        bool ucred_valid:1;
-        bool is_server:1;
-        bool anonymous_auth:1;
-        bool prefer_readv:1;
-        bool prefer_writev:1;
-        bool match_callbacks_modified:1;
-        bool filter_callbacks_modified:1;
-        bool nodes_modified:1;
-        bool trusted:1;
-        bool fake_creds_valid:1;
-        bool manual_peer_interface:1;
-
-        int use_memfd;
-
-        void *rbuffer;
-        size_t rbuffer_size;
-
-        sd_bus_message **rqueue;
-        unsigned rqueue_size;
-        size_t rqueue_allocated;
-
-        sd_bus_message **wqueue;
-        unsigned wqueue_size;
-        size_t windex;
-        size_t wqueue_allocated;
-
-        uint64_t cookie;
-
-        char *unique_name;
-        uint64_t unique_id;
-
-        struct bus_match_node match_callbacks;
-        Prioq *reply_callbacks_prioq;
-        Hashmap *reply_callbacks;
-        LIST_HEAD(struct filter_callback, filter_callbacks);
-
-        Hashmap *nodes;
-        Hashmap *vtable_methods;
-        Hashmap *vtable_properties;
-
-        union {
-                struct sockaddr sa;
-                struct sockaddr_un un;
-                struct sockaddr_in in;
-                struct sockaddr_in6 in6;
-        } sockaddr;
-        socklen_t sockaddr_size;
-
-        char *kernel;
-        char *machine;
-
-        sd_id128_t server_id;
-
-        char *address;
-        unsigned address_index;
-
-        int last_connect_error;
-
-        enum bus_auth auth;
-        size_t auth_rbegin;
-        struct iovec auth_iovec[3];
-        unsigned auth_index;
-        char *auth_buffer;
-        usec_t auth_timeout;
-
-        struct ucred ucred;
-        char label[NAME_MAX];
-
-        uint64_t creds_mask;
-
-        int *fds;
-        unsigned n_fds;
-
-        char *exec_path;
-        char **exec_argv;
-
-        uint64_t hello_cookie;
-        unsigned iteration_counter;
-
-        void *kdbus_buffer;
-
-        /* We do locking around the memfd cache, since we want to
-         * allow people to process a sd_bus_message in a different
-         * thread then it was generated on and free it there. Since
-         * adding something to the memfd cache might happen when a
-         * message is released, we hence need to protect this bit with
-         * a mutex. */
-        pthread_mutex_t memfd_cache_mutex;
-        struct memfd_cache memfd_cache[MEMFD_CACHE_MAX];
-        unsigned n_memfd_cache;
-
-        pid_t original_pid;
-
-        uint64_t hello_flags;
-        uint64_t attach_flags;
-
-        uint64_t match_cookie;
-
-        sd_event_source *input_io_event_source;
-        sd_event_source *output_io_event_source;
-        sd_event_source *time_event_source;
-        sd_event_source *quit_event_source;
-        sd_event *event;
-        int event_priority;
-
-        sd_bus_message *current;
-
-        sd_bus **default_bus_ptr;
-        pid_t tid;
-
-        struct kdbus_creds fake_creds;
-        char *fake_label;
-
-        char *cgroup_root;
-};
-
-#define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
-
-#define BUS_WQUEUE_MAX 1024
-#define BUS_RQUEUE_MAX 64*1024
-
-#define BUS_MESSAGE_SIZE_MAX (64*1024*1024)
-#define BUS_AUTH_SIZE_MAX (64*1024)
-
-#define BUS_CONTAINER_DEPTH 128
-
-/* Defined by the specification as maximum size of an array in
- * bytes */
-#define BUS_ARRAY_MAX_SIZE 67108864
-
-#define BUS_FDS_MAX 1024
-
-#define BUS_EXEC_ARGV_MAX 256
-
-bool interface_name_is_valid(const char *p) _pure_;
-bool service_name_is_valid(const char *p) _pure_;
-bool member_name_is_valid(const char *p) _pure_;
-bool object_path_is_valid(const char *p) _pure_;
-char *object_path_startswith(const char *a, const char *b) _pure_;
-
-bool namespace_complex_pattern(const char *pattern, const char *value) _pure_;
-bool path_complex_pattern(const char *pattern, const char *value) _pure_;
-
-bool namespace_simple_pattern(const char *pattern, const char *value) _pure_;
-bool path_simple_pattern(const char *pattern, const char *value) _pure_;
-
-int bus_message_type_from_string(const char *s, uint8_t *u) _pure_;
-const char *bus_message_type_to_string(uint8_t u) _pure_;
-
-#define error_name_is_valid interface_name_is_valid
-
-int bus_ensure_running(sd_bus *bus);
-int bus_start_running(sd_bus *bus);
-int bus_next_address(sd_bus *bus);
-
-int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m);
-
-int bus_rqueue_make_room(sd_bus *bus);
-
-bool bus_pid_changed(sd_bus *bus);
-
-char *bus_address_escape(const char *v);
-
-#define OBJECT_PATH_FOREACH_PREFIX(prefix, path)                        \
-        for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \
-             _slash && !(_slash[(_slash) == (prefix)] = 0);             \
-             _slash = streq((prefix), "/") ? NULL : strrchr((prefix), '/'))
-
-/* If we are invoking callbacks of a bus object, ensure unreffing the
- * bus from the callback doesn't destroy the object we are working
- * on */
-#define BUS_DONT_DESTROY(bus) \
-        _cleanup_bus_unref_ _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus)
diff --git a/src/libsystemd/bus-introspect.c b/src/libsystemd/bus-introspect.c
deleted file mode 100644
index d528ab2..0000000
--- a/src/libsystemd/bus-introspect.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*-*- 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 "util.h"
-#include "sd-bus-protocol.h"
-#include "bus-introspect.h"
-#include "bus-signature.h"
-#include "bus-internal.h"
-#include "bus-protocol.h"
-
-int introspect_begin(struct introspect *i, bool trusted) {
-        assert(i);
-
-        zero(*i);
-        i->trusted = trusted;
-
-        i->f = open_memstream(&i->introspection, &i->size);
-        if (!i->f)
-                return -ENOMEM;
-
-        fputs(BUS_INTROSPECT_DOCTYPE
-              "<node>\n", i->f);
-
-        return 0;
-}
-
-int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
-        assert(i);
-
-        fputs(BUS_INTROSPECT_INTERFACE_PEER
-              BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
-              BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
-
-        if (object_manager)
-                fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
-
-        return 0;
-}
-
-int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
-        char *node;
-
-        assert(i);
-        assert(prefix);
-
-        while ((node = set_steal_first(s))) {
-                const char *e;
-
-                e = object_path_startswith(node, prefix);
-                if (e && e[0])
-                        fprintf(i->f, " <node name=\"%s\"/>\n", e);
-
-                free(node);
-        }
-
-        return 0;
-}
-
-static void introspect_write_flags(struct introspect *i, int type, int flags) {
-        if (flags & SD_BUS_VTABLE_DEPRECATED)
-                fputs("   <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
-
-        if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
-                fputs("   <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
-
-        if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
-                if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
-                        fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
-                else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
-                        fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
-                else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
-                        fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
-        }
-
-        if (!i->trusted &&
-            (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
-            !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
-                fputs("   <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
-}
-
-static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
-        int r;
-
-        for (;;) {
-                size_t l;
-
-                if (!*signature)
-                        return 0;
-
-                r = signature_element_length(signature, &l);
-                if (r < 0)
-                        return r;
-
-                fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
-
-                if (direction)
-                        fprintf(i->f, " direction=\"%s\"/>\n", direction);
-                else
-                        fputs("/>\n", i->f);
-
-                signature += l;
-        }
-}
-
-int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
-        assert(i);
-        assert(v);
-
-        for (; v->type != _SD_BUS_VTABLE_END; v++) {
-
-                /* Ignore methods, signals and properties that are
-                 * marked "hidden", but do show the interface
-                 * itself */
-
-                if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
-                        continue;
-
-                switch (v->type) {
-
-                case _SD_BUS_VTABLE_START:
-                        if (v->flags & SD_BUS_VTABLE_DEPRECATED)
-                                fputs("  <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
-                        break;
-
-                case _SD_BUS_VTABLE_METHOD:
-                        fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
-                        introspect_write_arguments(i, strempty(v->x.method.signature), "in");
-                        introspect_write_arguments(i, strempty(v->x.method.result), "out");
-                        introspect_write_flags(i, v->type, v->flags);
-                        fputs("  </method>\n", i->f);
-                        break;
-
-                case _SD_BUS_VTABLE_PROPERTY:
-                case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
-                        fprintf(i->f, "  <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
-                                v->x.property.member,
-                                v->x.property.signature,
-                                v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
-                        introspect_write_flags(i, v->type, v->flags);
-                        fputs("  </property>\n", i->f);
-                        break;
-
-                case _SD_BUS_VTABLE_SIGNAL:
-                        fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
-                        introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
-                        introspect_write_flags(i, v->type, v->flags);
-                        fputs("  </signal>\n", i->f);
-                        break;
-                }
-
-        }
-
-        return 0;
-}
-
-int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
-        sd_bus_message *q;
-        int r;
-
-        assert(i);
-        assert(m);
-        assert(reply);
-
-        fputs("</node>\n", i->f);
-        fflush(i->f);
-
-        if (ferror(i->f))
-                return -ENOMEM;
-
-        r = sd_bus_message_new_method_return(m, &q);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append(q, "s", i->introspection);
-        if (r < 0) {
-                sd_bus_message_unref(q);
-                return r;
-        }
-
-        *reply = q;
-        return 0;
-}
-
-void introspect_free(struct introspect *i) {
-        assert(i);
-
-        if (i->f)
-                fclose(i->f);
-
-        if (i->introspection)
-                free(i->introspection);
-
-        zero(*i);
-}
diff --git a/src/libsystemd/bus-introspect.h b/src/libsystemd/bus-introspect.h
deleted file mode 100644
index 98312d1..0000000
--- a/src/libsystemd/bus-introspect.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-*- 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 <sys/types.h>
-#include <stdio.h>
-
-#include "sd-bus.h"
-#include "set.h"
-
-struct introspect {
-        FILE *f;
-        char *introspection;
-        size_t size;
-        bool trusted;
-};
-
-int introspect_begin(struct introspect *i, bool trusted);
-int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
-int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
-int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
-int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
-void introspect_free(struct introspect *i);
diff --git a/src/libsystemd/bus-kernel.c b/src/libsystemd/bus-kernel.c
deleted file mode 100644
index f85b4d5..0000000
--- a/src/libsystemd/bus-kernel.c
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*-*- 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/>.
-***/
-
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
-
-#include <fcntl.h>
-#include <malloc.h>
-#include <sys/mman.h>
-
-#include "util.h"
-#include "strv.h"
-
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-kernel.h"
-#include "bus-bloom.h"
-#include "bus-util.h"
-#include "cgroup-util.h"
-
-#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
-
-int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
-        int r;
-
-        assert(s);
-        assert(id);
-
-        if (!startswith(s, ":1."))
-                return 0;
-
-        r = safe_atou64(s + 3, id);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
-        assert(d);
-        assert(sz > 0);
-
-        *d = ALIGN8_PTR(*d);
-
-        /* Note that p can be NULL, which encodes a region full of
-         * zeroes, which is useful to optimize certain padding
-         * conditions */
-
-        (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
-        (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
-        (*d)->vec.address = PTR_TO_UINT64(p);
-        (*d)->vec.size = sz;
-
-        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
-}
-
-static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
-        assert(d);
-        assert(memfd >= 0);
-        assert(sz > 0);
-
-        *d = ALIGN8_PTR(*d);
-        (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
-        (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
-        (*d)->memfd.fd = memfd;
-        (*d)->memfd.size = sz;
-
-        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
-}
-
-static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
-        assert(d);
-        assert(s);
-
-        *d = ALIGN8_PTR(*d);
-
-        (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
-        (*d)->type = KDBUS_ITEM_DST_NAME;
-        memcpy((*d)->str, s, length + 1);
-
-        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
-}
-
-static void* append_bloom(struct kdbus_item **d, size_t length) {
-        void *r;
-
-        assert(d);
-
-        *d = ALIGN8_PTR(*d);
-
-        (*d)->size = offsetof(struct kdbus_item, data) + length;
-        (*d)->type = KDBUS_ITEM_BLOOM;
-        r = (*d)->data;
-
-        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
-
-        return r;
-}
-
-static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
-        assert(d);
-        assert(fds);
-        assert(n_fds > 0);
-
-        *d = ALIGN8_PTR(*d);
-        (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
-        (*d)->type = KDBUS_ITEM_FDS;
-        memcpy((*d)->fds, fds, sizeof(int) * n_fds);
-
-        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
-}
-
-static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
-        unsigned i;
-        int r;
-
-        assert(m);
-        assert(bloom);
-
-        memset(bloom, 0, BLOOM_SIZE);
-
-        bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
-
-        if (m->interface)
-                bloom_add_pair(bloom, "interface", m->interface);
-        if (m->member)
-                bloom_add_pair(bloom, "member", m->member);
-        if (m->path) {
-                bloom_add_pair(bloom, "path", m->path);
-                bloom_add_pair(bloom, "path-slash-prefix", m->path);
-                bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
-        }
-
-        r = sd_bus_message_rewind(m, true);
-        if (r < 0)
-                return r;
-
-        for (i = 0; i < 64; i++) {
-                char type;
-                const char *t;
-                char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
-                char *e;
-
-                r = sd_bus_message_peek_type(m, &type, NULL);
-                if (r < 0)
-                        return r;
-
-                if (type != SD_BUS_TYPE_STRING &&
-                    type != SD_BUS_TYPE_OBJECT_PATH &&
-                    type != SD_BUS_TYPE_SIGNATURE)
-                        break;
-
-                r = sd_bus_message_read_basic(m, type, &t);
-                if (r < 0)
-                        return r;
-
-                e = stpcpy(buf, "arg");
-                if (i < 10)
-                        *(e++) = '0' + (char) i;
-                else {
-                        *(e++) = '0' + (char) (i / 10);
-                        *(e++) = '0' + (char) (i % 10);
-                }
-
-                *e = 0;
-                bloom_add_pair(bloom, buf, t);
-
-                strcpy(e, "-dot-prefix");
-                bloom_add_prefixes(bloom, buf, t, '.');
-                strcpy(e, "-slash-prefix");
-                bloom_add_prefixes(bloom, buf, t, '/');
-        }
-
-        return 0;
-}
-
-static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
-        struct bus_body_part *part;
-        struct kdbus_item *d;
-        bool well_known;
-        uint64_t unique;
-        size_t sz, dl;
-        unsigned i;
-        int r;
-
-        assert(b);
-        assert(m);
-        assert(m->sealed);
-
-        if (m->kdbus)
-                return 0;
-
-        if (m->destination) {
-                r = bus_kernel_parse_unique_name(m->destination, &unique);
-                if (r < 0)
-                        return r;
-
-                well_known = r == 0;
-        } else
-                well_known = false;
-
-        sz = offsetof(struct kdbus_msg, items);
-
-        assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
-                  ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
-
-        /* Add in fixed header, fields header and payload */
-        sz += (1 + m->n_body_parts) *
-                ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
-
-        /* Add space for bloom filter */
-        sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
-
-        /* Add in well-known destination header */
-        if (well_known) {
-                dl = strlen(m->destination);
-                sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
-        }
-
-        /* Add space for unix fds */
-        if (m->n_fds > 0)
-                sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
-
-        m->kdbus = memalign(8, sz);
-        if (!m->kdbus) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        m->free_kdbus = true;
-        memset(m->kdbus, 0, sz);
-
-        m->kdbus->flags =
-                ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
-                ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
-        m->kdbus->dst_id =
-                well_known ? 0 :
-                m->destination ? unique : KDBUS_DST_ID_BROADCAST;
-        m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
-        m->kdbus->cookie = m->header->serial;
-
-        if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
-                m->kdbus->cookie_reply = m->reply_cookie;
-        else
-                m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
-
-        d = m->kdbus->items;
-
-        if (well_known)
-                append_destination(&d, m->destination, dl);
-
-        append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
-
-        MESSAGE_FOREACH_PART(part, i, m) {
-                if (part->is_zero) {
-                        /* If this is padding then simply send a
-                         * vector with a NULL data pointer which the
-                         * kernel will just pass through. This is the
-                         * most efficient way to encode zeroes */
-
-                        append_payload_vec(&d, NULL, part->size);
-                        continue;
-                }
-
-                if (part->memfd >= 0 && part->sealed && m->destination) {
-                        /* Try to send a memfd, if the part is
-                         * sealed and this is not a broadcast. Since we can only  */
-
-                        append_payload_memfd(&d, part->memfd, part->size);
-                        continue;
-                }
-
-                /* Otherwise let's send a vector to the actual data,
-                 * for that we need to map it first. */
-                r = bus_body_part_map(part);
-                if (r < 0)
-                        goto fail;
-
-                append_payload_vec(&d, part->data, part->size);
-        }
-
-        if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
-                void *p;
-
-                p = append_bloom(&d, BLOOM_SIZE);
-                r = bus_message_setup_bloom(m, p);
-                if (r < 0)
-                        goto fail;
-        }
-
-        if (m->n_fds > 0)
-                append_fds(&d, m->fds, m->n_fds);
-
-        m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
-        assert(m->kdbus->size <= sz);
-
-        return 0;
-
-fail:
-        m->poisoned = true;
-        return r;
-}
-
-static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
-        sd_bus_message *m = NULL;
-        struct kdbus_item *d;
-        unsigned n_fds = 0;
-        _cleanup_free_ int *fds = NULL;
-        struct bus_header *h = NULL;
-        size_t total, n_bytes = 0, idx = 0;
-        const char *destination = NULL, *seclabel = NULL;
-        int r;
-
-        assert(bus);
-        assert(k);
-        assert(k->payload_type == KDBUS_PAYLOAD_DBUS);
-
-        KDBUS_ITEM_FOREACH(d, k, items) {
-                size_t l;
-
-                l = d->size - offsetof(struct kdbus_item, data);
-
-                switch (d->type) {
-
-                case KDBUS_ITEM_PAYLOAD_OFF:
-                        if (!h) {
-                                h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
-
-                                if (!bus_header_is_complete(h, d->vec.size))
-                                        return -EBADMSG;
-                        }
-
-                        n_bytes += d->vec.size;
-                        break;
-
-                case KDBUS_ITEM_PAYLOAD_MEMFD:
-                        if (!h)
-                                return -EBADMSG;
-
-                        n_bytes += d->memfd.size;
-                        break;
-
-                case KDBUS_ITEM_FDS: {
-                        int *f;
-                        unsigned j;
-
-                        j = l / sizeof(int);
-                        f = realloc(fds, sizeof(int) * (n_fds + j));
-                        if (!f)
-                                return -ENOMEM;
-
-                        fds = f;
-                        memcpy(fds + n_fds, d->fds, sizeof(int) * j);
-                        n_fds += j;
-                        break;
-                }
-
-                case KDBUS_ITEM_SECLABEL:
-                        seclabel = d->str;
-                        break;
-                }
-        }
-
-        if (!h)
-                return -EBADMSG;
-
-        r = bus_header_message_size(h, &total);
-        if (r < 0)
-                return r;
-
-        if (n_bytes != total)
-                return -EBADMSG;
-
-        /* on kdbus we only speak native endian gvariant, never dbus1
-         * marshalling or reverse endian */
-        if (h->version != 2 ||
-            h->endian != BUS_NATIVE_ENDIAN)
-                return -EPROTOTYPE;
-
-        r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
-        if (r < 0)
-                return r;
-
-        /* The well-known names list is different from the other
-        credentials. If we asked for it, but nothing is there, this
-        means that the list of well-known names is simply empty, not
-        that we lack any data */
-
-        m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
-
-        KDBUS_ITEM_FOREACH(d, k, items) {
-                size_t l;
-
-                l = d->size - offsetof(struct kdbus_item, data);
-
-                switch (d->type) {
-
-                case KDBUS_ITEM_PAYLOAD_OFF: {
-                        size_t begin_body;
-
-                        begin_body = BUS_MESSAGE_BODY_BEGIN(m);
-
-                        if (idx + d->vec.size > begin_body) {
-                                struct bus_body_part *part;
-
-                                /* Contains body material */
-
-                                part = message_append_part(m);
-                                if (!part) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                /* A -1 offset is NUL padding. */
-                                part->is_zero = d->vec.offset == ~0ULL;
-
-                                if (idx >= begin_body) {
-                                        if (!part->is_zero)
-                                                part->data = (uint8_t *)k + d->vec.offset;
-                                        part->size = d->vec.size;
-                                } else {
-                                        if (!part->is_zero)
-                                                part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
-                                        part->size = d->vec.size - (begin_body - idx);
-                                }
-
-                                part->sealed = true;
-                        }
-
-                        idx += d->vec.size;
-                        break;
-                }
-
-                case KDBUS_ITEM_PAYLOAD_MEMFD: {
-                        struct bus_body_part *part;
-
-                        if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
-                                r = -EBADMSG;
-                                goto fail;
-                        }
-
-                        part = message_append_part(m);
-                        if (!part) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        part->memfd = d->memfd.fd;
-                        part->size = d->memfd.size;
-                        part->sealed = true;
-
-                        idx += d->memfd.size;
-                        break;
-                }
-
-                case KDBUS_ITEM_CREDS:
-                        /* UID/GID/PID are always valid */
-                        m->creds.uid = (uid_t) d->creds.uid;
-                        m->creds.gid = (gid_t) d->creds.gid;
-                        m->creds.pid = (pid_t) d->creds.pid;
-                        m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
-
-                        /* The PID starttime/TID might be missing
-                         * however, when the data is faked by some
-                         * data bus proxy and it lacks that
-                         * information about the real client since
-                         * SO_PEERCRED is used for that */
-
-                        if (d->creds.starttime > 0) {
-                                m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
-                                m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
-                        }
-
-                        if (d->creds.tid > 0) {
-                                m->creds.tid = (pid_t) d->creds.tid;
-                                m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
-                        }
-                        break;
-
-                case KDBUS_ITEM_TIMESTAMP:
-                        m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
-                        m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
-                        break;
-
-                case KDBUS_ITEM_PID_COMM:
-                        m->creds.comm = d->str;
-                        m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
-                        break;
-
-                case KDBUS_ITEM_TID_COMM:
-                        m->creds.tid_comm = d->str;
-                        m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
-                        break;
-
-                case KDBUS_ITEM_EXE:
-                        m->creds.exe = d->str;
-                        m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
-                        break;
-
-                case KDBUS_ITEM_CMDLINE:
-                        m->creds.cmdline = d->str;
-                        m->creds.cmdline_size = l;
-                        m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
-                        break;
-
-                case KDBUS_ITEM_CGROUP:
-                        m->creds.cgroup = d->str;
-                        m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
-
-                        if (!bus->cgroup_root) {
-                                r = cg_get_root_path(&bus->cgroup_root);
-                                if (r < 0)
-                                        goto fail;
-                        }
-
-                        m->creds.cgroup_root = bus->cgroup_root;
-
-                        break;
-
-                case KDBUS_ITEM_AUDIT:
-                        m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
-                        m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
-                        m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
-                        break;
-
-                case KDBUS_ITEM_CAPS:
-                        m->creds.capability = d->data;
-                        m->creds.capability_size = l;
-                        m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
-                        break;
-
-                case KDBUS_ITEM_DST_NAME:
-                        if (!service_name_is_valid(d->str))
-                                return -EBADMSG;
-
-                        destination = d->str;
-                        break;
-
-                case KDBUS_ITEM_NAME:
-                        if (!service_name_is_valid(d->name.name))
-                                return -EBADMSG;
-
-                        r = strv_extend(&m->creds.well_known_names, d->name.name);
-                        if (r < 0)
-                                goto fail;
-                        break;
-
-                case KDBUS_ITEM_FDS:
-                case KDBUS_ITEM_SECLABEL:
-                        break;
-
-                default:
-                        log_debug("Got unknown field from kernel %llu", d->type);
-                }
-        }
-
-        r = bus_message_parse_fields(m);
-        if (r < 0)
-                goto fail;
-
-        /* Override information from the user header with data from the kernel */
-        if (k->src_id == KDBUS_SRC_ID_KERNEL)
-                m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
-        else {
-                snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
-                m->sender = m->creds.unique_name = m->sender_buffer;
-        }
-
-        if (destination)
-                m->destination = destination;
-        else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
-                m->destination = NULL;
-        else if (k->dst_id == KDBUS_DST_ID_NAME)
-                m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
-        else {
-                snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
-                m->destination = m->destination_buffer;
-        }
-
-        /* We take possession of the kmsg struct now */
-        m->kdbus = k;
-        m->release_kdbus = true;
-        m->free_fds = true;
-        fds = NULL;
-
-        bus->rqueue[bus->rqueue_size++] = m;
-
-        return 1;
-
-fail:
-        if (m) {
-                struct bus_body_part *part;
-                unsigned i;
-
-                /* Make sure the memfds are not freed twice */
-                MESSAGE_FOREACH_PART(part, i, m)
-                        if (part->memfd >= 0)
-                                part->memfd = -1;
-
-                sd_bus_message_unref(m);
-        }
-
-        return r;
-}
-
-int bus_kernel_take_fd(sd_bus *b) {
-        struct kdbus_cmd_hello *hello;
-        struct kdbus_item *item;
-        size_t l = 0, sz;
-        int r;
-
-        assert(b);
-
-        if (b->is_server)
-                return -EINVAL;
-
-        b->use_memfd = 1;
-
-        sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
-
-        if (b->fake_creds_valid)
-                sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
-
-        if (b->fake_label) {
-                l = strlen(b->fake_label);
-                sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
-        }
-
-        hello = alloca0(sz);
-        hello->size = sz;
-        hello->conn_flags = b->hello_flags;
-        hello->attach_flags = b->attach_flags;
-        hello->pool_size = KDBUS_POOL_SIZE;
-
-        item = hello->items;
-
-        if (b->fake_creds_valid) {
-                item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
-                item->type = KDBUS_ITEM_CREDS;
-                item->creds = b->fake_creds;
-
-                item = KDBUS_ITEM_NEXT(item);
-        }
-
-        if (b->fake_label) {
-                item->size = offsetof(struct kdbus_item, str) + l + 1;
-                memcpy(item->str, b->fake_label, l+1);
-        }
-
-        r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
-        if (r < 0)
-                return -errno;
-
-        if (!b->kdbus_buffer) {
-                b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
-                if (b->kdbus_buffer == MAP_FAILED) {
-                        b->kdbus_buffer = NULL;
-                        return -errno;
-                }
-        }
-
-        /* The higher 32bit of both flags fields are considered
-         * 'incompatible flags'. Refuse them all for now. */
-        if (hello->bus_flags > 0xFFFFFFFFULL ||
-            hello->conn_flags > 0xFFFFFFFFULL)
-                return -ENOTSUP;
-
-        if (hello->bloom_size != BLOOM_SIZE)
-                return -ENOTSUP;
-
-        if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
-                return -ENOMEM;
-
-        b->unique_id = hello->id;
-
-        b->is_kernel = true;
-        b->bus_client = true;
-        b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
-        b->message_version = 2;
-        b->message_endian = BUS_NATIVE_ENDIAN;
-
-        /* the kernel told us the UUID of the underlying bus */
-        memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
-
-        return bus_start_running(b);
-}
-
-int bus_kernel_connect(sd_bus *b) {
-        assert(b);
-        assert(b->input_fd < 0);
-        assert(b->output_fd < 0);
-        assert(b->kernel);
-
-        if (b->is_server)
-                return -EINVAL;
-
-        b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (b->input_fd < 0)
-                return -errno;
-
-        b->output_fd = b->input_fd;
-
-        return bus_kernel_take_fd(b);
-}
-
-int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(bus->state == BUS_RUNNING);
-
-        /* If we can't deliver, we want room for the error message */
-        r = bus_rqueue_make_room(bus);
-        if (r < 0)
-                return r;
-
-        r = bus_message_setup_kmsg(bus, m);
-        if (r < 0)
-                return r;
-
-        r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
-        if (r < 0) {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-                sd_bus_message *reply;
-
-                if (errno == EAGAIN || errno == EINTR)
-                        return 0;
-                else if (errno == ENXIO || errno == ESRCH) {
-
-                        /* ENXIO: unique name not known
-                         * ESRCH: well-known name not known */
-
-                        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
-                                sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
-                        else {
-                                log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
-                                return 0;
-                        }
-
-                } else if (errno == EADDRNOTAVAIL) {
-
-                        /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
-
-                        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
-                                sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
-                        else {
-                                log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
-                                return 0;
-                        }
-                } else
-                        return -errno;
-
-                r = bus_message_new_synthetic_error(
-                                bus,
-                                BUS_MESSAGE_COOKIE(m),
-                                &error,
-                                &reply);
-
-                if (r < 0)
-                        return r;
-
-                r = bus_seal_synthetic_message(bus, reply);
-                if (r < 0)
-                        return r;
-
-                bus->rqueue[bus->rqueue_size++] = reply;
-
-                return 0;
-        }
-
-        return 1;
-}
-
-static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
-        uint64_t off;
-        struct kdbus_item *d;
-
-        assert(bus);
-        assert(k);
-
-        off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
-        ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
-
-        KDBUS_ITEM_FOREACH(d, k, items) {
-
-                if (d->type == KDBUS_ITEM_FDS)
-                        close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
-                else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
-                        close_nointr_nofail(d->memfd.fd);
-        }
-}
-
-static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert(bus);
-
-        r = sd_bus_message_new_signal(
-                        bus,
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "NameOwnerChanged",
-                        &m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
-        if (r < 0)
-                return r;
-
-        m->sender = "org.freedesktop.DBus";
-
-        r = bus_seal_synthetic_message(bus, m);
-        if (r < 0)
-                return r;
-
-        bus->rqueue[bus->rqueue_size++] = m;
-        m = NULL;
-
-        return 1;
-}
-
-static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
-        char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
-
-        assert(bus);
-        assert(k);
-        assert(d);
-
-        if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
-                old_owner[0] = 0;
-        else
-                sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id);
-
-        if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
-
-                if (isempty(old_owner))
-                        return 0;
-
-                new_owner[0] = 0;
-        } else
-                sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id);
-
-        return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
-}
-
-static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
-        char owner[UNIQUE_NAME_MAX];
-
-        assert(bus);
-        assert(k);
-        assert(d);
-
-        sprintf(owner, ":1.%llu", d->id_change.id);
-
-        return push_name_owner_changed(
-                        bus, owner,
-                        d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
-                        d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
-}
-
-static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert(bus);
-        assert(k);
-        assert(d);
-
-        r = bus_message_new_synthetic_error(
-                        bus,
-                        k->cookie_reply,
-                        d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
-                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
-                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
-                        &m);
-        if (r < 0)
-                return r;
-
-        m->sender = "org.freedesktop.DBus";
-
-        r = bus_seal_synthetic_message(bus, m);
-        if (r < 0)
-                return r;
-
-        bus->rqueue[bus->rqueue_size++] = m;
-        m = NULL;
-
-        return 1;
-}
-
-static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
-        struct kdbus_item *d, *found = NULL;
-
-        static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
-                [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
-                [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
-                [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
-
-                [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
-                [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
-
-                [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
-                [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
-        };
-
-        assert(bus);
-        assert(k);
-        assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
-
-        KDBUS_ITEM_FOREACH(d, k, items) {
-                if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
-                        if (found)
-                                return -EBADMSG;
-                        found = d;
-                } else
-                        log_debug("Got unknown field from kernel %llu", d->type);
-        }
-
-        if (!found) {
-                log_debug("Didn't find a kernel message to translate.");
-                return 0;
-        }
-
-        return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
-}
-
-int bus_kernel_read_message(sd_bus *bus) {
-        struct kdbus_cmd_recv recv = {};
-        struct kdbus_msg *k;
-        int r;
-
-        assert(bus);
-
-        r = bus_rqueue_make_room(bus);
-        if (r < 0)
-                return r;
-
-        r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &recv);
-        if (r < 0) {
-                if (errno == EAGAIN)
-                        return 0;
-
-                return -errno;
-        }
-        k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
-
-        if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
-                r = bus_kernel_make_message(bus, k);
-
-                /* Anybody can send us invalid messages, let's just drop them. */
-                if (r == -EBADMSG || r == -EPROTOTYPE) {
-                        log_debug("Ignoring invalid message: %s", strerror(-r));
-                        r = 0;
-                }
-
-        } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
-                r = bus_kernel_translate_message(bus, k);
-        else
-                r = 0;
-
-        if (r <= 0)
-                close_kdbus_msg(bus, k);
-
-        return r < 0 ? r : 1;
-}
-
-int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated) {
-        struct memfd_cache *c;
-        int fd;
-
-        assert(address);
-        assert(mapped);
-        assert(allocated);
-
-        if (!bus || !bus->is_kernel)
-                return -ENOTSUP;
-
-        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
-
-        if (bus->n_memfd_cache <= 0) {
-                struct kdbus_cmd_memfd_make cmd = {
-                        .size = sizeof(struct kdbus_cmd_memfd_make),
-                };
-                int r;
-
-                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
-
-                r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &cmd);
-                if (r < 0)
-                        return -errno;
-
-                *address = NULL;
-                *mapped = 0;
-                *allocated = 0;
-                return cmd.fd;
-        }
-
-        c = &bus->memfd_cache[--bus->n_memfd_cache];
-
-        assert(c->fd >= 0);
-        assert(c->mapped == 0 || c->address);
-
-        *address = c->address;
-        *mapped = c->mapped;
-        *allocated = c->allocated;
-        fd = c->fd;
-
-        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
-
-        return fd;
-}
-
-static void close_and_munmap(int fd, void *address, size_t size) {
-        if (size > 0)
-                assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
-
-        close_nointr_nofail(fd);
-}
-
-void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) {
-        struct memfd_cache *c;
-        uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
-
-        assert(fd >= 0);
-        assert(mapped == 0 || address);
-
-        if (!bus || !bus->is_kernel) {
-                close_and_munmap(fd, address, mapped);
-                return;
-        }
-
-        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
-
-        if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
-                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
-
-                close_and_munmap(fd, address, mapped);
-                return;
-        }
-
-        c = &bus->memfd_cache[bus->n_memfd_cache++];
-        c->fd = fd;
-        c->address = address;
-
-        /* If overly long, let's return a bit to the OS */
-        if (mapped > max_mapped) {
-                assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_mapped) >= 0);
-                assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0);
-                c->mapped = c->allocated = max_mapped;
-        } else {
-                c->mapped = mapped;
-                c->allocated = allocated;
-        }
-
-        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
-}
-
-void bus_kernel_flush_memfd(sd_bus *b) {
-        unsigned i;
-
-        assert(b);
-
-        for (i = 0; i < b->n_memfd_cache; i++)
-                close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
-}
-
-int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) {
-        uint64_t f = 0;
-
-        assert(kdbus_flags);
-
-        if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
-                f |= KDBUS_NAME_ALLOW_REPLACEMENT;
-
-        if (flags & SD_BUS_NAME_REPLACE_EXISTING)
-                f |= KDBUS_NAME_REPLACE_EXISTING;
-
-        if (flags & SD_BUS_NAME_QUEUE)
-                f |= KDBUS_NAME_QUEUE;
-
-        *kdbus_flags = f;
-        return 0;
-}
-
-int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
-        uint64_t m = 0;
-
-        assert(kdbus_mask);
-
-        if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))
-                m |= KDBUS_ATTACH_CREDS;
-
-        if (mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
-                m |= KDBUS_ATTACH_COMM;
-
-        if (mask & SD_BUS_CREDS_EXE)
-                m |= KDBUS_ATTACH_EXE;
-
-        if (mask & SD_BUS_CREDS_CMDLINE)
-                m |= KDBUS_ATTACH_CMDLINE;
-
-        if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))
-                m |= KDBUS_ATTACH_CGROUP;
-
-        if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
-                m |= KDBUS_ATTACH_CAPS;
-
-        if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
-                m |= KDBUS_ATTACH_SECLABEL;
-
-        if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
-                m |= KDBUS_ATTACH_AUDIT;
-
-        if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
-                m |= KDBUS_ATTACH_NAMES;
-
-        *kdbus_mask = m;
-        return 0;
-}
-
-int bus_kernel_create_bus(const char *name, bool world, char **s) {
-        struct kdbus_cmd_make *make;
-        struct kdbus_item *n;
-        int fd;
-
-        assert(name);
-        assert(s);
-
-        fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
-                              offsetof(struct kdbus_item, data64) + sizeof(uint64_t) +
-                              offsetof(struct kdbus_item, str) +
-                              DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1));
-
-        make->size = offsetof(struct kdbus_cmd_make, items);
-
-        n = make->items;
-        n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
-        n->type = KDBUS_ITEM_BLOOM_SIZE;
-        n->data64[0] = BLOOM_SIZE;
-        assert_cc(BLOOM_SIZE % 8 == 0);
-        make->size += ALIGN8(n->size);
-
-        n = KDBUS_ITEM_NEXT(n);
-        sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
-        n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
-        n->type = KDBUS_ITEM_MAKE_NAME;
-        make->size += ALIGN8(n->size);
-
-        make->flags = KDBUS_MAKE_POLICY_OPEN | (world ? KDBUS_MAKE_ACCESS_WORLD : 0);
-
-        if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        /* The higher 32bit of the flags field are considered
-         * 'incompatible flags'. Refuse them all for now. */
-        if (make->flags > 0xFFFFFFFFULL) {
-                close_nointr_nofail(fd);
-                return -ENOTSUP;
-        }
-
-        if (s) {
-                char *p;
-
-                p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
-                if (!p) {
-                        close_nointr_nofail(fd);
-                        return -ENOMEM;
-                }
-
-                *s = p;
-        }
-
-        return fd;
-}
-
-int bus_kernel_create_starter(const char *bus, const char *name) {
-        struct kdbus_cmd_hello *hello;
-        struct kdbus_item *n;
-        char *p;
-        int fd;
-
-        assert(bus);
-        assert(name);
-
-        p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus"));
-        sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus);
-
-        fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        hello = alloca0(ALIGN8(offsetof(struct kdbus_cmd_hello, items) +
-                               offsetof(struct kdbus_item, str) +
-                               strlen(name) + 1));
-
-        n = hello->items;
-        strcpy(n->str, name);
-        n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
-        n->type = KDBUS_ITEM_NAME;
-
-        hello->size = ALIGN8(offsetof(struct kdbus_cmd_hello, items) + n->size);
-        hello->conn_flags = KDBUS_HELLO_ACTIVATOR;
-        hello->pool_size = KDBUS_POOL_SIZE;
-
-        if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        /* The higher 32bit of both flags fields are considered
-         * 'incompatible flags'. Refuse them all for now. */
-        if (hello->bus_flags > 0xFFFFFFFFULL ||
-            hello->conn_flags > 0xFFFFFFFFULL) {
-                close_nointr_nofail(fd);
-                return -ENOTSUP;
-        }
-
-        if (hello->bloom_size != BLOOM_SIZE) {
-                close_nointr_nofail(fd);
-                return -ENOTSUP;
-        }
-
-        return fd;
-}
-
-int bus_kernel_create_namespace(const char *name, char **s) {
-        struct kdbus_cmd_make *make;
-        struct kdbus_item *n;
-        int fd;
-
-        assert(name);
-        assert(s);
-
-        fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
-                              offsetof(struct kdbus_item, str) +
-                              strlen(name) + 1));
-
-        n = make->items;
-        strcpy(n->str, name);
-        n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
-        n->type = KDBUS_ITEM_MAKE_NAME;
-
-        make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size);
-        make->flags = KDBUS_MAKE_POLICY_OPEN | KDBUS_MAKE_ACCESS_WORLD;
-
-        if (ioctl(fd, KDBUS_CMD_NS_MAKE, make) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        /* The higher 32bit of the flags field are considered
-         * 'incompatible flags'. Refuse them all for now. */
-        if (make->flags > 0xFFFFFFFFULL) {
-                close_nointr_nofail(fd);
-                return -ENOTSUP;
-        }
-
-        if (s) {
-                char *p;
-
-                p = strappend("/dev/kdbus/ns/", name);
-                if (!p) {
-                        close_nointr_nofail(fd);
-                        return -ENOMEM;
-                }
-
-                *s = p;
-        }
-
-        return fd;
-}
-
-int bus_kernel_create_monitor(const char *bus) {
-        struct kdbus_cmd_hello *hello;
-        char *p;
-        int fd;
-
-        assert(bus);
-
-        p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus"));
-        sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus);
-
-        fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        hello = alloca0(sizeof(struct kdbus_cmd_hello));
-        hello->size = sizeof(struct kdbus_cmd_hello);
-        hello->conn_flags = KDBUS_HELLO_ACTIVATOR;
-        hello->pool_size = KDBUS_POOL_SIZE;
-
-        if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        /* The higher 32bit of both flags fields are considered
-         * 'incompatible flags'. Refuse them all for now. */
-        if (hello->bus_flags > 0xFFFFFFFFULL ||
-            hello->conn_flags > 0xFFFFFFFFULL) {
-                close_nointr_nofail(fd);
-                return -ENOTSUP;
-        }
-
-        return fd;
-}
-
-int bus_kernel_try_close(sd_bus *bus) {
-        assert(bus);
-        assert(bus->is_kernel);
-
-        if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0)
-                return -errno;
-
-        return 0;
-}
diff --git a/src/libsystemd/bus-kernel.h b/src/libsystemd/bus-kernel.h
deleted file mode 100644
index 2aba0bb..0000000
--- a/src/libsystemd/bus-kernel.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*-*- 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 <stdbool.h>
-
-#include "sd-bus.h"
-
-#define KDBUS_ITEM_NEXT(item) \
-        (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
-
-#define KDBUS_ITEM_FOREACH(part, head, first)                           \
-        for (part = (head)->first;                                      \
-             (uint8_t *)(part) < (uint8_t *)(head) + (head)->size;      \
-             part = KDBUS_ITEM_NEXT(part))
-
-#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
-#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
-
-#define MEMFD_CACHE_MAX 32
-
-/* When we cache a memfd block for reuse, we will truncate blocks
- * longer than this in order not to keep too much data around. */
-#define MEMFD_CACHE_ITEM_SIZE_MAX (128*1024)
-
-/* This determines at which minimum size we prefer sending memfds over
- * sending vectors */
-#define MEMFD_MIN_SIZE (128*1024)
-
-/* The size of the per-connection memory pool that we set up and where
- * the kernel places our incoming messages */
-#define KDBUS_POOL_SIZE (16*1024*1024)
-
-struct memfd_cache {
-        int fd;
-        void *address;
-        size_t mapped;
-        size_t allocated;
-};
-
-int bus_kernel_connect(sd_bus *b);
-int bus_kernel_take_fd(sd_bus *b);
-
-int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m);
-int bus_kernel_read_message(sd_bus *bus);
-
-int bus_kernel_create_bus(const char *name, bool world, char **s);
-int bus_kernel_create_namespace(const char *name, char **s);
-int bus_kernel_create_starter(const char *bus, const char *name);
-int bus_kernel_create_monitor(const char *bus);
-
-int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated);
-void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated);
-
-void bus_kernel_flush_memfd(sd_bus *bus);
-
-int bus_kernel_parse_unique_name(const char *s, uint64_t *id);
-
-int kdbus_translate_request_name_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags);
-int kdbus_translate_attach_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags);
-
-int bus_kernel_try_close(sd_bus *bus);
diff --git a/src/libsystemd/bus-match.c b/src/libsystemd/bus-match.c
deleted file mode 100644
index ffc9756..0000000
--- a/src/libsystemd/bus-match.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*-*- 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 "bus-internal.h"
-#include "bus-message.h"
-#include "bus-match.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "strv.h"
-
-/* Example:
- *
- *  A: type=signal,sender=foo,interface=bar
- *  B: type=signal,sender=quux,interface=fips
- *  C: type=signal,sender=quux,interface=waldo
- *  D: type=signal,member=test
- *  E: sender=miau
- *  F: type=signal
- *  G: type=signal
- *
- *  results in this tree:
- *
- *  BUS_MATCH_ROOT
- *  + BUS_MATCH_MESSAGE_TYPE
- *  | ` BUS_MATCH_VALUE: value == signal
- *  |   + DBUS_MATCH_SENDER
- *  |   | + BUS_MATCH_VALUE: value == foo
- *  |   | | ` DBUS_MATCH_INTERFACE
- *  |   | |   ` BUS_MATCH_VALUE: value == bar
- *  |   | |     ` BUS_MATCH_LEAF: A
- *  |   | ` BUS_MATCH_VALUE: value == quux
- *  |   |   ` DBUS_MATCH_INTERFACE
- *  |   |     | BUS_MATCH_VALUE: value == fips
- *  |   |     | ` BUS_MATCH_LEAF: B
- *  |   |     ` BUS_MATCH_VALUE: value == waldo
- *  |   |       ` BUS_MATCH_LEAF: C
- *  |   + DBUS_MATCH_MEMBER
- *  |   | ` BUS_MATCH_VALUE: value == test
- *  |   |   ` BUS_MATCH_LEAF: D
- *  |   + BUS_MATCH_LEAF: F
- *  |   ` BUS_MATCH_LEAF: G
- *  ` BUS_MATCH_SENDER
- *    ` BUS_MATCH_VALUE: value == miau
- *      ` BUS_MATCH_LEAF: E
- */
-
-static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
-        return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
-}
-
-static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
-        return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
-                (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
-}
-
-static void bus_match_node_free(struct bus_match_node *node) {
-        assert(node);
-        assert(node->parent);
-        assert(!node->child);
-        assert(node->type != BUS_MATCH_ROOT);
-        assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
-
-        if (node->parent->child) {
-                /* We are apparently linked into the parent's child
-                 * list. Let's remove us from there. */
-                if (node->prev) {
-                        assert(node->prev->next == node);
-                        node->prev->next = node->next;
-                } else {
-                        assert(node->parent->child == node);
-                        node->parent->child = node->next;
-                }
-
-                if (node->next)
-                        node->next->prev = node->prev;
-        }
-
-        if (node->type == BUS_MATCH_VALUE) {
-                /* We might be in the parent's hash table, so clean
-                 * this up */
-
-                if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
-                        hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
-                else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
-                        hashmap_remove(node->parent->compare.children, node->value.str);
-
-                free(node->value.str);
-        }
-
-        if (BUS_MATCH_IS_COMPARE(node->type)) {
-                assert(hashmap_isempty(node->compare.children));
-                hashmap_free(node->compare.children);
-        }
-
-        free(node);
-}
-
-static bool bus_match_node_maybe_free(struct bus_match_node *node) {
-        assert(node);
-
-        if (node->child)
-                return false;
-
-        if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
-                return true;
-
-        bus_match_node_free(node);
-        return true;
-}
-
-static bool value_node_test(
-                struct bus_match_node *node,
-                enum bus_match_node_type parent_type,
-                uint8_t value_u8,
-                const char *value_str,
-                sd_bus_message *m) {
-
-        assert(node);
-        assert(node->type == BUS_MATCH_VALUE);
-
-        /* Tests parameters against this value node, doing prefix
-         * magic and stuff. */
-
-        switch (parent_type) {
-
-        case BUS_MATCH_MESSAGE_TYPE:
-                return node->value.u8 == value_u8;
-
-        case BUS_MATCH_SENDER:
-                if (streq_ptr(node->value.str, value_str))
-                        return true;
-
-                if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
-                        char **i;
-
-                        /* on kdbus we have the well known names list
-                         * in the credentials, let's make use of that
-                         * for an accurate match */
-
-                        STRV_FOREACH(i, m->creds.well_known_names)
-                                if (streq_ptr(node->value.str, *i))
-                                        return true;
-
-                } else {
-
-                        /* If we don't have kdbus, we don't know the
-                         * well-known names of the senders. In that,
-                         * let's just hope that dbus-daemon doesn't
-                         * send us stuff we didn't want. */
-
-                        if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
-                                return true;
-                }
-
-                return false;
-
-        case BUS_MATCH_DESTINATION:
-        case BUS_MATCH_INTERFACE:
-        case BUS_MATCH_MEMBER:
-        case BUS_MATCH_PATH:
-        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
-                return streq_ptr(node->value.str, value_str);
-
-        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
-                return namespace_simple_pattern(node->value.str, value_str);
-
-        case BUS_MATCH_PATH_NAMESPACE:
-                return path_simple_pattern(node->value.str, value_str);
-
-        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
-                return path_complex_pattern(node->value.str, value_str);
-
-        default:
-                assert_not_reached("Invalid node type");
-        }
-}
-
-static bool value_node_same(
-                struct bus_match_node *node,
-                enum bus_match_node_type parent_type,
-                uint8_t value_u8,
-                const char *value_str) {
-
-        /* Tests parameters against this value node, not doing prefix
-         * magic and stuff, i.e. this one actually compares the match
-         * itself.*/
-
-        assert(node);
-        assert(node->type == BUS_MATCH_VALUE);
-
-        switch (parent_type) {
-
-        case BUS_MATCH_MESSAGE_TYPE:
-                return node->value.u8 == value_u8;
-
-        case BUS_MATCH_SENDER:
-        case BUS_MATCH_DESTINATION:
-        case BUS_MATCH_INTERFACE:
-        case BUS_MATCH_MEMBER:
-        case BUS_MATCH_PATH:
-        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
-        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
-        case BUS_MATCH_PATH_NAMESPACE:
-        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
-                return streq(node->value.str, value_str);
-
-        default:
-                assert_not_reached("Invalid node type");
-        }
-}
-
-int bus_match_run(
-                sd_bus *bus,
-                struct bus_match_node *node,
-                sd_bus_message *m) {
-
-
-        const char *test_str = NULL;
-        uint8_t test_u8 = 0;
-        int r;
-
-        assert(m);
-
-        if (!node)
-                return 0;
-
-        if (bus && bus->match_callbacks_modified)
-                return 0;
-
-        /* Not these special semantics: when traversing the tree we
-         * usually let bus_match_run() when called for a node
-         * recursively invoke bus_match_run(). There's are two
-         * exceptions here though, which are BUS_NODE_ROOT (which
-         * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
-         * are invoked anyway by its parent. */
-
-        switch (node->type) {
-
-        case BUS_MATCH_ROOT:
-
-                /* Run all children. Since we cannot have any siblings
-                 * we won't call any. The children of the root node
-                 * are compares or leaves, they will automatically
-                 * call their siblings. */
-                return bus_match_run(bus, node->child, m);
-
-        case BUS_MATCH_VALUE:
-
-                /* Run all children. We don't execute any siblings, we
-                 * assume our caller does that. The children of value
-                 * nodes are compares or leaves, they will
-                 * automatically call their siblings */
-
-                assert(node->child);
-                return bus_match_run(bus, node->child, m);
-
-        case BUS_MATCH_LEAF:
-
-                if (bus) {
-                        if (node->leaf.last_iteration == bus->iteration_counter)
-                                return 0;
-
-                        node->leaf.last_iteration = bus->iteration_counter;
-                }
-
-                r = sd_bus_message_rewind(m, true);
-                if (r < 0)
-                        return r;
-
-                /* Run the callback. And then invoke siblings. */
-                if (node->leaf.callback) {
-                        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-
-                        r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
-                        r = bus_maybe_reply_error(m, r, &error_buffer);
-                        if (r != 0)
-                                return r;
-                }
-
-                return bus_match_run(bus, node->next, m);
-
-        case BUS_MATCH_MESSAGE_TYPE:
-                test_u8 = m->header->type;
-                break;
-
-        case BUS_MATCH_SENDER:
-                test_str = m->sender;
-                /* FIXME: resolve test_str from a well-known to a unique name first */
-                break;
-
-        case BUS_MATCH_DESTINATION:
-                test_str = m->destination;
-                break;
-
-        case BUS_MATCH_INTERFACE:
-                test_str = m->interface;
-                break;
-
-        case BUS_MATCH_MEMBER:
-                test_str = m->member;
-                break;
-
-        case BUS_MATCH_PATH:
-        case BUS_MATCH_PATH_NAMESPACE:
-                test_str = m->path;
-                break;
-
-        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
-                test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
-                break;
-
-        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
-                test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
-                break;
-
-        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
-                test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
-                break;
-
-        default:
-                assert_not_reached("Unknown match type.");
-        }
-
-        if (BUS_MATCH_CAN_HASH(node->type)) {
-                struct bus_match_node *found;
-
-                /* Lookup via hash table, nice! So let's jump directly. */
-
-                if (test_str)
-                        found = hashmap_get(node->compare.children, test_str);
-                else if (node->type == BUS_MATCH_MESSAGE_TYPE)
-                        found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
-                else
-                        found = NULL;
-
-                if (found) {
-                        r = bus_match_run(bus, found, m);
-                        if (r != 0)
-                                return r;
-                }
-        } else {
-                struct bus_match_node *c;
-
-                /* No hash table, so let's iterate manually... */
-
-                for (c = node->child; c; c = c->next) {
-                        if (!value_node_test(c, node->type, test_u8, test_str, m))
-                                continue;
-
-                        r = bus_match_run(bus, c, m);
-                        if (r != 0)
-                                return r;
-                }
-        }
-
-        if (bus && bus->match_callbacks_modified)
-                return 0;
-
-        /* And now, let's invoke our siblings */
-        return bus_match_run(bus, node->next, m);
-}
-
-static int bus_match_add_compare_value(
-                struct bus_match_node *where,
-                enum bus_match_node_type t,
-                uint8_t value_u8,
-                const char *value_str,
-                struct bus_match_node **ret) {
-
-        struct bus_match_node *c = NULL, *n = NULL;
-        int r;
-
-        assert(where);
-        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
-        assert(BUS_MATCH_IS_COMPARE(t));
-        assert(ret);
-
-        for (c = where->child; c && c->type != t; c = c->next)
-                ;
-
-        if (c) {
-                /* Comparison node already exists? Then let's see if
-                 * the value node exists too. */
-
-                if (t == BUS_MATCH_MESSAGE_TYPE)
-                        n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
-                else if (BUS_MATCH_CAN_HASH(t))
-                        n = hashmap_get(c->compare.children, value_str);
-                else {
-                        for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
-                                ;
-                }
-
-                if (n) {
-                        *ret = n;
-                        return 0;
-                }
-        } else {
-                /* Comparison node, doesn't exist yet? Then let's
-                 * create it. */
-
-                c = new0(struct bus_match_node, 1);
-                if (!c) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                c->type = t;
-                c->parent = where;
-                c->next = where->child;
-                if (c->next)
-                        c->next->prev = c;
-                where->child = c;
-
-                if (t == BUS_MATCH_MESSAGE_TYPE) {
-                        c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
-                        if (!c->compare.children) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-                } else if (BUS_MATCH_CAN_HASH(t)) {
-                        c->compare.children = hashmap_new(string_hash_func, string_compare_func);
-                        if (!c->compare.children) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-                }
-        }
-
-        n = new0(struct bus_match_node, 1);
-        if (!n) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        n->type = BUS_MATCH_VALUE;
-        n->value.u8 = value_u8;
-        if (value_str) {
-                n->value.str = strdup(value_str);
-                if (!n->value.str) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        n->parent = c;
-        if (c->compare.children) {
-
-                if (t == BUS_MATCH_MESSAGE_TYPE)
-                        r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
-                else
-                        r = hashmap_put(c->compare.children, n->value.str, n);
-
-                if (r < 0)
-                        goto fail;
-        } else {
-                n->next = c->child;
-                if (n->next)
-                        n->next->prev = n;
-                c->child = n;
-        }
-
-        *ret = n;
-        return 1;
-
-fail:
-        if (c)
-                bus_match_node_maybe_free(c);
-
-        if (n) {
-                free(n->value.str);
-                free(n);
-        }
-
-        return r;
-}
-
-static int bus_match_find_compare_value(
-                struct bus_match_node *where,
-                enum bus_match_node_type t,
-                uint8_t value_u8,
-                const char *value_str,
-                struct bus_match_node **ret) {
-
-        struct bus_match_node *c, *n;
-
-        assert(where);
-        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
-        assert(BUS_MATCH_IS_COMPARE(t));
-        assert(ret);
-
-        for (c = where->child; c && c->type != t; c = c->next)
-                ;
-
-        if (!c)
-                return 0;
-
-        if (t == BUS_MATCH_MESSAGE_TYPE)
-                n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
-        else if (BUS_MATCH_CAN_HASH(t))
-                n = hashmap_get(c->compare.children, value_str);
-        else {
-                for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
-                        ;
-        }
-
-        if (n) {
-                *ret = n;
-                return 1;
-        }
-
-        return 0;
-}
-
-static int bus_match_add_leaf(
-                struct bus_match_node *where,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t cookie,
-                struct bus_match_node **ret) {
-
-        struct bus_match_node *n;
-
-        assert(where);
-        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
-        assert(ret);
-
-        n = new0(struct bus_match_node, 1);
-        if (!n)
-                return -ENOMEM;
-
-        n->type = BUS_MATCH_LEAF;
-        n->parent = where;
-        n->next = where->child;
-        if (n->next)
-                n->next->prev = n;
-        n->leaf.callback = callback;
-        n->leaf.userdata = userdata;
-        n->leaf.cookie = cookie;
-
-        where->child = n;
-
-        *ret = n;
-        return 1;
-}
-
-static int bus_match_find_leaf(
-                struct bus_match_node *where,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                struct bus_match_node **ret) {
-
-        struct bus_match_node *c;
-
-        assert(where);
-        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
-        assert(ret);
-
-        for (c = where->child; c; c = c->next) {
-                if (c->type == BUS_MATCH_LEAF &&
-                    c->leaf.callback == callback &&
-                    c->leaf.userdata == userdata) {
-                        *ret = c;
-                        return 1;
-                }
-        }
-
-        return 0;
-}
-
-enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
-        assert(k);
-
-        if (n == 4 && startswith(k, "type"))
-                return BUS_MATCH_MESSAGE_TYPE;
-        if (n == 6 && startswith(k, "sender"))
-                return BUS_MATCH_SENDER;
-        if (n == 11 && startswith(k, "destination"))
-                return BUS_MATCH_DESTINATION;
-        if (n == 9 && startswith(k, "interface"))
-                return BUS_MATCH_INTERFACE;
-        if (n == 6 && startswith(k, "member"))
-                return BUS_MATCH_MEMBER;
-        if (n == 4 && startswith(k, "path"))
-                return BUS_MATCH_PATH;
-        if (n == 14 && startswith(k, "path_namespace"))
-                return BUS_MATCH_PATH_NAMESPACE;
-
-        if (n == 4 && startswith(k, "arg")) {
-                int j;
-
-                j = undecchar(k[3]);
-                if (j < 0)
-                        return -EINVAL;
-
-                return BUS_MATCH_ARG + j;
-        }
-
-        if (n == 5 && startswith(k, "arg")) {
-                int a, b;
-                enum bus_match_node_type t;
-
-                a = undecchar(k[3]);
-                b = undecchar(k[4]);
-                if (a <= 0 || b < 0)
-                        return -EINVAL;
-
-                t = BUS_MATCH_ARG + a * 10 + b;
-                if (t > BUS_MATCH_ARG_LAST)
-                        return -EINVAL;
-
-                return t;
-        }
-
-        if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
-                int j;
-
-                j = undecchar(k[3]);
-                if (j < 0)
-                        return -EINVAL;
-
-                return BUS_MATCH_ARG_PATH + j;
-        }
-
-        if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
-                enum bus_match_node_type t;
-                int a, b;
-
-                a = undecchar(k[3]);
-                b = undecchar(k[4]);
-                if (a <= 0 || b < 0)
-                        return -EINVAL;
-
-                t = BUS_MATCH_ARG_PATH + a * 10 + b;
-                if (t > BUS_MATCH_ARG_PATH_LAST)
-                        return -EINVAL;
-
-                return t;
-        }
-
-        if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
-                int j;
-
-                j = undecchar(k[3]);
-                if (j < 0)
-                        return -EINVAL;
-
-                return BUS_MATCH_ARG_NAMESPACE + j;
-        }
-
-        if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
-                enum bus_match_node_type t;
-                int a, b;
-
-                a = undecchar(k[3]);
-                b = undecchar(k[4]);
-                if (a <= 0 || b < 0)
-                        return -EINVAL;
-
-                t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
-                if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
-                        return -EINVAL;
-
-                return t;
-        }
-
-        return -EINVAL;
-}
-
-static int match_component_compare(const void *a, const void *b) {
-        const struct bus_match_component *x = a, *y = b;
-
-        if (x->type < y->type)
-                return -1;
-        if (x->type > y->type)
-                return 1;
-
-        return 0;
-}
-
-void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
-        unsigned i;
-
-        for (i = 0; i < n_components; i++)
-                free(components[i].value_str);
-
-        free(components);
-}
-
-int bus_match_parse(
-                const char *match,
-                struct bus_match_component **_components,
-                unsigned *_n_components) {
-
-        const char *p = match;
-        struct bus_match_component *components = NULL;
-        size_t components_allocated = 0;
-        unsigned n_components = 0, i;
-        _cleanup_free_ char *value = NULL;
-        int r;
-
-        assert(match);
-        assert(_components);
-        assert(_n_components);
-
-        while (*p != 0) {
-                const char *eq, *q;
-                enum bus_match_node_type t;
-                unsigned j = 0;
-                size_t value_allocated = 0;
-                bool escaped = false, quoted;
-                uint8_t u;
-
-                eq = strchr(p, '=');
-                if (!eq)
-                        return -EINVAL;
-
-                t = bus_match_node_type_from_string(p, eq - p);
-                if (t < 0)
-                        return -EINVAL;
-
-                quoted = eq[1] == '\'';
-
-                for (q = eq + 1 + quoted;; q++) {
-
-                        if (*q == 0) {
-
-                                if (quoted) {
-                                        r = -EINVAL;
-                                        goto fail;
-                                } else {
-                                        if (value)
-                                                value[j] = 0;
-                                        break;
-                                }
-                        }
-
-                        if (!escaped) {
-                                if (*q == '\\') {
-                                        escaped = true;
-                                        continue;
-                                }
-
-                                if (quoted) {
-                                        if (*q == '\'') {
-                                                if (value)
-                                                        value[j] = 0;
-                                                break;
-                                        }
-                                } else {
-                                        if (*q == ',') {
-                                                if (value)
-                                                        value[j] = 0;
-
-                                                break;
-                                        }
-                                }
-                        }
-
-                        if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        value[j++] = *q;
-                        escaped = false;
-                }
-
-                if (!value) {
-                        value = strdup("");
-                        if (!value) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-                }
-
-                if (t == BUS_MATCH_MESSAGE_TYPE) {
-                        r = bus_message_type_from_string(value, &u);
-                        if (r < 0)
-                                goto fail;
-
-                        free(value);
-                        value = NULL;
-                } else
-                        u = 0;
-
-                if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                components[n_components].type = t;
-                components[n_components].value_str = value;
-                components[n_components].value_u8 = u;
-                n_components++;
-
-                value = NULL;
-
-                if (q[1] == 0)
-                        break;
-
-                if (q[quoted] != ',') {
-                        r = -EINVAL;
-                        goto fail;
-                }
-
-                p = q + 1 + quoted;
-        }
-
-        /* Order the whole thing, so that we always generate the same tree */
-        qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
-
-        /* Check for duplicates */
-        for (i = 0; i+1 < n_components; i++)
-                if (components[i].type == components[i+1].type) {
-                        r = -EINVAL;
-                        goto fail;
-                }
-
-        *_components = components;
-        *_n_components = n_components;
-
-        return 0;
-
-fail:
-        bus_match_parse_free(components, n_components);
-        return r;
-}
-
-char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
-        _cleanup_free_ FILE *f = NULL;
-        char *buffer = NULL;
-        size_t size = 0;
-        unsigned i;
-
-        if (n_components <= 0)
-                return strdup("");
-
-        assert(components);
-
-        f = open_memstream(&buffer, &size);
-        if (!f)
-                return NULL;
-
-        for (i = 0; i < n_components; i++) {
-                char buf[32];
-
-                if (i != 0)
-                        fputc(',', f);
-
-                fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
-                fputc('=', f);
-                fputc('\'', f);
-
-                if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
-                        fputs(bus_message_type_to_string(components[i].value_u8), f);
-                else
-                        fputs(components[i].value_str, f);
-
-                fputc('\'', f);
-        }
-
-        fflush(f);
-        if (ferror(f))
-                return NULL;
-
-        return buffer;
-}
-
-int bus_match_add(
-                struct bus_match_node *root,
-                struct bus_match_component *components,
-                unsigned n_components,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t cookie,
-                struct bus_match_node **ret) {
-
-        unsigned i;
-        struct bus_match_node *n;
-        int r;
-
-        assert(root);
-
-        n = root;
-        for (i = 0; i < n_components; i++) {
-                r = bus_match_add_compare_value(
-                                n, components[i].type,
-                                components[i].value_u8, components[i].value_str, &n);
-                if (r < 0)
-                        return r;
-        }
-
-        r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
-        if (r < 0)
-                return r;
-
-        if (ret)
-                *ret = n;
-
-        return 0;
-}
-
-int bus_match_remove(
-                struct bus_match_node *root,
-                struct bus_match_component *components,
-                unsigned n_components,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t *cookie) {
-
-        unsigned i;
-        struct bus_match_node *n, **gc;
-        int r;
-
-        assert(root);
-
-        gc = newa(struct bus_match_node*, n_components);
-
-        n = root;
-        for (i = 0; i < n_components; i++) {
-                r = bus_match_find_compare_value(
-                                n, components[i].type,
-                                components[i].value_u8, components[i].value_str,
-                                &n);
-                if (r <= 0)
-                        return r;
-
-                gc[i] = n;
-        }
-
-        r = bus_match_find_leaf(n, callback, userdata, &n);
-        if (r <= 0)
-                return r;
-
-        if (cookie)
-                *cookie = n->leaf.cookie;
-
-        /* Free the leaf */
-        bus_match_node_free(n);
-
-        /* Prune the tree above */
-        for (i = n_components; i > 0; i --) {
-                struct bus_match_node *p = gc[i-1]->parent;
-
-                if (!bus_match_node_maybe_free(gc[i-1]))
-                        break;
-
-                if (!bus_match_node_maybe_free(p))
-                        break;
-        }
-
-        return r;
-}
-
-void bus_match_free(struct bus_match_node *node) {
-        struct bus_match_node *c;
-
-        if (!node)
-                return;
-
-        if (BUS_MATCH_CAN_HASH(node->type)) {
-                Iterator i;
-
-                HASHMAP_FOREACH(c, node->compare.children, i)
-                        bus_match_free(c);
-
-                assert(hashmap_isempty(node->compare.children));
-        }
-
-        while ((c = node->child))
-                bus_match_free(c);
-
-        if (node->type != BUS_MATCH_ROOT)
-                bus_match_node_free(node);
-}
-
-const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
-        switch (t) {
-
-        case BUS_MATCH_ROOT:
-                return "root";
-
-        case BUS_MATCH_VALUE:
-                return "value";
-
-        case BUS_MATCH_LEAF:
-                return "leaf";
-
-        case BUS_MATCH_MESSAGE_TYPE:
-                return "type";
-
-        case BUS_MATCH_SENDER:
-                return "sender";
-
-        case BUS_MATCH_DESTINATION:
-                return "destination";
-
-        case BUS_MATCH_INTERFACE:
-                return "interface";
-
-        case BUS_MATCH_MEMBER:
-                return "member";
-
-        case BUS_MATCH_PATH:
-                return "path";
-
-        case BUS_MATCH_PATH_NAMESPACE:
-                return "path_namespace";
-
-        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
-                snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
-                return buf;
-
-        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
-                snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
-                return buf;
-
-        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
-                snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
-                return buf;
-
-        default:
-                return NULL;
-        }
-}
-
-void bus_match_dump(struct bus_match_node *node, unsigned level) {
-        struct bus_match_node *c;
-        _cleanup_free_ char *pfx = NULL;
-        char buf[32];
-
-        if (!node)
-                return;
-
-        pfx = strrep("  ", level);
-        printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
-
-        if (node->type == BUS_MATCH_VALUE) {
-                if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
-                        printf(" <%u>\n", node->value.u8);
-                else
-                        printf(" <%s>\n", node->value.str);
-        } else if (node->type == BUS_MATCH_ROOT)
-                puts(" root");
-        else if (node->type == BUS_MATCH_LEAF)
-                printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
-        else
-                putchar('\n');
-
-        if (BUS_MATCH_CAN_HASH(node->type)) {
-                Iterator i;
-
-                HASHMAP_FOREACH(c, node->compare.children, i)
-                        bus_match_dump(c, level + 1);
-        }
-
-        for (c = node->child; c; c = c->next)
-                bus_match_dump(c, level + 1);
-}
diff --git a/src/libsystemd/bus-match.h b/src/libsystemd/bus-match.h
deleted file mode 100644
index 056082b..0000000
--- a/src/libsystemd/bus-match.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*-*- 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 "hashmap.h"
-
-#include "sd-bus.h"
-
-enum bus_match_node_type {
-        BUS_MATCH_ROOT,
-        BUS_MATCH_VALUE,
-        BUS_MATCH_LEAF,
-
-        /* The following are all different kinds of compare nodes */
-        BUS_MATCH_SENDER,
-        BUS_MATCH_MESSAGE_TYPE,
-        BUS_MATCH_DESTINATION,
-        BUS_MATCH_INTERFACE,
-        BUS_MATCH_MEMBER,
-        BUS_MATCH_PATH,
-        BUS_MATCH_PATH_NAMESPACE,
-        BUS_MATCH_ARG,
-        BUS_MATCH_ARG_LAST = BUS_MATCH_ARG + 63,
-        BUS_MATCH_ARG_PATH,
-        BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63,
-        BUS_MATCH_ARG_NAMESPACE,
-        BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63,
-        _BUS_MATCH_NODE_TYPE_MAX,
-        _BUS_MATCH_NODE_TYPE_INVALID = -1
-};
-
-struct bus_match_node {
-        enum bus_match_node_type type;
-        struct bus_match_node *parent, *next, *prev, *child;
-
-        union {
-                struct {
-                        char *str;
-                        uint8_t u8;
-                } value;
-                struct {
-                        sd_bus_message_handler_t callback;
-                        void *userdata;
-                        unsigned last_iteration;
-                        uint64_t cookie;
-                } leaf;
-                struct {
-                        /* If this is set, then the child is NULL */
-                        Hashmap *children;
-                } compare;
-        };
-};
-
-struct bus_match_component {
-        enum bus_match_node_type type;
-        uint8_t value_u8;
-        char *value_str;
-};
-
-int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
-
-int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t cookie, struct bus_match_node **ret);
-int bus_match_remove(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t *cookie);
-
-void bus_match_free(struct bus_match_node *node);
-
-void bus_match_dump(struct bus_match_node *node, unsigned level);
-
-const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l);
-enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n);
-
-int bus_match_parse(const char *match, struct bus_match_component **_components, unsigned *_n_components);
-void bus_match_parse_free(struct bus_match_component *components, unsigned n_components);
-char *bus_match_to_string(struct bus_match_component *components, unsigned n_components);
diff --git a/src/libsystemd/bus-message.c b/src/libsystemd/bus-message.c
deleted file mode 100644
index 1a2039b..0000000
--- a/src/libsystemd/bus-message.c
+++ /dev/null
@@ -1,5535 +0,0 @@
-/*-*- 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 <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "util.h"
-#include "utf8.h"
-#include "strv.h"
-#include "time-util.h"
-#include "cgroup-util.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-internal.h"
-#include "bus-type.h"
-#include "bus-signature.h"
-#include "bus-gvariant.h"
-#include "bus-util.h"
-
-static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
-
-static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
-
-        if (p == NULL)
-                return NULL;
-
-        if (old_base == new_base)
-                return (void*) p;
-
-        if ((uint8_t*) p < (uint8_t*) old_base)
-                return (void*) p;
-
-        if ((uint8_t*) p >= (uint8_t*) old_base + sz)
-                return (void*) p;
-
-        return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
-}
-
-static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
-        assert(m);
-        assert(part);
-
-        if (part->memfd >= 0) {
-                /* If we can reuse the memfd, try that. For that it
-                 * can't be sealed yet. */
-
-                if (!part->sealed)
-                        bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
-                else {
-                        if (part->mapped > 0)
-                                assert_se(munmap(part->data, part->mapped) == 0);
-
-                        close_nointr_nofail(part->memfd);
-                }
-
-        } else if (part->munmap_this)
-                munmap(part->data, part->mapped);
-        else if (part->free_this)
-                free(part->data);
-
-        if (part != &m->body)
-                free(part);
-}
-
-static void message_reset_parts(sd_bus_message *m) {
-        struct bus_body_part *part;
-
-        assert(m);
-
-        part = &m->body;
-        while (m->n_body_parts > 0) {
-                struct bus_body_part *next = part->next;
-                message_free_part(m, part);
-                part = next;
-                m->n_body_parts--;
-        }
-
-        m->body_end = NULL;
-
-        m->cached_rindex_part = NULL;
-        m->cached_rindex_part_begin = 0;
-}
-
-static void message_reset_containers(sd_bus_message *m) {
-        unsigned i;
-
-        assert(m);
-
-        for (i = 0; i < m->n_containers; i++) {
-                free(m->containers[i].signature);
-                free(m->containers[i].offsets);
-        }
-
-        free(m->containers);
-        m->containers = NULL;
-
-        m->n_containers = m->containers_allocated = 0;
-        m->root_container.index = 0;
-}
-
-static void message_free(sd_bus_message *m) {
-        assert(m);
-
-        if (m->free_header)
-                free(m->header);
-
-        message_reset_parts(m);
-
-        if (m->free_kdbus)
-                free(m->kdbus);
-
-        if (m->release_kdbus) {
-                uint64_t off;
-
-                off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer;
-                ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off);
-        }
-
-        if (m->bus)
-                sd_bus_unref(m->bus);
-
-        if (m->free_fds) {
-                close_many(m->fds, m->n_fds);
-                free(m->fds);
-        }
-
-        if (m->iovec != m->iovec_fixed)
-                free(m->iovec);
-
-        message_reset_containers(m);
-        free(m->root_container.signature);
-        free(m->root_container.offsets);
-
-        free(m->root_container.peeked_signature);
-
-        bus_creds_done(&m->creds);
-        free(m);
-}
-
-static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
-        void *op, *np;
-        size_t old_size, new_size, start;
-
-        assert(m);
-
-        if (m->poisoned)
-                return NULL;
-
-        old_size = sizeof(struct bus_header) + m->header->fields_size;
-        start = ALIGN_TO(old_size, align);
-        new_size = start + sz;
-
-        if (old_size == new_size)
-                return (uint8_t*) m->header + old_size;
-
-        if (new_size > (size_t) ((uint32_t) -1))
-                goto poison;
-
-        if (m->free_header) {
-                np = realloc(m->header, ALIGN8(new_size));
-                if (!np)
-                        goto poison;
-        } else {
-                /* Initially, the header is allocated as part of of
-                 * the sd_bus_message itself, let's replace it by
-                 * dynamic data */
-
-                np = malloc(ALIGN8(new_size));
-                if (!np)
-                        goto poison;
-
-                memcpy(np, m->header, sizeof(struct bus_header));
-        }
-
-        /* Zero out padding */
-        if (start > old_size)
-                memset((uint8_t*) np + old_size, 0, start - old_size);
-
-        op = m->header;
-        m->header = np;
-        m->header->fields_size = new_size - sizeof(struct bus_header);
-
-        /* Adjust quick access pointers */
-        m->path = adjust_pointer(m->path, op, old_size, m->header);
-        m->interface = adjust_pointer(m->interface, op, old_size, m->header);
-        m->member = adjust_pointer(m->member, op, old_size, m->header);
-        m->destination = adjust_pointer(m->destination, op, old_size, m->header);
-        m->sender = adjust_pointer(m->sender, op, old_size, m->header);
-        m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
-
-        m->free_header = true;
-
-        if (add_offset) {
-                if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
-                        goto poison;
-
-                m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
-        }
-
-        return (uint8_t*) np + start;
-
-poison:
-        m->poisoned = true;
-        return NULL;
-}
-
-static int message_append_field_string(
-                sd_bus_message *m,
-                uint8_t h,
-                char type,
-                const char *s,
-                const char **ret) {
-
-        size_t l;
-        uint8_t *p;
-
-        assert(m);
-
-        /* dbus1 doesn't allow strings over 32bit, let's enforce this
-         * globally, to not risk convertability */
-        l = strlen(s);
-        if (l > (size_t) (uint32_t) -1)
-                return -EINVAL;
-
-        /* Signature "(yv)" where the variant contains "s" */
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-
-                /* (field id byte + 7x padding, ((string + NUL) + NUL + signature string 's') */
-                p = message_extend_fields(m, 8, 1 + 7 + l + 1 + 1 + 1, true);
-                if (!p)
-                        return -ENOMEM;
-
-                p[0] = h;
-                memset(p+1, 0, 7);
-                memcpy(p+8, s, l);
-                p[8+l] = 0;
-                p[8+l+1] = 0;
-                p[8+l+2] = type;
-
-                if (ret)
-                        *ret = (char*) p + 8;
-
-        } else {
-                /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
-                p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
-                if (!p)
-                        return -ENOMEM;
-
-                p[0] = h;
-                p[1] = 1;
-                p[2] = type;
-                p[3] = 0;
-
-                ((uint32_t*) p)[1] = l;
-                memcpy(p + 8, s, l + 1);
-
-                if (ret)
-                        *ret = (char*) p + 8;
-        }
-
-        return 0;
-}
-
-static int message_append_field_signature(
-                sd_bus_message *m,
-                uint8_t h,
-                const char *s,
-                const char **ret) {
-
-        size_t l;
-        uint8_t *p;
-
-        assert(m);
-
-        /* dbus1 doesn't allow signatures over 32bit, let's enforce
-         * this globally, to not risk convertability */
-        l = strlen(s);
-        if (l > 255)
-                return -EINVAL;
-
-        /* Signature "(yv)" where the variant contains "g" */
-
-        if (BUS_MESSAGE_IS_GVARIANT(m))
-                /* For gvariant the serialization is the same as for normal strings */
-                return message_append_field_string(m, h, 'g', s, ret);
-        else {
-                /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
-                p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
-                if (!p)
-                        return -ENOMEM;
-
-                p[0] = h;
-                p[1] = 1;
-                p[2] = SD_BUS_TYPE_SIGNATURE;
-                p[3] = 0;
-                p[4] = l;
-                memcpy(p + 5, s, l + 1);
-
-                if (ret)
-                        *ret = (const char*) p + 5;
-        }
-
-        return 0;
-}
-
-static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) {
-        uint8_t *p;
-
-        assert(m);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                /* (field id byte + 7x padding + ((value + NUL + signature string 'u') */
-
-                p = message_extend_fields(m, 8, 1 + 7 + 4 + 1 + 1, true);
-                if (!p)
-                        return -ENOMEM;
-
-                p[0] = h;
-                memset(p+1, 0, 7);
-                *((uint32_t*) (p + 8)) = x;
-                p[12] = 0;
-                p[13] = 'u';
-        } else {
-                /* (field id byte + (signature length + signature 'u' + NUL) + value) */
-                p = message_extend_fields(m, 8, 4 + 4, false);
-                if (!p)
-                        return -ENOMEM;
-
-                p[0] = h;
-                p[1] = 1;
-                p[2] = SD_BUS_TYPE_UINT32;
-                p[3] = 0;
-
-                ((uint32_t*) p)[1] = x;
-        }
-
-        return 0;
-}
-
-int bus_message_from_header(
-                sd_bus *bus,
-                void *buffer,
-                size_t length,
-                int *fds,
-                unsigned n_fds,
-                const struct ucred *ucred,
-                const char *label,
-                size_t extra,
-                sd_bus_message **ret) {
-
-        sd_bus_message *m;
-        struct bus_header *h;
-        size_t a, label_sz;
-
-        assert(buffer || length <= 0);
-        assert(fds || n_fds <= 0);
-        assert(ret);
-
-        if (length < sizeof(struct bus_header))
-                return -EBADMSG;
-
-        h = buffer;
-        if (h->version != 1 &&
-            h->version != 2)
-                return -EBADMSG;
-
-        if (h->serial == 0)
-                return -EBADMSG;
-
-        if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
-                return -EBADMSG;
-
-        if (h->endian != BUS_LITTLE_ENDIAN &&
-            h->endian != BUS_BIG_ENDIAN)
-                return -EBADMSG;
-
-        a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
-
-        if (label) {
-                label_sz = strlen(label);
-                a += label_sz + 1;
-        }
-
-        m = malloc0(a);
-        if (!m)
-                return -ENOMEM;
-
-        m->n_ref = 1;
-        m->sealed = true;
-        m->header = h;
-        m->fds = fds;
-        m->n_fds = n_fds;
-
-        if (ucred) {
-                m->creds.uid = ucred->uid;
-                m->creds.pid = ucred->pid;
-                m->creds.gid = ucred->gid;
-                m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID;
-        }
-
-        if (label) {
-                m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
-                memcpy(m->creds.label, label, label_sz + 1);
-
-                m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
-        }
-
-        if (bus)
-                m->bus = sd_bus_ref(bus);
-
-        *ret = m;
-        return 0;
-}
-
-int bus_message_from_malloc(
-                sd_bus *bus,
-                void *buffer,
-                size_t length,
-                int *fds,
-                unsigned n_fds,
-                const struct ucred *ucred,
-                const char *label,
-                sd_bus_message **ret) {
-
-        sd_bus_message *m;
-        size_t sz;
-        int r;
-
-        r = bus_message_from_header(bus, buffer, length, fds, n_fds, ucred, label, 0, &m);
-        if (r < 0)
-                return r;
-
-        if (length != BUS_MESSAGE_SIZE(m)) {
-                r = -EBADMSG;
-                goto fail;
-        }
-
-        sz = length - sizeof(struct bus_header) - ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
-        if (sz > 0) {
-                m->n_body_parts = 1;
-                m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
-                m->body.size = sz;
-                m->body.sealed = true;
-                m->body.memfd = -1;
-        }
-
-        m->n_iovec = 1;
-        m->iovec = m->iovec_fixed;
-        m->iovec[0].iov_base = buffer;
-        m->iovec[0].iov_len = length;
-
-        r = bus_message_parse_fields(m);
-        if (r < 0)
-                goto fail;
-
-        /* We take possession of the memory and fds now */
-        m->free_header = true;
-        m->free_fds = true;
-
-        *ret = m;
-        return 0;
-
-fail:
-        message_free(m);
-        return r;
-}
-
-static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
-        sd_bus_message *m;
-
-        m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
-        if (!m)
-                return NULL;
-
-        m->n_ref = 1;
-        m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
-        m->header->endian = BUS_NATIVE_ENDIAN;
-        m->header->type = type;
-        m->header->version = bus ? bus->message_version : 1;
-        m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
-        m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
-
-        if (bus)
-                m->bus = sd_bus_ref(bus);
-
-        return m;
-}
-
-_public_ int sd_bus_message_new_signal(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_message **m) {
-
-        sd_bus_message *t;
-        int r;
-
-        assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(m, -EINVAL);
-
-        t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
-        if (!t)
-                return -ENOMEM;
-
-        t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
-
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
-        if (r < 0)
-                goto fail;
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
-        if (r < 0)
-                goto fail;
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
-        if (r < 0)
-                goto fail;
-
-        *m = t;
-        return 0;
-
-fail:
-        sd_bus_message_unref(t);
-        return r;
-}
-
-_public_ int sd_bus_message_new_method_call(
-                sd_bus *bus,
-                const char *destination,
-                const char *path,
-                const char *interface,
-                const char *member,
-                sd_bus_message **m) {
-
-        sd_bus_message *t;
-        int r;
-
-        assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
-        assert_return(!destination || service_name_is_valid(destination), -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
-        assert_return(member_name_is_valid(member), -EINVAL);
-        assert_return(m, -EINVAL);
-
-        t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
-        if (!t)
-                return -ENOMEM;
-
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
-        if (r < 0)
-                goto fail;
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
-        if (r < 0)
-                goto fail;
-
-        if (interface) {
-                r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
-                if (r < 0)
-                        goto fail;
-        }
-
-        if (destination) {
-                r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
-                if (r < 0)
-                        goto fail;
-        }
-
-        *m = t;
-        return 0;
-
-fail:
-        message_free(t);
-        return r;
-}
-
-static int message_new_reply(
-                sd_bus_message *call,
-                uint8_t type,
-                sd_bus_message **m) {
-
-        sd_bus_message *t;
-        int r;
-
-        assert_return(call, -EINVAL);
-        assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(!call->bus || call->bus->state != BUS_UNSET, -ENOTCONN);
-        assert_return(m, -EINVAL);
-
-        t = message_new(call->bus, type);
-        if (!t)
-                return -ENOMEM;
-
-        t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
-        t->reply_cookie = BUS_MESSAGE_COOKIE(call);
-
-        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
-        if (r < 0)
-                goto fail;
-
-        if (call->sender) {
-                r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
-                if (r < 0)
-                        goto fail;
-        }
-
-        t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
-        t->enforced_reply_signature = call->enforced_reply_signature;
-
-        *m = t;
-        return 0;
-
-fail:
-        message_free(t);
-        return r;
-}
-
-_public_ int sd_bus_message_new_method_return(
-                sd_bus_message *call,
-                sd_bus_message **m) {
-
-        return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
-}
-
-_public_ int sd_bus_message_new_method_error(
-                sd_bus_message *call,
-                const sd_bus_error *e,
-                sd_bus_message **m) {
-
-        sd_bus_message *t;
-        int r;
-
-        assert_return(sd_bus_error_is_set(e), -EINVAL);
-        assert_return(m, -EINVAL);
-
-        r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
-        if (r < 0)
-                return r;
-
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
-        if (r < 0)
-                goto fail;
-
-        if (e->message) {
-                r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
-                if (r < 0)
-                        goto fail;
-        }
-
-        t->error._need_free = -1;
-
-        *m = t;
-        return 0;
-
-fail:
-        message_free(t);
-        return r;
-}
-
-_public_ int sd_bus_message_new_method_errorf(
-                sd_bus_message *call,
-                sd_bus_message **m,
-                const char *name,
-                const char *format,
-                ...) {
-
-        _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        va_list ap;
-
-        assert_return(name, -EINVAL);
-        assert_return(m, -EINVAL);
-
-        va_start(ap, format);
-        bus_error_setfv(&error, name, format, ap);
-        va_end(ap);
-
-        return sd_bus_message_new_method_error(call, &error, m);
-}
-
-_public_ int sd_bus_message_new_method_errno(
-                sd_bus_message *call,
-                int error,
-                const sd_bus_error *p,
-                sd_bus_message **m) {
-
-        _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
-
-        if (sd_bus_error_is_set(p))
-                return sd_bus_message_new_method_error(call, p, m);
-
-        sd_bus_error_set_errno(&berror, error);
-
-        return sd_bus_message_new_method_error(call, &berror, m);
-}
-
-_public_ int sd_bus_message_new_method_errnof(
-                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;
-
-        va_start(ap, format);
-        bus_error_set_errnofv(&berror, error, format, ap);
-        va_end(ap);
-
-        return sd_bus_message_new_method_error(call, &berror, m);
-}
-
-int bus_message_new_synthetic_error(
-                sd_bus *bus,
-                uint64_t cookie,
-                const sd_bus_error *e,
-                sd_bus_message **m) {
-
-        sd_bus_message *t;
-        int r;
-
-        assert(sd_bus_error_is_set(e));
-        assert(m);
-
-        t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
-        if (!t)
-                return -ENOMEM;
-
-        t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
-        t->reply_cookie = cookie;
-
-        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
-        if (r < 0)
-                goto fail;
-
-        if (bus && bus->unique_name) {
-                r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
-                if (r < 0)
-                        goto fail;
-        }
-
-        r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
-        if (r < 0)
-                goto fail;
-
-        if (e->message) {
-                r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
-                if (r < 0)
-                        goto fail;
-        }
-
-        t->error._need_free = -1;
-
-        *m = t;
-        return 0;
-
-fail:
-        message_free(t);
-        return r;
-}
-
-_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        assert(m->n_ref > 0);
-        m->n_ref++;
-
-        return m;
-}
-
-_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
-
-        if (!m)
-                return NULL;
-
-        assert(m->n_ref > 0);
-        m->n_ref--;
-
-        if (m->n_ref <= 0)
-                message_free(m);
-
-        return NULL;
-}
-
-_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
-        assert_return(m, -EINVAL);
-        assert_return(type, -EINVAL);
-
-        *type = m->header->type;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
-        assert_return(m, -EINVAL);
-        assert_return(cookie, -EINVAL);
-        assert_return(m->header->serial != 0, -ENODATA);
-
-        *cookie = BUS_MESSAGE_COOKIE(m);
-        return 0;
-}
-
-_public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
-        assert_return(m, -EINVAL);
-        assert_return(cookie, -EINVAL);
-        assert_return(m->reply_cookie != 0, -ENODATA);
-
-        *cookie = m->reply_cookie;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
-        assert_return(m, -EINVAL);
-
-        return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
-}
-
-_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
-        assert_return(m, -EINVAL);
-
-        return !!(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
-}
-
-_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        return m->path;
-}
-
-_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        return m->interface;
-}
-
-_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        return m->member;
-}
-
-_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        return m->destination;
-}
-
-_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        return m->sender;
-}
-
-_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
-        assert_return(m, NULL);
-        assert_return(sd_bus_error_is_set(&m->error), NULL);
-
-        return &m->error;
-}
-
-_public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) {
-        assert_return(m, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(m->monotonic > 0, -ENODATA);
-
-        *usec = m->monotonic;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) {
-        assert_return(m, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(m->realtime > 0, -ENODATA);
-
-        *usec = m->realtime;
-        return 0;
-}
-
-_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        if (m->creds.mask == 0)
-                return NULL;
-
-        return &m->creds;
-}
-
-_public_ int sd_bus_message_is_signal(sd_bus_message *m,
-                                      const char *interface,
-                                      const char *member) {
-        assert_return(m, -EINVAL);
-
-        if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
-                return 0;
-
-        if (interface && (!m->interface || !streq(m->interface, interface)))
-                return 0;
-
-        if (member &&  (!m->member || !streq(m->member, member)))
-                return 0;
-
-        return 1;
-}
-
-_public_ int sd_bus_message_is_method_call(sd_bus_message *m,
-                                           const char *interface,
-                                           const char *member) {
-        assert_return(m, -EINVAL);
-
-        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
-                return 0;
-
-        if (interface && (!m->interface || !streq(m->interface, interface)))
-                return 0;
-
-        if (member &&  (!m->member || !streq(m->member, member)))
-                return 0;
-
-        return 1;
-}
-
-_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
-        assert_return(m, -EINVAL);
-
-        if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
-                return 0;
-
-        if (name && (!m->error.name || !streq(m->error.name, name)))
-                return 0;
-
-        return 1;
-}
-
-_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
-
-        if (b)
-                m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
-        else
-                m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
-
-        return 0;
-}
-
-_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-
-        if (b)
-                m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
-        else
-                m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
-
-        return 0;
-}
-
-static struct bus_container *message_get_container(sd_bus_message *m) {
-        assert(m);
-
-        if (m->n_containers == 0)
-                return &m->root_container;
-
-        assert(m->containers);
-        return m->containers + m->n_containers - 1;
-}
-
-struct bus_body_part *message_append_part(sd_bus_message *m) {
-        struct bus_body_part *part;
-
-        assert(m);
-
-        if (m->poisoned)
-                return NULL;
-
-        if (m->n_body_parts <= 0) {
-                part = &m->body;
-                zero(*part);
-        } else {
-                assert(m->body_end);
-
-                part = new0(struct bus_body_part, 1);
-                if (!part) {
-                        m->poisoned = true;
-                        return NULL;
-                }
-
-                m->body_end->next = part;
-        }
-
-        part->memfd = -1;
-        m->body_end = part;
-        m->n_body_parts ++;
-
-        return part;
-}
-
-static void part_zero(struct bus_body_part *part, size_t sz) {
-        assert(part);
-        assert(sz > 0);
-        assert(sz < 8);
-
-        /* All other fields can be left in their defaults */
-        assert(!part->data);
-        assert(part->memfd < 0);
-
-        part->size = sz;
-        part->is_zero = true;
-        part->sealed = true;
-}
-
-static int part_make_space(
-                struct sd_bus_message *m,
-                struct bus_body_part *part,
-                size_t sz,
-                void **q) {
-
-        void *n;
-        int r;
-
-        assert(m);
-        assert(part);
-        assert(!part->sealed);
-
-        if (m->poisoned)
-                return -ENOMEM;
-
-        if (!part->data && part->memfd < 0)
-                part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
-
-        if (part->memfd >= 0) {
-
-                if (part->allocated == 0 || sz > part->allocated) {
-                        uint64_t new_allocated;
-
-                        new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
-                        r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated);
-                        if (r < 0) {
-                                m->poisoned = true;
-                                return -errno;
-                        }
-
-                        part->allocated = new_allocated;
-                }
-
-                if (!part->data || sz > part->mapped) {
-                        size_t psz;
-
-                        psz = PAGE_ALIGN(sz > 0 ? sz : 1);
-                        if (part->mapped <= 0)
-                                n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
-                        else
-                                n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
-
-                        if (n == MAP_FAILED) {
-                                m->poisoned = true;
-                                return -errno;
-                        }
-
-                        part->mapped = psz;
-                        part->data = n;
-                }
-
-                part->munmap_this = true;
-        } else {
-                if (part->allocated == 0 || sz > part->allocated) {
-                        size_t new_allocated;
-
-                        new_allocated = sz > 0 ? 2 * sz : 64;
-                        n = realloc(part->data, new_allocated);
-                        if (!n) {
-                                m->poisoned = true;
-                                return -ENOMEM;
-                        }
-
-                        part->data = n;
-                        part->allocated = new_allocated;
-                        part->free_this = true;
-                }
-        }
-
-        if (q)
-                *q = part->data ? (uint8_t*) part->data + part->size : NULL;
-
-        part->size = sz;
-        return 0;
-}
-
-static int message_add_offset(sd_bus_message *m, size_t offset) {
-        struct bus_container *c;
-
-        assert(m);
-        assert(BUS_MESSAGE_IS_GVARIANT(m));
-
-        /* Add offset to current container, unless this is the first
-         * item in it, which will have the 0 offset, which we can
-         * ignore. */
-        c = message_get_container(m);
-
-        if (!c->need_offsets)
-                return 0;
-
-        if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
-                return -ENOMEM;
-
-        c->offsets[c->n_offsets++] = offset;
-        return 0;
-}
-
-static void message_extend_containers(sd_bus_message *m, size_t expand) {
-        struct bus_container *c;
-
-        assert(m);
-
-        if (expand <= 0)
-                return;
-
-        /* Update counters */
-        for (c = m->containers; c < m->containers + m->n_containers; c++) {
-
-                if (c->array_size)
-                        *c->array_size += expand;
-        }
-}
-
-static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
-        size_t start_body, end_body, padding, added;
-        void *p;
-        int r;
-
-        assert(m);
-        assert(align > 0);
-        assert(!m->sealed);
-
-        if (m->poisoned)
-                return NULL;
-
-        start_body = ALIGN_TO((size_t) m->header->body_size, align);
-        end_body = start_body + sz;
-
-        padding = start_body - m->header->body_size;
-        added = padding + sz;
-
-        /* Check for 32bit overflows */
-        if (end_body > (size_t) ((uint32_t) -1)) {
-                m->poisoned = true;
-                return NULL;
-        }
-
-        if (added > 0) {
-                struct bus_body_part *part = NULL;
-                bool add_new_part;
-
-                add_new_part =
-                        m->n_body_parts <= 0 ||
-                        m->body_end->sealed ||
-                        padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
-
-                if (add_new_part) {
-                        if (padding > 0) {
-                                part = message_append_part(m);
-                                if (!part)
-                                        return NULL;
-
-                                part_zero(part, padding);
-                        }
-
-                        part = message_append_part(m);
-                        if (!part)
-                                return NULL;
-
-                        r = part_make_space(m, part, sz, &p);
-                        if (r < 0)
-                                return NULL;
-                } else {
-                        struct bus_container *c;
-                        void *op;
-                        size_t os, start_part, end_part;
-
-                        part = m->body_end;
-                        op = part->data;
-                        os = part->size;
-
-                        start_part = ALIGN_TO(part->size, align);
-                        end_part = start_part + sz;
-
-                        r = part_make_space(m, part, end_part, &p);
-                        if (r < 0)
-                                return NULL;
-
-                        if (padding > 0) {
-                                memset(p, 0, padding);
-                                p = (uint8_t*) p + padding;
-                        }
-
-                        /* Readjust pointers */
-                        for (c = m->containers; c < m->containers + m->n_containers; c++)
-                                c->array_size = adjust_pointer(c->array_size, op, os, part->data);
-
-                        m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
-                }
-        } else
-                /* Return something that is not NULL and is aligned */
-                p = (uint8_t *) NULL + align;
-
-        m->header->body_size = end_body;
-        message_extend_containers(m, added);
-
-        if (add_offset) {
-                r = message_add_offset(m, end_body);
-                if (r < 0) {
-                        m->poisoned = true;
-                        return NULL;
-                }
-        }
-
-        return p;
-}
-
-static int message_push_fd(sd_bus_message *m, int fd) {
-        int *f, copy;
-
-        assert(m);
-
-        if (fd < 0)
-                return -EINVAL;
-
-        if (!m->allow_fds)
-                return -ENOTSUP;
-
-        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-        if (copy < 0)
-                return -errno;
-
-        f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
-        if (!f) {
-                m->poisoned = true;
-                close_nointr_nofail(copy);
-                return -ENOMEM;
-        }
-
-        m->fds = f;
-        m->fds[m->n_fds] = copy;
-        m->free_fds = true;
-
-        return copy;
-}
-
-int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
-        _cleanup_close_ int fd = -1;
-        struct bus_container *c;
-        ssize_t align, sz;
-        void *a;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(bus_type_is_basic(type), -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        c = message_get_container(m);
-
-        if (c->signature && c->signature[c->index]) {
-                /* Container signature is already set */
-
-                if (c->signature[c->index] != type)
-                        return -ENXIO;
-        } else {
-                char *e;
-
-                /* Maybe we can append to the signature? But only if this is the top-level container*/
-                if (c->enclosing != 0)
-                        return -ENXIO;
-
-                e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
-                if (!e) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-        }
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                uint8_t u8;
-                uint32_t u32;
-
-                switch (type) {
-
-                case SD_BUS_TYPE_SIGNATURE:
-                case SD_BUS_TYPE_STRING:
-                        p = strempty(p);
-
-                        /* Fall through... */
-                case SD_BUS_TYPE_OBJECT_PATH:
-                        if (!p)
-                                return -EINVAL;
-
-                        align = 1;
-                        sz = strlen(p) + 1;
-                        break;
-
-                case SD_BUS_TYPE_BOOLEAN:
-
-                        u8 = p && *(int*) p;
-                        p = &u8;
-
-                        align = sz = 1;
-                        break;
-
-                case SD_BUS_TYPE_UNIX_FD:
-
-                        if (!p)
-                                return -EINVAL;
-
-                        fd = message_push_fd(m, *(int*) p);
-                        if (fd < 0)
-                                return fd;
-
-                        u32 = m->n_fds;
-                        p = &u32;
-
-                        align = sz = 4;
-                        break;
-
-                default:
-                        align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
-                        sz = bus_gvariant_get_size(CHAR_TO_STR(type));
-                        break;
-                }
-
-                assert(align > 0);
-                assert(sz > 0);
-
-                a = message_extend_body(m, align, sz, true);
-                if (!a)
-                        return -ENOMEM;
-
-                memcpy(a, p, sz);
-
-                if (stored)
-                        *stored = (const uint8_t*) a;
-
-        } else {
-                uint32_t u32;
-
-                switch (type) {
-
-                case SD_BUS_TYPE_STRING:
-                        /* To make things easy we'll serialize a NULL string
-                         * into the empty string */
-                        p = strempty(p);
-
-                        /* Fall through... */
-                case SD_BUS_TYPE_OBJECT_PATH:
-
-                        if (!p)
-                                return -EINVAL;
-
-                        align = 4;
-                        sz = 4 + strlen(p) + 1;
-                        break;
-
-                case SD_BUS_TYPE_SIGNATURE:
-
-                        p = strempty(p);
-
-                        align = 1;
-                        sz = 1 + strlen(p) + 1;
-                        break;
-
-                case SD_BUS_TYPE_BOOLEAN:
-
-                        u32 = p && *(int*) p;
-                        p = &u32;
-
-                        align = sz = 4;
-                        break;
-
-                case SD_BUS_TYPE_UNIX_FD:
-
-                        if (!p)
-                                return -EINVAL;
-
-                        fd = message_push_fd(m, *(int*) p);
-                        if (fd < 0)
-                                return fd;
-
-                        u32 = m->n_fds;
-                        p = &u32;
-
-                        align = sz = 4;
-                        break;
-
-                default:
-                        align = bus_type_get_alignment(type);
-                        sz = bus_type_get_size(type);
-                        break;
-                }
-
-                assert(align > 0);
-                assert(sz > 0);
-
-                a = message_extend_body(m, align, sz, false);
-                if (!a)
-                        return -ENOMEM;
-
-                if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
-                        *(uint32_t*) a = sz - 5;
-                        memcpy((uint8_t*) a + 4, p, sz - 4);
-
-                        if (stored)
-                                *stored = (const uint8_t*) a + 4;
-
-                } else if (type == SD_BUS_TYPE_SIGNATURE) {
-                        *(uint8_t*) a = sz - 2;
-                        memcpy((uint8_t*) a + 1, p, sz - 1);
-
-                        if (stored)
-                                *stored = (const uint8_t*) a + 1;
-                } else {
-                        memcpy(a, p, sz);
-
-                        if (stored)
-                                *stored = a;
-                }
-        }
-
-        if (type == SD_BUS_TYPE_UNIX_FD)
-                m->n_fds ++;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index++;
-
-        fd = -1;
-        return 0;
-}
-
-_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
-        return message_append_basic(m, type, p, NULL);
-}
-
-_public_ int sd_bus_message_append_string_space(
-                sd_bus_message *m,
-                size_t size,
-                char **s) {
-
-        struct bus_container *c;
-        void *a;
-
-        assert_return(m, -EINVAL);
-        assert_return(s, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->poisoned, -ESTALE);
-
-        c = message_get_container(m);
-
-        if (c->signature && c->signature[c->index]) {
-                /* Container signature is already set */
-
-                if (c->signature[c->index] != SD_BUS_TYPE_STRING)
-                        return -ENXIO;
-        } else {
-                char *e;
-
-                /* Maybe we can append to the signature? But only if this is the top-level container*/
-                if (c->enclosing != 0)
-                        return -ENXIO;
-
-                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
-                if (!e) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-        }
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                a = message_extend_body(m, 1, size + 1, true);
-                if (!a)
-                        return -ENOMEM;
-
-                *s = a;
-        } else {
-                a = message_extend_body(m, 4, 4 + size + 1, false);
-                if (!a)
-                        return -ENOMEM;
-
-                *(uint32_t*) a = size;
-                *s = (char*) a + 4;
-        }
-
-        (*s)[size] = 0;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index++;
-
-        return 0;
-}
-
-_public_ int sd_bus_message_append_string_iovec(
-                sd_bus_message *m,
-                const struct iovec *iov,
-                unsigned n) {
-
-        size_t size;
-        unsigned i;
-        char *p;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(iov || n == 0, -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        size = IOVEC_TOTAL_SIZE(iov, n);
-
-        r = sd_bus_message_append_string_space(m, size, &p);
-        if (r < 0)
-                return r;
-
-        for (i = 0; i < n; i++) {
-
-                if (iov[i].iov_base)
-                        memcpy(p, iov[i].iov_base, iov[i].iov_len);
-                else
-                        memset(p, ' ', iov[i].iov_len);
-
-                p += iov[i].iov_len;
-        }
-
-        return 0;
-}
-
-static int bus_message_open_array(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                uint32_t **array_size,
-                size_t *begin,
-                bool *need_offsets) {
-
-        unsigned nindex;
-        int alignment, r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(array_size);
-        assert(begin);
-        assert(need_offsets);
-
-        if (!signature_is_single(contents, true))
-                return -EINVAL;
-
-        if (c->signature && c->signature[c->index]) {
-
-                /* Verify the existing signature */
-
-                if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
-                        return -ENXIO;
-
-                if (!startswith(c->signature + c->index + 1, contents))
-                        return -ENXIO;
-
-                nindex = c->index + 1 + strlen(contents);
-        } else {
-                char *e;
-
-                if (c->enclosing != 0)
-                        return -ENXIO;
-
-                /* Extend the existing signature */
-
-                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
-                if (!e) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-
-                nindex = e - c->signature;
-        }
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                alignment = bus_gvariant_get_alignment(contents);
-                if (alignment < 0)
-                        return alignment;
-
-                /* Add alignment padding and add to offset list */
-                if (!message_extend_body(m, alignment, 0, false))
-                        return -ENOMEM;
-
-                r = bus_gvariant_is_fixed_size(contents);
-                if (r < 0)
-                        return r;
-
-                *begin = m->header->body_size;
-                *need_offsets = r == 0;
-        } else {
-                void *a, *op;
-                size_t os;
-                struct bus_body_part *o;
-
-                alignment = bus_type_get_alignment(contents[0]);
-                if (alignment < 0)
-                        return alignment;
-
-                a = message_extend_body(m, 4, 4, false);
-                if (!a)
-                        return -ENOMEM;
-
-                o = m->body_end;
-                op = m->body_end->data;
-                os = m->body_end->size;
-
-                /* Add alignment between size and first element */
-                if (!message_extend_body(m, alignment, 0, false))
-                        return -ENOMEM;
-
-                /* location of array size might have changed so let's readjust a */
-                if (o == m->body_end)
-                        a = adjust_pointer(a, op, os, m->body_end->data);
-
-                *(uint32_t*) a = 0;
-                *array_size = a;
-        }
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index = nindex;
-
-        return 0;
-}
-
-static int bus_message_open_variant(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents) {
-
-        assert(m);
-        assert(c);
-        assert(contents);
-
-        if (!signature_is_single(contents, false))
-                return -EINVAL;
-
-        if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
-                return -EINVAL;
-
-        if (c->signature && c->signature[c->index]) {
-
-                if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
-                        return -ENXIO;
-
-        } else {
-                char *e;
-
-                if (c->enclosing != 0)
-                        return -ENXIO;
-
-                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
-                if (!e) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-        }
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                /* Variants are always aligned to 8 */
-
-                if (!message_extend_body(m, 8, 0, false))
-                        return -ENOMEM;
-
-        } else {
-                size_t l;
-                void *a;
-
-                l = strlen(contents);
-                a = message_extend_body(m, 1, 1 + l + 1, false);
-                if (!a)
-                        return -ENOMEM;
-
-                *(uint8_t*) a = l;
-                memcpy((uint8_t*) a + 1, contents, l + 1);
-        }
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index++;
-
-        return 0;
-}
-
-static int bus_message_open_struct(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                size_t *begin,
-                bool *need_offsets) {
-
-        size_t nindex;
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(begin);
-        assert(need_offsets);
-
-        if (!signature_is_valid(contents, false))
-                return -EINVAL;
-
-        if (c->signature && c->signature[c->index]) {
-                size_t l;
-
-                l = strlen(contents);
-
-                if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
-                    !startswith(c->signature + c->index + 1, contents) ||
-                    c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
-                        return -ENXIO;
-
-                nindex = c->index + 1 + l + 1;
-        } else {
-                char *e;
-
-                if (c->enclosing != 0)
-                        return -ENXIO;
-
-                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
-                if (!e) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-
-                nindex = e - c->signature;
-        }
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                int alignment;
-
-                alignment = bus_gvariant_get_alignment(contents);
-                if (alignment < 0)
-                        return alignment;
-
-                if (!message_extend_body(m, alignment, 0, false))
-                        return -ENOMEM;
-
-                r = bus_gvariant_is_fixed_size(contents);
-                if (r < 0)
-                        return r;
-
-                *begin = m->header->body_size;
-                *need_offsets = r == 0;
-        } else {
-                /* Align contents to 8 byte boundary */
-                if (!message_extend_body(m, 8, 0, false))
-                        return -ENOMEM;
-        }
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index = nindex;
-
-        return 0;
-}
-
-static int bus_message_open_dict_entry(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                size_t *begin,
-                bool *need_offsets) {
-
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(begin);
-        assert(need_offsets);
-
-        if (!signature_is_pair(contents))
-                return -EINVAL;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                return -ENXIO;
-
-        if (c->signature && c->signature[c->index]) {
-                size_t l;
-
-                l = strlen(contents);
-
-                if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
-                    !startswith(c->signature + c->index + 1, contents) ||
-                    c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
-                        return -ENXIO;
-        } else
-                return -ENXIO;
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                int alignment;
-
-                alignment = bus_gvariant_get_alignment(contents);
-                if (alignment < 0)
-                        return alignment;
-
-                if (!message_extend_body(m, alignment, 0, false))
-                        return -ENOMEM;
-
-                r = bus_gvariant_is_fixed_size(contents);
-                if (r < 0)
-                        return r;
-
-                *begin = m->header->body_size;
-                *need_offsets = r == 0;
-        } else {
-                /* Align contents to 8 byte boundary */
-                if (!message_extend_body(m, 8, 0, false))
-                        return -ENOMEM;
-        }
-
-        return 0;
-}
-
-_public_ int sd_bus_message_open_container(
-                sd_bus_message *m,
-                char type,
-                const char *contents) {
-
-        struct bus_container *c, *w;
-        uint32_t *array_size = NULL;
-        char *signature;
-        size_t before, begin;
-        bool need_offsets = false;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(contents, -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        /* Make sure we have space for one more container */
-        if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
-                m->poisoned = true;
-                return -ENOMEM;
-        }
-
-        c = message_get_container(m);
-
-        signature = strdup(contents);
-        if (!signature) {
-                m->poisoned = true;
-                return -ENOMEM;
-        }
-
-        /* Save old index in the parent container, in case we have to
-         * abort this container */
-        c->saved_index = c->index;
-        before = m->header->body_size;
-
-        if (type == SD_BUS_TYPE_ARRAY)
-                r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
-        else if (type == SD_BUS_TYPE_VARIANT)
-                r = bus_message_open_variant(m, c, contents);
-        else if (type == SD_BUS_TYPE_STRUCT)
-                r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
-        else if (type == SD_BUS_TYPE_DICT_ENTRY)
-                r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
-        else
-                r = -EINVAL;
-
-        if (r < 0) {
-                free(signature);
-                return r;
-        }
-
-        /* OK, let's fill it in */
-        w = m->containers + m->n_containers++;
-        w->enclosing = type;
-        w->signature = signature;
-        w->index = 0;
-        w->array_size = array_size;
-        w->before = before;
-        w->begin = begin;
-        w->n_offsets = w->offsets_allocated = 0;
-        w->offsets = NULL;
-        w->need_offsets = need_offsets;
-
-        return 0;
-}
-
-static size_t determine_word_size(size_t sz, size_t extra) {
-        if (sz + extra <= 0xFF)
-                return 1;
-        else if (sz + extra*2 <= 0xFFFF)
-                return 2;
-        else if (sz + extra*4 <= 0xFFFFFFFF)
-                return 4;
-        else
-                return 8;
-}
-
-static size_t read_word_le(void *p, size_t sz) {
-        union {
-                uint16_t u16;
-                uint32_t u32;
-                uint64_t u64;
-        } x;
-
-        assert(p);
-
-        if (sz == 1)
-                return *(uint8_t*) p;
-
-        memcpy(&x, p, sz);
-
-        if (sz == 2)
-                return le16toh(x.u16);
-        else if (sz == 4)
-                return le32toh(x.u32);
-        else if (sz == 8)
-                return le64toh(x.u64);
-
-        assert_not_reached("unknown word width");
-}
-
-static void write_word_le(void *p, size_t sz, size_t value) {
-        union {
-                uint16_t u16;
-                uint32_t u32;
-                uint64_t u64;
-        } x;
-
-        assert(p);
-        assert(sz == 8 || (value < (1ULL << (sz*8))));
-
-        if (sz == 1) {
-                *(uint8_t*) p = value;
-                return;
-        } else if (sz == 2)
-                x.u16 = htole16((uint16_t) value);
-        else if (sz == 4)
-                x.u32 = htole32((uint32_t) value);
-        else if (sz == 8)
-                x.u64 = htole64((uint64_t) value);
-        else
-                assert_not_reached("unknown word width");
-
-        memcpy(p, &x, sz);
-}
-
-static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
-
-        assert(m);
-        assert(c);
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m))
-                return 0;
-
-        if (c->need_offsets) {
-                size_t payload, sz, i;
-                uint8_t *a;
-
-                /* Variable-width arrays */
-
-                payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
-                sz = determine_word_size(payload, c->n_offsets);
-
-                a = message_extend_body(m, 1, sz * c->n_offsets, true);
-                if (!a)
-                        return -ENOMEM;
-
-                for (i = 0; i < c->n_offsets; i++)
-                        write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
-        } else {
-                void *a;
-
-                /* Fixed-width or empty arrays */
-
-                a = message_extend_body(m, 1, 0, true); /* let's add offset to parent */
-                if (!a)
-                        return -ENOMEM;
-        }
-
-        return 0;
-}
-
-static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
-        uint8_t *a;
-        size_t l;
-
-        assert(m);
-        assert(c);
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m))
-                return 0;
-
-        l = strlen(c->signature);
-
-        a = message_extend_body(m, 1, 1 + l, true);
-        if (!a)
-                return -ENOMEM;
-
-        a[0] = 0;
-        memcpy(a+1, c->signature, l);
-
-        return 0;
-}
-
-static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
-        size_t n_variable = 0;
-        unsigned i = 0;
-        const char *p;
-        uint8_t *a;
-        int r;
-
-        assert(m);
-        assert(c);
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m))
-                return 0;
-
-        p = strempty(c->signature);
-        while (*p != 0) {
-                size_t n;
-
-                r = signature_element_length(p, &n);
-                if (r < 0)
-                        return r;
-                else {
-                        char t[n+1];
-
-                        memcpy(t, p, n);
-                        t[n] = 0;
-
-                        r = bus_gvariant_is_fixed_size(t);
-                        if (r < 0)
-                                return r;
-                }
-
-                assert(!c->need_offsets || i <= c->n_offsets);
-
-                /* We need to add an offset for each item that has a
-                 * variable size and that is not the last one in the
-                 * list */
-                if (r == 0 && p[n] != 0)
-                        n_variable++;
-
-                i++;
-                p += n;
-        }
-
-        assert(!c->need_offsets || i == c->n_offsets);
-        assert(c->need_offsets || n_variable == 0);
-
-        if (n_variable <= 0) {
-                a = message_extend_body(m, 1, 0, add_offset);
-                if (!a)
-                        return -ENOMEM;
-        } else {
-                size_t sz;
-                unsigned j;
-
-                assert(c->offsets[c->n_offsets-1] == m->header->body_size);
-
-                sz = determine_word_size(m->header->body_size - c->begin, n_variable);
-
-                a = message_extend_body(m, 1, sz * n_variable, add_offset);
-                if (!a)
-                        return -ENOMEM;
-
-                p = strempty(c->signature);
-                for (i = 0, j = 0; i < c->n_offsets; i++) {
-                        unsigned k;
-                        size_t n;
-
-                        r = signature_element_length(p, &n);
-                        if (r < 0)
-                                return r;
-                        else {
-                                char t[n+1];
-
-                                memcpy(t, p, n);
-                                t[n] = 0;
-
-                                p += n;
-
-                                r = bus_gvariant_is_fixed_size(t);
-                                if (r < 0)
-                                        return r;
-                                if (r > 0 || p[0] == 0)
-                                        continue;
-                        }
-
-                        k = n_variable - 1 - j;
-
-                        write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
-
-                        j++;
-                }
-        }
-
-        return 0;
-}
-
-_public_ int sd_bus_message_close_container(sd_bus_message *m) {
-        struct bus_container *c;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(m->n_containers > 0, -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        c = message_get_container(m);
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                if (c->signature && c->signature[c->index] != 0)
-                        return -EINVAL;
-
-        m->n_containers--;
-
-        if (c->enclosing == SD_BUS_TYPE_ARRAY)
-                r = bus_message_close_array(m, c);
-        else if (c->enclosing == SD_BUS_TYPE_VARIANT)
-                r = bus_message_close_variant(m, c);
-        else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
-                r = bus_message_close_struct(m, c, true);
-        else
-                assert_not_reached("Unknown container type");
-
-        free(c->signature);
-        free(c->offsets);
-
-        return r;
-}
-
-typedef struct {
-        const char *types;
-        unsigned n_struct;
-        unsigned n_array;
-} TypeStack;
-
-static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
-        assert(stack);
-        assert(max > 0);
-
-        if (*i >= max)
-                return -EINVAL;
-
-        stack[*i].types = types;
-        stack[*i].n_struct = n_struct;
-        stack[*i].n_array = n_array;
-        (*i)++;
-
-        return 0;
-}
-
-static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
-        assert(stack);
-        assert(max > 0);
-        assert(types);
-        assert(n_struct);
-        assert(n_array);
-
-        if (*i <= 0)
-                return 0;
-
-        (*i)--;
-        *types = stack[*i].types;
-        *n_struct = stack[*i].n_struct;
-        *n_array = stack[*i].n_array;
-
-        return 1;
-}
-
-int bus_message_append_ap(
-                sd_bus_message *m,
-                const char *types,
-                va_list ap) {
-
-        unsigned n_array, n_struct;
-        TypeStack stack[BUS_CONTAINER_DEPTH];
-        unsigned stack_ptr = 0;
-        int r;
-
-        assert(m);
-
-        if (!types)
-                return 0;
-
-        n_array = (unsigned) -1;
-        n_struct = strlen(types);
-
-        for (;;) {
-                const char *t;
-
-                if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
-                        r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                break;
-
-                        r = sd_bus_message_close_container(m);
-                        if (r < 0)
-                                return r;
-
-                        continue;
-                }
-
-                t = types;
-                if (n_array != (unsigned) -1)
-                        n_array --;
-                else {
-                        types ++;
-                        n_struct--;
-                }
-
-                switch (*t) {
-
-                case SD_BUS_TYPE_BYTE: {
-                        uint8_t x;
-
-                        x = (uint8_t) va_arg(ap, int);
-                        r = sd_bus_message_append_basic(m, *t, &x);
-                        break;
-                }
-
-                case SD_BUS_TYPE_BOOLEAN:
-                case SD_BUS_TYPE_INT32:
-                case SD_BUS_TYPE_UINT32:
-                case SD_BUS_TYPE_UNIX_FD: {
-                        uint32_t x;
-
-                        /* We assume a boolean is the same as int32_t */
-                        assert_cc(sizeof(int32_t) == sizeof(int));
-
-                        x = va_arg(ap, uint32_t);
-                        r = sd_bus_message_append_basic(m, *t, &x);
-                        break;
-                }
-
-                case SD_BUS_TYPE_INT16:
-                case SD_BUS_TYPE_UINT16: {
-                        uint16_t x;
-
-                        x = (uint16_t) va_arg(ap, int);
-                        r = sd_bus_message_append_basic(m, *t, &x);
-                        break;
-                }
-
-                case SD_BUS_TYPE_INT64:
-                case SD_BUS_TYPE_UINT64:
-                case SD_BUS_TYPE_DOUBLE: {
-                        uint64_t x;
-
-                        x = va_arg(ap, uint64_t);
-                        r = sd_bus_message_append_basic(m, *t, &x);
-                        break;
-                }
-
-                case SD_BUS_TYPE_STRING:
-                case SD_BUS_TYPE_OBJECT_PATH:
-                case SD_BUS_TYPE_SIGNATURE: {
-                        const char *x;
-
-                        x = va_arg(ap, const char*);
-                        r = sd_bus_message_append_basic(m, *t, x);
-                        break;
-                }
-
-                case SD_BUS_TYPE_ARRAY: {
-                        size_t k;
-
-                        r = signature_element_length(t + 1, &k);
-                        if (r < 0)
-                                return r;
-
-                        {
-                                char s[k + 1];
-                                memcpy(s, t + 1, k);
-                                s[k] = 0;
-
-                                r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        if (n_array == (unsigned) -1) {
-                                types += k;
-                                n_struct -= k;
-                        }
-
-                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
-                        if (r < 0)
-                                return r;
-
-                        types = t + 1;
-                        n_struct = k;
-                        n_array = va_arg(ap, unsigned);
-
-                        break;
-                }
-
-                case SD_BUS_TYPE_VARIANT: {
-                        const char *s;
-
-                        s = va_arg(ap, const char*);
-                        if (!s)
-                                return -EINVAL;
-
-                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
-                        if (r < 0)
-                                return r;
-
-                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
-                        if (r < 0)
-                                return r;
-
-                        types = s;
-                        n_struct = strlen(s);
-                        n_array = (unsigned) -1;
-
-                        break;
-                }
-
-                case SD_BUS_TYPE_STRUCT_BEGIN:
-                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
-                        size_t k;
-
-                        r = signature_element_length(t, &k);
-                        if (r < 0)
-                                return r;
-
-                        {
-                                char s[k - 1];
-
-                                memcpy(s, t + 1, k - 2);
-                                s[k - 2] = 0;
-
-                                r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        if (n_array == (unsigned) -1) {
-                                types += k - 1;
-                                n_struct -= k - 1;
-                        }
-
-                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
-                        if (r < 0)
-                                return r;
-
-                        types = t + 1;
-                        n_struct = k - 2;
-                        n_array = (unsigned) -1;
-
-                        break;
-                }
-
-                default:
-                        r = -EINVAL;
-                }
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 1;
-}
-
-_public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
-        va_list ap;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(types, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->poisoned, -ESTALE);
-
-        va_start(ap, types);
-        r = bus_message_append_ap(m, types, ap);
-        va_end(ap);
-
-        return r;
-}
-
-_public_ int sd_bus_message_append_array_space(
-                sd_bus_message *m,
-                char type,
-                size_t size,
-                void **ptr) {
-
-        ssize_t align, sz;
-        void *a;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
-        assert_return(ptr || size == 0, -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        /* alignment and size of the trivial types (except bool) is
-         * identical for gvariant and dbus1 marshalling */
-        align = bus_type_get_alignment(type);
-        sz = bus_type_get_size(type);
-
-        assert_se(align > 0);
-        assert_se(sz > 0);
-
-        if (size % sz != 0)
-                return -EINVAL;
-
-        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
-        if (r < 0)
-                return r;
-
-        a = message_extend_body(m, align, size, false);
-        if (!a)
-                return -ENOMEM;
-
-        r = sd_bus_message_close_container(m);
-        if (r < 0)
-                return r;
-
-        *ptr = a;
-        return 0;
-}
-
-_public_ int sd_bus_message_append_array(sd_bus_message *m,
-                                         char type,
-                                         const void *ptr,
-                                         size_t size) {
-        int r;
-        void *p;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(bus_type_is_trivial(type), -EINVAL);
-        assert_return(ptr || size == 0, -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        r = sd_bus_message_append_array_space(m, type, size, &p);
-        if (r < 0)
-                return r;
-
-        if (size > 0)
-                memcpy(p, ptr, size);
-
-        return 0;
-}
-
-_public_ int sd_bus_message_append_array_iovec(
-                sd_bus_message *m,
-                char type,
-                const struct iovec *iov,
-                unsigned n) {
-
-        size_t size;
-        unsigned i;
-        void *p;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(bus_type_is_trivial(type), -EINVAL);
-        assert_return(iov || n == 0, -EINVAL);
-        assert_return(!m->poisoned, -ESTALE);
-
-        size = IOVEC_TOTAL_SIZE(iov, n);
-
-        r = sd_bus_message_append_array_space(m, type, size, &p);
-        if (r < 0)
-                return r;
-
-        for (i = 0; i < n; i++) {
-
-                if (iov[i].iov_base)
-                        memcpy(p, iov[i].iov_base, iov[i].iov_len);
-                else
-                        memset(p, 0, iov[i].iov_len);
-
-                p = (uint8_t*) p + iov[i].iov_len;
-        }
-
-        return 0;
-}
-
-_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
-                                               char type,
-                                               sd_memfd *memfd) {
-        _cleanup_close_ int copy_fd = -1;
-        struct bus_body_part *part;
-        ssize_t align, sz;
-        uint64_t size;
-        void *a;
-        int r;
-
-        if (!m)
-                return -EINVAL;
-        if (!memfd)
-                return -EINVAL;
-        if (m->sealed)
-                return -EPERM;
-        if (!bus_type_is_trivial(type))
-                return -EINVAL;
-        if (m->poisoned)
-                return -ESTALE;
-
-        r = sd_memfd_set_sealed(memfd, true);
-        if (r < 0)
-                return r;
-
-        copy_fd = sd_memfd_dup_fd(memfd);
-        if (copy_fd < 0)
-                return copy_fd;
-
-        r = sd_memfd_get_size(memfd, &size);
-        if (r < 0)
-                return r;
-
-        align = bus_type_get_alignment(type);
-        sz = bus_type_get_size(type);
-
-        assert_se(align > 0);
-        assert_se(sz > 0);
-
-        if (size % sz != 0)
-                return -EINVAL;
-
-        if (size > (uint64_t) (uint32_t) -1)
-                return -EINVAL;
-
-        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
-        if (r < 0)
-                return r;
-
-        a = message_extend_body(m, align, 0, false);
-        if (!a)
-                return -ENOMEM;
-
-        part = message_append_part(m);
-        if (!part)
-                return -ENOMEM;
-
-        part->memfd = copy_fd;
-        part->sealed = true;
-        part->size = size;
-        copy_fd = -1;
-
-        m->header->body_size += size;
-        message_extend_containers(m, size);
-
-        return sd_bus_message_close_container(m);
-}
-
-_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
-        _cleanup_close_ int copy_fd = -1;
-        struct bus_body_part *part;
-        struct bus_container *c;
-        uint64_t size;
-        void *a;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(memfd, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->poisoned, -ESTALE);
-
-        r = sd_memfd_set_sealed(memfd, true);
-        if (r < 0)
-                return r;
-
-        copy_fd = sd_memfd_dup_fd(memfd);
-        if (copy_fd < 0)
-                return copy_fd;
-
-        r = sd_memfd_get_size(memfd, &size);
-        if (r < 0)
-                return r;
-
-        /* We require this to be NUL terminated */
-        if (size == 0)
-                return -EINVAL;
-
-        if (size > (uint64_t) (uint32_t) -1)
-                return -EINVAL;
-
-        c = message_get_container(m);
-        if (c->signature && c->signature[c->index]) {
-                /* Container signature is already set */
-
-                if (c->signature[c->index] != SD_BUS_TYPE_STRING)
-                        return -ENXIO;
-        } else {
-                char *e;
-
-                /* Maybe we can append to the signature? But only if this is the top-level container*/
-                if (c->enclosing != 0)
-                        return -ENXIO;
-
-                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
-                if (!e) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-        }
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m)) {
-                a = message_extend_body(m, 4, 4, false);
-                if (!a)
-                        return -ENOMEM;
-
-                *(uint32_t*) a = size - 1;
-        }
-
-        part = message_append_part(m);
-        if (!part)
-                return -ENOMEM;
-
-        part->memfd = copy_fd;
-        part->sealed = true;
-        part->size = size;
-        copy_fd = -1;
-
-        m->header->body_size += size;
-        message_extend_containers(m, size);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                r = message_add_offset(m, m->header->body_size);
-                if (r < 0) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
-        }
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index++;
-
-        return 0;
-}
-
-_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
-        char **i;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->poisoned, -ESTALE);
-
-        r = sd_bus_message_open_container(m, 'a', "s");
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(i, l) {
-                r = sd_bus_message_append_basic(m, 's', *i);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_message_close_container(m);
-}
-
-static int bus_message_close_header(sd_bus_message *m) {
-        uint8_t *a;
-        size_t sz, i;
-
-        assert(m);
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m))
-                return 0;
-
-        if (m->n_header_offsets < 1)
-                return 0;
-
-        assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
-
-        sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
-
-        a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
-        if (!a)
-                return -ENOMEM;
-
-        for (i = 0; i < m->n_header_offsets; i++)
-                write_word_le(a + sz*i, sz, m->header_offsets[i]);
-
-        return 0;
-}
-
-int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
-        struct bus_body_part *part;
-        size_t l, a;
-        unsigned i;
-        int r;
-
-        assert(m);
-
-        if (m->sealed)
-                return -EPERM;
-
-        if (m->n_containers > 0)
-                return -EBADMSG;
-
-        if (m->poisoned)
-                return -ESTALE;
-
-        /* In vtables the return signature of method calls is listed,
-         * let's check if they match if this is a response */
-        if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
-            m->enforced_reply_signature &&
-            !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
-                return -ENOMSG;
-
-        /* If gvariant marshalling is used we need to close the body structure */
-        r = bus_message_close_struct(m, &m->root_container, false);
-        if (r < 0)
-                return r;
-
-        /* If there's a non-trivial signature set, then add it in here */
-        if (!isempty(m->root_container.signature)) {
-                r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
-                if (r < 0)
-                        return r;
-        }
-
-        if (m->n_fds > 0) {
-                r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
-                if (r < 0)
-                        return r;
-        }
-
-        r = bus_message_close_header(m);
-        if (r < 0)
-                return r;
-
-        m->header->serial = (uint32_t) cookie;
-        m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
-
-        /* Add padding at the end of the fields part, since we know
-         * the body needs to start at an 8 byte alignment. We made
-         * sure we allocated enough space for this, so all we need to
-         * do here is to zero it out. */
-        l = BUS_MESSAGE_FIELDS_SIZE(m);
-        a = ALIGN8(l) - l;
-        if (a > 0)
-                memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
-
-        /* If this is something we can send as memfd, then let's seal
-        the memfd now. Note that we can send memfds as payload only
-        for directed messages, and not for broadcasts. */
-        if (m->destination && m->bus && m->bus->use_memfd) {
-                MESSAGE_FOREACH_PART(part, i, m)
-                        if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
-                                uint64_t sz;
-
-                                /* Try to seal it if that makes
-                                 * sense. First, unmap our own map to
-                                 * make sure we don't keep it busy. */
-                                bus_body_part_unmap(part);
-
-                                /* Then, sync up real memfd size */
-                                sz = part->size;
-                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0)
-                                        return -errno;
-
-                                /* Finally, try to seal */
-                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
-                                        part->sealed = true;
-                        }
-        }
-
-        m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
-        m->root_container.index = 0;
-        m->root_container.offset_index = 0;
-        m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
-
-        m->sealed = true;
-
-        return 0;
-}
-
-int bus_body_part_map(struct bus_body_part *part) {
-        void *p;
-        size_t psz;
-
-        assert_se(part);
-
-        if (part->data)
-                return 0;
-
-        if (part->size <= 0)
-                return 0;
-
-        /* For smaller zero parts (as used for padding) we don't need to map anything... */
-        if (part->memfd < 0 && part->is_zero && part->size < 8) {
-                static const uint8_t zeroes[7] = { };
-                part->data = (void*) zeroes;
-                return 0;
-        }
-
-        psz = PAGE_ALIGN(part->size);
-
-        if (part->memfd >= 0)
-                p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
-        else if (part->is_zero)
-                p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-        else
-                return -EINVAL;
-
-        if (p == MAP_FAILED)
-                return -errno;
-
-        part->mapped = psz;
-        part->data = p;
-        part->munmap_this = true;
-
-        return 0;
-}
-
-void bus_body_part_unmap(struct bus_body_part *part) {
-
-        assert_se(part);
-
-        if (part->memfd < 0)
-                return;
-
-        if (!part->data)
-                return;
-
-        if (!part->munmap_this)
-                return;
-
-        assert_se(munmap(part->data, part->mapped) == 0);
-
-        part->data = NULL;
-        part->mapped = 0;
-        part->munmap_this = false;
-
-        return;
-}
-
-static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
-        size_t k, start, end;
-
-        assert(rindex);
-        assert(align > 0);
-
-        start = ALIGN_TO((size_t) *rindex, align);
-        end = start + nbytes;
-
-        if (end > sz)
-                return -EBADMSG;
-
-        /* Verify that padding is 0 */
-        for (k = *rindex; k < start; k++)
-                if (((const uint8_t*) p)[k] != 0)
-                        return -EBADMSG;
-
-        if (r)
-                *r = (uint8_t*) p + start;
-
-        *rindex = end;
-
-        return 1;
-}
-
-static bool message_end_of_signature(sd_bus_message *m) {
-        struct bus_container *c;
-
-        assert(m);
-
-        c = message_get_container(m);
-        return !c->signature || c->signature[c->index] == 0;
-}
-
-static bool message_end_of_array(sd_bus_message *m, size_t index) {
-        struct bus_container *c;
-
-        assert(m);
-
-        c = message_get_container(m);
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                return false;
-
-        if (BUS_MESSAGE_IS_GVARIANT(m))
-                return index >= c->end;
-        else {
-                assert(c->array_size);
-                return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
-        }
-}
-
-_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-
-        if (complete && m->n_containers > 0)
-                return false;
-
-        if (message_end_of_signature(m))
-                return true;
-
-        if (message_end_of_array(m, m->rindex))
-                return true;
-
-        return false;
-}
-
-static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
-        struct bus_body_part *part;
-        size_t begin;
-        int r;
-
-        assert(m);
-
-        if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
-                part = m->cached_rindex_part;
-                begin = m->cached_rindex_part_begin;
-        } else {
-                part = &m->body;
-                begin = 0;
-        }
-
-        while (part) {
-                if (index < begin)
-                        return NULL;
-
-                if (index + sz <= begin + part->size) {
-
-                        r = bus_body_part_map(part);
-                        if (r < 0)
-                                return NULL;
-
-                        if (p)
-                                *p = (uint8_t*) part->data + index - begin;
-
-                        m->cached_rindex_part = part;
-                        m->cached_rindex_part_begin = begin;
-
-                        return part;
-                }
-
-                begin += part->size;
-                part = part->next;
-        }
-
-        return NULL;
-}
-
-static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(rindex);
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m))
-                return 0;
-
-        if (c->enclosing == SD_BUS_TYPE_ARRAY) {
-                int sz;
-
-                sz = bus_gvariant_get_size(c->signature);
-                if (sz < 0) {
-                        int alignment;
-
-                        if (c->offset_index+1 >= c->n_offsets)
-                                goto end;
-
-                        /* Variable-size array */
-
-                        alignment = bus_gvariant_get_alignment(c->signature);
-                        assert(alignment > 0);
-
-                        *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
-                        c->item_size = c->offsets[c->offset_index+1] - *rindex;
-                } else {
-
-                        if (c->offset_index+1 >= (c->end-c->begin)/sz)
-                                goto end;
-
-                        /* Fixed-size array */
-                        *rindex = c->begin + (c->offset_index+1) * sz;
-                        c->item_size = sz;
-                }
-
-                c->offset_index++;
-
-        } else if (c->enclosing == 0 ||
-                   c->enclosing == SD_BUS_TYPE_STRUCT ||
-                   c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
-
-                int alignment;
-                size_t n, j;
-
-                if (c->offset_index+1 >= c->n_offsets)
-                        goto end;
-
-                r = signature_element_length(c->signature + c->index, &n);
-                if (r < 0)
-                        return r;
-
-                r = signature_element_length(c->signature + c->index + n, &j);
-                if (r < 0)
-                        return r;
-                else {
-                        char t[j+1];
-                        memcpy(t, c->signature + c->index + n, j);
-                        t[j] = 0;
-
-                        alignment = bus_gvariant_get_alignment(t);
-                }
-
-                assert(alignment > 0);
-
-                *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
-                c->item_size = c->offsets[c->offset_index+1] - *rindex;
-
-                c->offset_index++;
-
-        } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
-                goto end;
-        else
-                assert_not_reached("Unknown container type");
-
-        return 0;
-
-end:
-        /* Reached the end */
-        *rindex = c->end;
-        c->item_size = 0;
-        return 0;
-}
-
-
-static int message_peek_body(
-                sd_bus_message *m,
-                size_t *rindex,
-                size_t align,
-                size_t nbytes,
-                void **ret) {
-
-        size_t k, start, end, padding;
-        struct bus_body_part *part;
-        uint8_t *q;
-
-        assert(m);
-        assert(rindex);
-        assert(align > 0);
-
-        start = ALIGN_TO((size_t) *rindex, align);
-        padding = start - *rindex;
-        end = start + nbytes;
-
-        if (end > BUS_MESSAGE_BODY_SIZE(m))
-                return -EBADMSG;
-
-        part = find_part(m, *rindex, padding, (void**) &q);
-        if (!part)
-                return -EBADMSG;
-
-        if (q) {
-                /* Verify padding */
-                for (k = 0; k < padding; k++)
-                        if (q[k] != 0)
-                                return -EBADMSG;
-        }
-
-        part = find_part(m, start, nbytes, (void**) &q);
-        if (!part || (nbytes > 0 && !q))
-                return -EBADMSG;
-
-        *rindex = end;
-
-        if (ret)
-                *ret = q;
-
-        return 0;
-}
-
-static bool validate_nul(const char *s, size_t l) {
-
-        /* Check for NUL chars in the string */
-        if (memchr(s, 0, l))
-                return false;
-
-        /* Check for NUL termination */
-        if (s[l] != 0)
-                return false;
-
-        return true;
-}
-
-static bool validate_string(const char *s, size_t l) {
-
-        if (!validate_nul(s, l))
-                return false;
-
-        /* Check if valid UTF8 */
-        if (!utf8_is_valid(s))
-                return false;
-
-        return true;
-}
-
-static bool validate_signature(const char *s, size_t l) {
-
-        if (!validate_nul(s, l))
-                return false;
-
-        /* Check if valid signature */
-        if (!signature_is_valid(s, true))
-                return false;
-
-        return true;
-}
-
-static bool validate_object_path(const char *s, size_t l) {
-
-        if (!validate_nul(s, l))
-                return false;
-
-        if (!object_path_is_valid(s))
-                return false;
-
-        return true;
-}
-
-_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
-        struct bus_container *c;
-        size_t rindex;
-        void *q;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(bus_type_is_basic(type), -EINVAL);
-
-        if (message_end_of_signature(m))
-                return -ENXIO;
-
-        if (message_end_of_array(m, m->rindex))
-                return 0;
-
-        c = message_get_container(m);
-        if (c->signature[c->index] != type)
-                return -ENXIO;
-
-        rindex = m->rindex;
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-
-                if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
-                        bool ok;
-
-                        r = message_peek_body(m, &rindex, 1, c->item_size, &q);
-                        if (r < 0)
-                                return r;
-
-                        if (type == SD_BUS_TYPE_STRING)
-                                ok = validate_string(q, c->item_size-1);
-                        else if (type == SD_BUS_TYPE_OBJECT_PATH)
-                                ok = validate_object_path(q, c->item_size-1);
-                        else
-                                ok = validate_signature(q, c->item_size-1);
-
-                        if (!ok)
-                                return -EBADMSG;
-
-                        if (p)
-                                *(const char**) p = q;
-                } else {
-                        int sz, align;
-
-                        sz = bus_gvariant_get_size(CHAR_TO_STR(type));
-                        assert(sz > 0);
-                        if ((size_t) sz != c->item_size)
-                                return -EBADMSG;
-
-                        align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
-                        assert(align > 0);
-
-                        r = message_peek_body(m, &rindex, align, c->item_size, &q);
-                        if (r < 0)
-                                return r;
-
-                        switch (type) {
-
-                        case SD_BUS_TYPE_BYTE:
-                                if (p)
-                                        *(uint8_t*) p = *(uint8_t*) q;
-                                break;
-
-                        case SD_BUS_TYPE_BOOLEAN:
-                                if (p)
-                                        *(int*) p = !!*(uint8_t*) q;
-                                break;
-
-                        case SD_BUS_TYPE_INT16:
-                        case SD_BUS_TYPE_UINT16:
-                                if (p)
-                                        *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
-                                break;
-
-                        case SD_BUS_TYPE_INT32:
-                        case SD_BUS_TYPE_UINT32:
-                                if (p)
-                                        *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
-                                break;
-
-                        case SD_BUS_TYPE_INT64:
-                        case SD_BUS_TYPE_UINT64:
-                        case SD_BUS_TYPE_DOUBLE:
-                                if (p)
-                                        *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
-                                break;
-
-                        case SD_BUS_TYPE_UNIX_FD: {
-                                uint32_t j;
-
-                                j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
-                                if (j >= m->n_fds)
-                                        return -EBADMSG;
-
-                                if (p)
-                                        *(int*) p = m->fds[j];
-
-                                break;
-                        }
-
-                        default:
-                                assert_not_reached("unexpected type");
-                        }
-                }
-
-                r = container_next_item(m, c, &rindex);
-                if (r < 0)
-                        return r;
-        } else {
-
-                rindex = m->rindex;
-
-                if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
-                        uint32_t l;
-                        bool ok;
-
-                        r = message_peek_body(m, &rindex, 4, 4, &q);
-                        if (r < 0)
-                                return r;
-
-                        l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
-                        r = message_peek_body(m, &rindex, 1, l+1, &q);
-                        if (r < 0)
-                                return r;
-
-                        if (type == SD_BUS_TYPE_OBJECT_PATH)
-                                ok = validate_object_path(q, l);
-                        else
-                                ok = validate_string(q, l);
-                        if (!ok)
-                                return -EBADMSG;
-
-                        if (p)
-                                *(const char**) p = q;
-
-                } else if (type == SD_BUS_TYPE_SIGNATURE) {
-                        uint8_t l;
-
-                        r = message_peek_body(m, &rindex, 1, 1, &q);
-                        if (r < 0)
-                                return r;
-
-                        l = *(uint8_t*) q;
-                        r = message_peek_body(m, &rindex, 1, l+1, &q);
-                        if (r < 0)
-                                return r;
-
-                        if (!validate_signature(q, l))
-                                return -EBADMSG;
-
-                        if (p)
-                                *(const char**) p = q;
-
-                } else {
-                        ssize_t sz, align;
-
-                        align = bus_type_get_alignment(type);
-                        assert(align > 0);
-
-                        sz = bus_type_get_size(type);
-                        assert(sz > 0);
-
-                        r = message_peek_body(m, &rindex, align, sz, &q);
-                        if (r < 0)
-                                return r;
-
-                        switch (type) {
-
-                        case SD_BUS_TYPE_BYTE:
-                                if (p)
-                                        *(uint8_t*) p = *(uint8_t*) q;
-                                break;
-
-                        case SD_BUS_TYPE_BOOLEAN:
-                                if (p)
-                                        *(int*) p = !!*(uint32_t*) q;
-                                break;
-
-                        case SD_BUS_TYPE_INT16:
-                        case SD_BUS_TYPE_UINT16:
-                                if (p)
-                                        *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
-                                break;
-
-                        case SD_BUS_TYPE_INT32:
-                        case SD_BUS_TYPE_UINT32:
-                                if (p)
-                                        *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
-                                break;
-
-                        case SD_BUS_TYPE_INT64:
-                        case SD_BUS_TYPE_UINT64:
-                        case SD_BUS_TYPE_DOUBLE:
-                                if (p)
-                                        *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
-                                break;
-
-                        case SD_BUS_TYPE_UNIX_FD: {
-                                uint32_t j;
-
-                                j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
-                                if (j >= m->n_fds)
-                                        return -EBADMSG;
-
-                                if (p)
-                                        *(int*) p = m->fds[j];
-                                break;
-                        }
-
-                        default:
-                                assert_not_reached("Unknown basic type...");
-                        }
-                }
-        }
-
-        m->rindex = rindex;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index++;
-
-        return 1;
-}
-
-static int bus_message_enter_array(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                uint32_t **array_size,
-                size_t *item_size,
-                size_t **offsets,
-                size_t *n_offsets) {
-
-        size_t rindex;
-        void *q;
-        int r, alignment;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(array_size);
-        assert(item_size);
-        assert(offsets);
-        assert(n_offsets);
-
-        if (!signature_is_single(contents, true))
-                return -EINVAL;
-
-        if (!c->signature || c->signature[c->index] == 0)
-                return -ENXIO;
-
-        if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
-                return -ENXIO;
-
-        if (!startswith(c->signature + c->index + 1, contents))
-                return -ENXIO;
-
-        rindex = m->rindex;
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m)) {
-                /* dbus1 */
-
-                r = message_peek_body(m, &rindex, 4, 4, &q);
-                if (r < 0)
-                        return r;
-
-                if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
-                        return -EBADMSG;
-
-                alignment = bus_type_get_alignment(contents[0]);
-                if (alignment < 0)
-                        return alignment;
-
-                r = message_peek_body(m, &rindex, alignment, 0, NULL);
-                if (r < 0)
-                        return r;
-
-                *array_size = (uint32_t*) q;
-
-        } else if (c->item_size <= 0) {
-
-                /* gvariant: empty array */
-                *item_size = 0;
-                *offsets = NULL;
-                *n_offsets = 0;
-
-        } else if (bus_gvariant_is_fixed_size(contents)) {
-
-                /* gvariant: fixed length array */
-                *item_size = bus_gvariant_get_size(contents);
-                *offsets = NULL;
-                *n_offsets = 0;
-
-        } else {
-                size_t where, p = 0, framing, sz;
-                unsigned i;
-
-                /* gvariant: variable length array */
-                sz = determine_word_size(c->item_size, 0);
-
-                where = rindex + c->item_size - sz;
-                r = message_peek_body(m, &where, 1, sz, &q);
-                if (r < 0)
-                        return r;
-
-                framing = read_word_le(q, sz);
-                if (framing > c->item_size - sz)
-                        return -EBADMSG;
-                if ((c->item_size - framing) % sz != 0)
-                        return -EBADMSG;
-
-                *n_offsets = (c->item_size - framing) / sz;
-
-                where = rindex + framing;
-                r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
-                if (r < 0)
-                        return r;
-
-                *offsets = new(size_t, *n_offsets);
-                if (!*offsets)
-                        return -ENOMEM;
-
-                for (i = 0; i < *n_offsets; i++) {
-                        size_t x;
-
-                        x = read_word_le((uint8_t*) q + i * sz, sz);
-                        if (x > c->item_size - sz)
-                                return -EBADMSG;
-                        if (x < p)
-                                return -EBADMSG;
-
-                        (*offsets)[i] = rindex + x;
-                        p = x;
-                }
-
-                *item_size = (*offsets)[0] - rindex;
-        }
-
-        m->rindex = rindex;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index += 1 + strlen(contents);
-
-        return 1;
-}
-
-static int bus_message_enter_variant(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                size_t *item_size) {
-
-        size_t rindex;
-        uint8_t l;
-        void *q;
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(item_size);
-
-        if (!signature_is_single(contents, false))
-                return -EINVAL;
-
-        if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
-                return -EINVAL;
-
-        if (!c->signature || c->signature[c->index] == 0)
-                return -ENXIO;
-
-        if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
-                return -ENXIO;
-
-        rindex = m->rindex;
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                size_t k, where;
-
-                k = strlen(contents);
-                if (1+k > c->item_size)
-                        return -EBADMSG;
-
-                where = rindex + c->item_size - (1+k);
-                r = message_peek_body(m, &where, 1, 1+k, &q);
-                if (r < 0)
-                        return r;
-
-                if (*(char*) q != 0)
-                        return -EBADMSG;
-
-                if (memcmp((uint8_t*) q+1, contents, k))
-                        return -ENXIO;
-
-                *item_size = c->item_size - (1+k);
-
-        } else {
-                r = message_peek_body(m, &rindex, 1, 1, &q);
-                if (r < 0)
-                        return r;
-
-                l = *(uint8_t*) q;
-                r = message_peek_body(m, &rindex, 1, l+1, &q);
-                if (r < 0)
-                        return r;
-
-                if (!validate_signature(q, l))
-                        return -EBADMSG;
-
-                if (!streq(q, contents))
-                        return -ENXIO;
-        }
-
-        m->rindex = rindex;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index++;
-
-        return 1;
-}
-
-static int build_struct_offsets(
-                sd_bus_message *m,
-                const char *signature,
-                size_t size,
-                size_t *item_size,
-                size_t **offsets,
-                size_t *n_offsets) {
-
-        unsigned n_variable = 0, n_total = 0, v;
-        size_t previous = 0, where;
-        const char *p;
-        size_t sz;
-        void *q;
-        int r;
-
-        assert(m);
-        assert(item_size);
-        assert(offsets);
-        assert(n_offsets);
-
-        if (isempty(signature)) {
-                *item_size = 0;
-                *offsets = NULL;
-                *n_offsets = 0;
-                return 0;
-        }
-
-        sz = determine_word_size(size, 0);
-        if (sz <= 0)
-                return -EBADMSG;
-
-        /* First, loop over signature and count variable elements and
-         * elements in general. We use this to know how large the
-         * offset array is at the end of the structure. Note that
-         * GVariant only stores offsets for all variable size elements
-         * that are not the last item. */
-
-        p = signature;
-        while (*p != 0) {
-                size_t n;
-
-                r = signature_element_length(p, &n);
-                if (r < 0)
-                        return r;
-                else {
-                        char t[n+1];
-
-                        memcpy(t, p, n);
-                        t[n] = 0;
-
-                        r = bus_gvariant_is_fixed_size(t);
-                }
-
-                if (r < 0)
-                        return r;
-                if (r == 0 && p[n] != 0) /* except the last item */
-                        n_variable ++;
-                n_total++;
-
-                p += n;
-        }
-
-        if (size < n_variable * sz)
-                return -EBADMSG;
-
-        where = m->rindex + size - (n_variable * sz);
-        r = message_peek_body(m, &where, 1, n_variable * sz, &q);
-        if (r < 0)
-                return r;
-
-        v = n_variable;
-
-        *offsets = new(size_t, n_total);
-        if (!*offsets)
-                return -ENOMEM;
-
-        *n_offsets = 0;
-
-        /* Second, loop again and build an offset table */
-        p = signature;
-        while (*p != 0) {
-                size_t n, offset;
-                int k;
-
-                r = signature_element_length(p, &n);
-                if (r < 0)
-                        return r;
-                else {
-                        char t[n+1];
-
-                        memcpy(t, p, n);
-                        t[n] = 0;
-
-                        k = bus_gvariant_get_size(t);
-                        if (k < 0) {
-                                size_t x;
-
-                                /* variable size */
-                                if (v > 0) {
-                                        v--;
-
-                                        x = read_word_le((uint8_t*) q + v*sz, sz);
-                                        if (x >= size)
-                                                return -EBADMSG;
-                                        if (m->rindex + x < previous)
-                                                return -EBADMSG;
-                                } else
-                                        /* The last item's end
-                                         * is determined from
-                                         * the start of the
-                                         * offset array */
-                                        x = size - (n_variable * sz);
-
-                                offset = m->rindex + x;
-
-                        } else {
-                                size_t align;
-
-                                /* fixed size */
-                                align = bus_gvariant_get_alignment(t);
-                                assert(align > 0);
-
-                                offset = (*n_offsets == 0 ? m->rindex  : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
-                        }
-                }
-
-                previous = (*offsets)[(*n_offsets)++] = offset;
-                p += n;
-        }
-
-        assert(v == 0);
-        assert(*n_offsets == n_total);
-
-        *item_size = (*offsets)[0] - m->rindex;
-        return 0;
-}
-
-static int enter_struct_or_dict_entry(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                size_t *item_size,
-                size_t **offsets,
-                size_t *n_offsets) {
-
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(item_size);
-        assert(offsets);
-        assert(n_offsets);
-
-        if (!BUS_MESSAGE_IS_GVARIANT(m)) {
-
-                /* dbus1 */
-                r = message_peek_body(m, &m->rindex, 8, 0, NULL);
-                if (r < 0)
-                        return r;
-
-        } else if (c->item_size <= 0) {
-
-                /* gvariant empty struct */
-                *item_size = 0;
-                *offsets = NULL;
-                *n_offsets = 0;
-        } else
-                /* gvariant with contents */
-                return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
-
-        return 0;
-}
-
-static int bus_message_enter_struct(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                size_t *item_size,
-                size_t **offsets,
-                size_t *n_offsets) {
-
-        size_t l;
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-        assert(item_size);
-        assert(offsets);
-        assert(n_offsets);
-
-        if (!signature_is_valid(contents, false))
-                return -EINVAL;
-
-        if (!c->signature || c->signature[c->index] == 0)
-                return -ENXIO;
-
-        l = strlen(contents);
-
-        if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
-            !startswith(c->signature + c->index + 1, contents) ||
-            c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
-                return -ENXIO;
-
-        r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
-        if (r < 0)
-                return r;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index += 1 + l + 1;
-
-        return 1;
-}
-
-static int bus_message_enter_dict_entry(
-                sd_bus_message *m,
-                struct bus_container *c,
-                const char *contents,
-                size_t *item_size,
-                size_t **offsets,
-                size_t *n_offsets) {
-
-        size_t l;
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(contents);
-
-        if (!signature_is_pair(contents))
-                return -EINVAL;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                return -ENXIO;
-
-        if (!c->signature || c->signature[c->index] == 0)
-                return 0;
-
-        l = strlen(contents);
-
-        if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
-            !startswith(c->signature + c->index + 1, contents) ||
-            c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
-                return -ENXIO;
-
-        r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
-        if (r < 0)
-                return r;
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY)
-                c->index += 1 + l + 1;
-
-        return 1;
-}
-
-_public_ int sd_bus_message_enter_container(sd_bus_message *m,
-                                            char type,
-                                            const char *contents) {
-        struct bus_container *c, *w;
-        uint32_t *array_size = NULL;
-        char *signature;
-        size_t before;
-        size_t *offsets = NULL;
-        size_t n_offsets = 0, item_size = 0;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(type != 0 || !contents, -EINVAL);
-
-        if (type == 0 || !contents) {
-                const char *cc;
-                char tt;
-
-                /* Allow entering into anonymous containers */
-                r = sd_bus_message_peek_type(m, &tt, &cc);
-                if (r < 0)
-                        return r;
-
-                if (type != 0 && type != tt)
-                        return -ENXIO;
-
-                if (contents && !streq(contents, cc))
-                        return -ENXIO;
-
-                type = tt;
-                contents = cc;
-        }
-
-        /*
-         * We enforce a global limit on container depth, that is much
-         * higher than the 32 structs and 32 arrays the specification
-         * mandates. This is simpler to implement for us, and we need
-         * this only to ensure our container array doesn't grow
-         * without bounds. We are happy to return any data from a
-         * message as long as the data itself is valid, even if the
-         * overall message might be not.
-         *
-         * Note that the message signature is validated when
-         * parsing the headers, and that validation does check the
-         * 32/32 limit.
-         *
-         * Note that the specification defines no limits on the depth
-         * of stacked variants, but we do.
-         */
-        if (m->n_containers >= BUS_CONTAINER_DEPTH)
-                return -EBADMSG;
-
-        if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
-                return -ENOMEM;
-
-        if (message_end_of_signature(m))
-                return -ENXIO;
-
-        if (message_end_of_array(m, m->rindex))
-                return 0;
-
-        c = message_get_container(m);
-
-        signature = strdup(contents);
-        if (!signature)
-                return -ENOMEM;
-
-        c->saved_index = c->index;
-        before = m->rindex;
-
-        if (type == SD_BUS_TYPE_ARRAY)
-                r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
-        else if (type == SD_BUS_TYPE_VARIANT)
-                r = bus_message_enter_variant(m, c, contents, &item_size);
-        else if (type == SD_BUS_TYPE_STRUCT)
-                r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
-        else if (type == SD_BUS_TYPE_DICT_ENTRY)
-                r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
-        else
-                r = -EINVAL;
-
-        if (r <= 0) {
-                free(signature);
-                free(offsets);
-                return r;
-        }
-
-        /* OK, let's fill it in */
-        w = m->containers + m->n_containers++;
-        w->enclosing = type;
-        w->signature = signature;
-        w->peeked_signature = NULL;
-        w->index = 0;
-
-        w->before = before;
-        w->begin = m->rindex;
-        w->end = m->rindex + c->item_size;
-
-        w->array_size = array_size;
-        w->item_size = item_size;
-        w->offsets = offsets;
-        w->n_offsets = n_offsets;
-        w->offset_index = 0;
-
-        return 1;
-}
-
-_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
-        struct bus_container *c;
-        unsigned saved;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(m->n_containers > 0, -ENXIO);
-
-        c = message_get_container(m);
-
-        if (c->enclosing != SD_BUS_TYPE_ARRAY) {
-                if (c->signature && c->signature[c->index] != 0)
-                        return -EBUSY;
-        }
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                if (m->rindex < c->end)
-                        return -EBUSY;
-
-        } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
-                uint32_t l;
-
-                l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
-                if (c->begin + l != m->rindex)
-                        return -EBUSY;
-        }
-
-        free(c->signature);
-        free(c->peeked_signature);
-        free(c->offsets);
-        m->n_containers--;
-
-        c = message_get_container(m);
-
-        saved = c->index;
-        c->index = c->saved_index;
-        r = container_next_item(m, c, &m->rindex);
-        c->index = saved;
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static void message_quit_container(sd_bus_message *m) {
-        struct bus_container *c;
-
-        assert(m);
-        assert(m->sealed);
-        assert(m->n_containers > 0);
-
-        c = message_get_container(m);
-
-        /* Undo seeks */
-        assert(m->rindex >= c->before);
-        m->rindex = c->before;
-
-        /* Free container */
-        free(c->signature);
-        free(c->offsets);
-        m->n_containers--;
-
-        /* Correct index of new top-level container */
-        c = message_get_container(m);
-        c->index = c->saved_index;
-}
-
-_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
-        struct bus_container *c;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-
-        if (message_end_of_signature(m))
-                goto eof;
-
-        if (message_end_of_array(m, m->rindex))
-                goto eof;
-
-        c = message_get_container(m);
-
-        if (bus_type_is_basic(c->signature[c->index])) {
-                if (contents)
-                        *contents = NULL;
-                if (type)
-                        *type = c->signature[c->index];
-                return 1;
-        }
-
-        if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
-
-                if (contents) {
-                        size_t l;
-                        char *sig;
-
-                        r = signature_element_length(c->signature+c->index+1, &l);
-                        if (r < 0)
-                                return r;
-
-                        assert(l >= 1);
-
-                        sig = strndup(c->signature + c->index + 1, l);
-                        if (!sig)
-                                return -ENOMEM;
-
-                        free(c->peeked_signature);
-                        *contents = c->peeked_signature = sig;
-                }
-
-                if (type)
-                        *type = SD_BUS_TYPE_ARRAY;
-
-                return 1;
-        }
-
-        if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
-            c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
-
-                if (contents) {
-                        size_t l;
-                        char *sig;
-
-                        r = signature_element_length(c->signature+c->index, &l);
-                        if (r < 0)
-                                return r;
-
-                        assert(l >= 2);
-                        sig = strndup(c->signature + c->index + 1, l - 2);
-                        if (!sig)
-                                return -ENOMEM;
-
-                        free(c->peeked_signature);
-                        *contents = c->peeked_signature = sig;
-                }
-
-                if (type)
-                        *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
-
-                return 1;
-        }
-
-        if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
-                if (contents) {
-                        void *q;
-
-                        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                                size_t k;
-
-                                if (c->item_size < 2)
-                                        return -EBADMSG;
-
-                                /* Look for the NUL delimiter that
-                                   separates the payload from the
-                                   signature. Since the body might be
-                                   in a different part that then the
-                                   signature we map byte by byte. */
-
-                                for (k = 2; k <= c->item_size; k++) {
-                                        size_t where;
-
-                                        where = m->rindex + c->item_size - k;
-                                        r = message_peek_body(m, &where, 1, k, &q);
-                                        if (r < 0)
-                                                return r;
-
-                                        if (*(char*) q == 0)
-                                                break;
-                                }
-
-                                if (k > c->item_size)
-                                        return -EBADMSG;
-
-                                free(c->peeked_signature);
-                                c->peeked_signature = strndup((char*) q + 1, k - 1);
-                                if (!c->peeked_signature)
-                                        return -ENOMEM;
-
-                                if (!signature_is_valid(c->peeked_signature, true))
-                                        return -EBADMSG;
-
-                                *contents = c->peeked_signature;
-                        } else {
-                                size_t rindex, l;
-
-                                rindex = m->rindex;
-                                r = message_peek_body(m, &rindex, 1, 1, &q);
-                                if (r < 0)
-                                        return r;
-
-                                l = *(uint8_t*) q;
-                                r = message_peek_body(m, &rindex, 1, l+1, &q);
-                                if (r < 0)
-                                        return r;
-
-                                if (!validate_signature(q, l))
-                                        return -EBADMSG;
-
-                                *contents = q;
-                        }
-                }
-
-                if (type)
-                        *type = SD_BUS_TYPE_VARIANT;
-
-                return 1;
-        }
-
-        return -EINVAL;
-
-eof:
-        if (type)
-                *type = 0;
-        if (contents)
-                *contents = NULL;
-        return 0;
-}
-
-_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
-        struct bus_container *c;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-
-        if (complete) {
-                message_reset_containers(m);
-                m->rindex = 0;
-
-                c = message_get_container(m);
-        } else {
-                c = message_get_container(m);
-
-                c->offset_index = 0;
-                c->index = 0;
-                m->rindex = c->begin;
-        }
-
-        c->offset_index = 0;
-        c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
-
-        return !isempty(c->signature);
-}
-
-static int message_read_ap(
-                sd_bus_message *m,
-                const char *types,
-                va_list ap) {
-
-        unsigned n_array, n_struct;
-        TypeStack stack[BUS_CONTAINER_DEPTH];
-        unsigned stack_ptr = 0;
-        unsigned n_loop = 0;
-        int r;
-
-        assert(m);
-
-        if (isempty(types))
-                return 0;
-
-        /* Ideally, we'd just call ourselves recursively on every
-         * complex type. However, the state of a va_list that is
-         * passed to a function is undefined after that function
-         * returns. This means we need to docode the va_list linearly
-         * in a single stackframe. We hence implement our own
-         * home-grown stack in an array. */
-
-        n_array = (unsigned) -1; /* lenght of current array entries */
-        n_struct = strlen(types); /* length of current struct contents signature */
-
-        for (;;) {
-                const char *t;
-
-                n_loop++;
-
-                if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
-                        r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                break;
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0)
-                                return r;
-
-                        continue;
-                }
-
-                t = types;
-                if (n_array != (unsigned) -1)
-                        n_array --;
-                else {
-                        types ++;
-                        n_struct--;
-                }
-
-                switch (*t) {
-
-                case SD_BUS_TYPE_BYTE:
-                case SD_BUS_TYPE_BOOLEAN:
-                case SD_BUS_TYPE_INT16:
-                case SD_BUS_TYPE_UINT16:
-                case SD_BUS_TYPE_INT32:
-                case SD_BUS_TYPE_UINT32:
-                case SD_BUS_TYPE_INT64:
-                case SD_BUS_TYPE_UINT64:
-                case SD_BUS_TYPE_DOUBLE:
-                case SD_BUS_TYPE_STRING:
-                case SD_BUS_TYPE_OBJECT_PATH:
-                case SD_BUS_TYPE_SIGNATURE:
-                case SD_BUS_TYPE_UNIX_FD: {
-                        void *p;
-
-                        p = va_arg(ap, void*);
-                        r = sd_bus_message_read_basic(m, *t, p);
-                        if (r < 0)
-                                return r;
-                        if (r == 0) {
-                                if (n_loop <= 1)
-                                        return 0;
-
-                                return -ENXIO;
-                        }
-
-                        break;
-                }
-
-                case SD_BUS_TYPE_ARRAY: {
-                        size_t k;
-
-                        r = signature_element_length(t + 1, &k);
-                        if (r < 0)
-                                return r;
-
-                        {
-                                char s[k + 1];
-                                memcpy(s, t + 1, k);
-                                s[k] = 0;
-
-                                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
-                                if (r < 0)
-                                        return r;
-                                if (r == 0) {
-                                        if (n_loop <= 1)
-                                                return 0;
-
-                                        return -ENXIO;
-                                }
-                        }
-
-                        if (n_array == (unsigned) -1) {
-                                types += k;
-                                n_struct -= k;
-                        }
-
-                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
-                        if (r < 0)
-                                return r;
-
-                        types = t + 1;
-                        n_struct = k;
-                        n_array = va_arg(ap, unsigned);
-
-                        break;
-                }
-
-                case SD_BUS_TYPE_VARIANT: {
-                        const char *s;
-
-                        s = va_arg(ap, const char *);
-                        if (!s)
-                                return -EINVAL;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
-                        if (r < 0)
-                                return r;
-                        if (r == 0) {
-                                if (n_loop <= 1)
-                                        return 0;
-
-                                return -ENXIO;
-                        }
-
-                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
-                        if (r < 0)
-                                return r;
-
-                        types = s;
-                        n_struct = strlen(s);
-                        n_array = (unsigned) -1;
-
-                        break;
-                }
-
-                case SD_BUS_TYPE_STRUCT_BEGIN:
-                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
-                        size_t k;
-
-                        r = signature_element_length(t, &k);
-                        if (r < 0)
-                                return r;
-
-                        {
-                                char s[k - 1];
-                                memcpy(s, t + 1, k - 2);
-                                s[k - 2] = 0;
-
-                                r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
-                                if (r < 0)
-                                        return r;
-                                if (r == 0) {
-                                        if (n_loop <= 1)
-                                                return 0;
-                                        return -ENXIO;
-                                }
-                        }
-
-                        if (n_array == (unsigned) -1) {
-                                types += k - 1;
-                                n_struct -= k - 1;
-                        }
-
-                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
-                        if (r < 0)
-                                return r;
-
-                        types = t + 1;
-                        n_struct = k - 2;
-                        n_array = (unsigned) -1;
-
-                        break;
-                }
-
-                default:
-                        return -EINVAL;
-                }
-        }
-
-        return 1;
-}
-
-_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
-        va_list ap;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(types, -EINVAL);
-
-        va_start(ap, types);
-        r = message_read_ap(m, types, ap);
-        va_end(ap);
-
-        return r;
-}
-
-_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(types, -EINVAL);
-
-        if (isempty(types))
-                return 0;
-
-        switch (*types) {
-
-        case SD_BUS_TYPE_BYTE:
-        case SD_BUS_TYPE_BOOLEAN:
-        case SD_BUS_TYPE_INT16:
-        case SD_BUS_TYPE_UINT16:
-        case SD_BUS_TYPE_INT32:
-        case SD_BUS_TYPE_UINT32:
-        case SD_BUS_TYPE_INT64:
-        case SD_BUS_TYPE_UINT64:
-        case SD_BUS_TYPE_DOUBLE:
-        case SD_BUS_TYPE_STRING:
-        case SD_BUS_TYPE_OBJECT_PATH:
-        case SD_BUS_TYPE_SIGNATURE:
-        case SD_BUS_TYPE_UNIX_FD:
-
-                r = sd_bus_message_read_basic(m, *types, NULL);
-                if (r <= 0)
-                        return r;
-
-                r = sd_bus_message_skip(m, types + 1);
-                if (r < 0)
-                        return r;
-
-                return 1;
-
-        case SD_BUS_TYPE_ARRAY: {
-                size_t k;
-
-                r = signature_element_length(types + 1, &k);
-                if (r < 0)
-                        return r;
-
-                {
-                        char s[k+1];
-                        memcpy(s, types+1, k);
-                        s[k] = 0;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
-                        if (r <= 0)
-                                return r;
-
-                        for (;;) {
-                                r = sd_bus_message_skip(m, s);
-                                if (r < 0)
-                                        return r;
-                                if (r == 0)
-                                        break;
-                        }
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0)
-                                return r;
-                }
-
-                r = sd_bus_message_skip(m, types + 1 + k);
-                if (r < 0)
-                        return r;
-
-                return 1;
-        }
-
-        case SD_BUS_TYPE_VARIANT: {
-                const char *contents;
-                char x;
-
-                r = sd_bus_message_peek_type(m, &x, &contents);
-                if (r <= 0)
-                        return r;
-
-                if (x != SD_BUS_TYPE_VARIANT)
-                        return -ENXIO;
-
-                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
-                if (r <= 0)
-                        return r;
-
-                r = sd_bus_message_skip(m, contents);
-                if (r < 0)
-                        return r;
-                assert(r != 0);
-
-                r = sd_bus_message_exit_container(m);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_skip(m, types + 1);
-                if (r < 0)
-                        return r;
-
-                return 1;
-        }
-
-        case SD_BUS_TYPE_STRUCT_BEGIN:
-        case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
-                size_t k;
-
-                r = signature_element_length(types, &k);
-                if (r < 0)
-                        return r;
-
-                {
-                        char s[k-1];
-                        memcpy(s, types+1, k-2);
-                        s[k-2] = 0;
-
-                        r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
-                        if (r <= 0)
-                                return r;
-
-                        r = sd_bus_message_skip(m, s);
-                        if (r < 0)
-                                return r;
-                        assert(r != 0);
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0)
-                                return r;
-                }
-
-                r = sd_bus_message_skip(m, types + k);
-                if (r < 0)
-                        return r;
-
-                return 1;
-        }
-
-        default:
-                return -EINVAL;
-        }
-}
-
-_public_ int sd_bus_message_read_array(sd_bus_message *m,
-                                       char type,
-                                       const void **ptr,
-                                       size_t *size) {
-        struct bus_container *c;
-        void *p;
-        size_t sz;
-        ssize_t align;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(bus_type_is_trivial(type), -EINVAL);
-        assert_return(ptr, -EINVAL);
-        assert_return(size, -EINVAL);
-        assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
-        if (r <= 0)
-                return r;
-
-        c = message_get_container(m);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
-                if (align < 0)
-                        return align;
-
-                sz = c->end - c->begin;
-        } else {
-                align = bus_type_get_alignment(type);
-                if (align < 0)
-                        return align;
-
-                sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
-        }
-
-        if (sz == 0)
-                /* Zero length array, let's return some aligned
-                 * pointer that is not NULL */
-                p = (uint8_t*) NULL + align;
-        else {
-                r = message_peek_body(m, &m->rindex, align, sz, &p);
-                if (r < 0)
-                        goto fail;
-        }
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                goto fail;
-
-        *ptr = (const void*) p;
-        *size = sz;
-
-        return 1;
-
-fail:
-        message_quit_container(m);
-        return r;
-}
-
-static int message_peek_fields(
-                sd_bus_message *m,
-                size_t *rindex,
-                size_t align,
-                size_t nbytes,
-                void **ret) {
-
-        assert(m);
-        assert(rindex);
-        assert(align > 0);
-
-        return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
-}
-
-static int message_peek_field_uint32(
-                sd_bus_message *m,
-                size_t *ri,
-                size_t item_size,
-                uint32_t *ret) {
-
-        int r;
-        void *q;
-
-        assert(m);
-        assert(ri);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
-                return -EBADMSG;
-
-        /* identical for gvariant and dbus1 */
-
-        r = message_peek_fields(m, ri, 4, 4, &q);
-        if (r < 0)
-                return r;
-
-        if (ret)
-                *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
-
-        return 0;
-}
-
-static int message_peek_field_string(
-                sd_bus_message *m,
-                bool (*validate)(const char *p),
-                size_t *ri,
-                size_t item_size,
-                const char **ret) {
-
-        uint32_t l;
-        int r;
-        void *q;
-
-        assert(m);
-        assert(ri);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-
-                if (item_size <= 0)
-                        return -EBADMSG;
-
-                r = message_peek_fields(m, ri, 1, item_size, &q);
-                if (r < 0)
-                        return r;
-
-                l = item_size - 1;
-        } else {
-                r = message_peek_field_uint32(m, ri, 4, &l);
-                if (r < 0)
-                        return r;
-
-                r = message_peek_fields(m, ri, 1, l+1, &q);
-                if (r < 0)
-                        return r;
-        }
-
-        if (validate) {
-                if (!validate_nul(q, l))
-                        return -EBADMSG;
-
-                if (!validate(q))
-                        return -EBADMSG;
-        } else {
-                if (!validate_string(q, l))
-                        return -EBADMSG;
-        }
-
-        if (ret)
-                *ret = q;
-
-        return 0;
-}
-
-static int message_peek_field_signature(
-                sd_bus_message *m,
-                size_t *ri,
-                size_t item_size,
-                const char **ret) {
-
-        size_t l;
-        int r;
-        void *q;
-
-        assert(m);
-        assert(ri);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-
-                if (item_size <= 0)
-                        return -EBADMSG;
-
-                r = message_peek_fields(m, ri, 1, item_size, &q);
-                if (r < 0)
-                        return r;
-
-                l = item_size - 1;
-        } else {
-                r = message_peek_fields(m, ri, 1, 1, &q);
-                if (r < 0)
-                        return r;
-
-                l = *(uint8_t*) q;
-                r = message_peek_fields(m, ri, 1, l+1, &q);
-                if (r < 0)
-                        return r;
-        }
-
-        if (!validate_signature(q, l))
-                return -EBADMSG;
-
-        if (ret)
-                *ret = q;
-
-        return 0;
-}
-
-static int message_skip_fields(
-                sd_bus_message *m,
-                size_t *ri,
-                uint32_t array_size,
-                const char **signature) {
-
-        size_t original_index;
-        int r;
-
-        assert(m);
-        assert(ri);
-        assert(signature);
-        assert(!BUS_MESSAGE_IS_GVARIANT(m));
-
-        original_index = *ri;
-
-        for (;;) {
-                char t;
-                size_t l;
-
-                if (array_size != (uint32_t) -1 &&
-                    array_size <= *ri - original_index)
-                        return 0;
-
-                t = **signature;
-                if (!t)
-                        return 0;
-
-                if (t == SD_BUS_TYPE_STRING) {
-
-                        r = message_peek_field_string(m, NULL, ri, 0, NULL);
-                        if (r < 0)
-                                return r;
-
-                        (*signature)++;
-
-                } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
-
-                        r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
-                        if (r < 0)
-                                return r;
-
-                        (*signature)++;
-
-                } else if (t == SD_BUS_TYPE_SIGNATURE) {
-
-                        r = message_peek_field_signature(m, ri, 0, NULL);
-                        if (r < 0)
-                                return r;
-
-                        (*signature)++;
-
-                } else if (bus_type_is_basic(t)) {
-                        ssize_t align, k;
-
-                        align = bus_type_get_alignment(t);
-                        k = bus_type_get_size(t);
-                        assert(align > 0 && k > 0);
-
-                        r = message_peek_fields(m, ri, align, k, NULL);
-                        if (r < 0)
-                                return r;
-
-                        (*signature)++;
-
-                } else if (t == SD_BUS_TYPE_ARRAY) {
-
-                        r = signature_element_length(*signature+1, &l);
-                        if (r < 0)
-                                return r;
-
-                        assert(l >= 1);
-                        {
-                                char sig[l-1], *s;
-                                uint32_t nas;
-                                int alignment;
-
-                                strncpy(sig, *signature + 1, l-1);
-                                s = sig;
-
-                                alignment = bus_type_get_alignment(sig[0]);
-                                if (alignment < 0)
-                                        return alignment;
-
-                                r = message_peek_field_uint32(m, ri, 0, &nas);
-                                if (r < 0)
-                                        return r;
-                                if (nas > BUS_ARRAY_MAX_SIZE)
-                                        return -EBADMSG;
-
-                                r = message_peek_fields(m, ri, alignment, 0, NULL);
-                                if (r < 0)
-                                        return r;
-
-                                r = message_skip_fields(m, ri, nas, (const char**) &s);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        (*signature) += 1 + l;
-
-                } else if (t == SD_BUS_TYPE_VARIANT) {
-                        const char *s;
-
-                        r = message_peek_field_signature(m, ri, 0, &s);
-                        if (r < 0)
-                                return r;
-
-                        r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
-                        if (r < 0)
-                                return r;
-
-                        (*signature)++;
-
-                } else if (t == SD_BUS_TYPE_STRUCT ||
-                           t == SD_BUS_TYPE_DICT_ENTRY) {
-
-                        r = signature_element_length(*signature, &l);
-                        if (r < 0)
-                                return r;
-
-                        assert(l >= 2);
-                        {
-                                char sig[l-1], *s;
-                                strncpy(sig, *signature + 1, l-1);
-                                s = sig;
-
-                                r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        *signature += l;
-                } else
-                        return -EINVAL;
-        }
-}
-
-int bus_message_parse_fields(sd_bus_message *m) {
-        size_t ri;
-        int r;
-        uint32_t unix_fds = 0;
-        void *offsets = NULL;
-        unsigned n_offsets = 0;
-        size_t sz = 0;
-        unsigned i = 0;
-
-        assert(m);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                void *q;
-
-                sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0);
-                if (sz > 0) {
-                        size_t framing;
-
-                        ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz;
-                        r = message_peek_fields(m, &ri, 1, sz, &q);
-                        if (r < 0)
-                                return r;
-
-                        framing = read_word_le(q, sz);
-                        if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz)
-                                return -EBADMSG;
-                        if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0)
-                                return -EBADMSG;
-
-                        ri = framing;
-                        r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets);
-                        if (r < 0)
-                                return r;
-
-                        n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz;
-                }
-        }
-
-        ri = 0;
-        while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) {
-                _cleanup_free_ char *sig = NULL;
-                const char *signature;
-                uint8_t *header;
-                size_t item_size = (size_t) -1;
-
-                if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                        if (i >= n_offsets)
-                                break;
-
-                        if (i == 0)
-                                ri = 0;
-                        else
-                                ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
-                }
-
-                r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
-                if (r < 0)
-                        return r;
-
-                if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                        size_t where, end;
-                        char *b;
-                        void *q;
-
-                        end = read_word_le((uint8_t*) offsets + i*sz, sz);
-
-                        if (end < ri)
-                                return -EBADMSG;
-
-                        where = ri = ALIGN_TO(ri, 8);
-                        item_size = end - ri;
-                        r = message_peek_fields(m, &where, 1, item_size, &q);
-                        if (r < 0)
-                                return r;
-
-                        b = memrchr(q, 0, item_size);
-                        if (!b)
-                                return -EBADMSG;
-
-                        sig = strndup(b+1, item_size - (b+1-(char*) q));
-                        if (!sig)
-                                return -ENOMEM;
-
-                        signature = sig;
-                        item_size = b - (char*) q;
-                } else {
-                        r = message_peek_field_signature(m, &ri, 0, &signature);
-                        if (r < 0)
-                                return r;
-                }
-
-                switch (*header) {
-                case _BUS_MESSAGE_HEADER_INVALID:
-                        return -EBADMSG;
-
-                case BUS_MESSAGE_HEADER_PATH:
-
-                        if (m->path)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "o"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
-                        break;
-
-                case BUS_MESSAGE_HEADER_INTERFACE:
-
-                        if (m->interface)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "s"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
-                        break;
-
-                case BUS_MESSAGE_HEADER_MEMBER:
-
-                        if (m->member)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "s"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
-                        break;
-
-                case BUS_MESSAGE_HEADER_ERROR_NAME:
-
-                        if (m->error.name)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "s"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
-                        if (r >= 0)
-                                m->error._need_free = -1;
-
-                        break;
-
-                case BUS_MESSAGE_HEADER_DESTINATION:
-
-                        if (m->destination)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "s"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
-                        break;
-
-                case BUS_MESSAGE_HEADER_SENDER:
-
-                        if (m->sender)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "s"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
-
-                        if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
-                                m->creds.unique_name = (char*) m->sender;
-                                m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
-                        }
-
-                        break;
-
-
-                case BUS_MESSAGE_HEADER_SIGNATURE: {
-                        const char *s;
-                        char *c;
-
-                        if (m->root_container.signature)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "g"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_signature(m, &ri, item_size, &s);
-                        if (r < 0)
-                                return r;
-
-                        c = strdup(s);
-                        if (!c)
-                                return -ENOMEM;
-
-                        free(m->root_container.signature);
-                        m->root_container.signature = c;
-                        break;
-                }
-
-                case BUS_MESSAGE_HEADER_REPLY_SERIAL:
-                        if (m->reply_cookie != 0)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "u"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_uint32(m, &ri, item_size, &m->reply_cookie);
-                        if (r < 0)
-                                return r;
-
-                        if (m->reply_cookie == 0)
-                                return -EBADMSG;
-
-                        break;
-
-                case BUS_MESSAGE_HEADER_UNIX_FDS:
-                        if (unix_fds != 0)
-                                return -EBADMSG;
-
-                        if (!streq(signature, "u"))
-                                return -EBADMSG;
-
-                        r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
-                        if (r < 0)
-                                return -EBADMSG;
-
-                        if (unix_fds == 0)
-                                return -EBADMSG;
-
-                        break;
-
-                default:
-                        if (!BUS_MESSAGE_IS_GVARIANT(m))
-                                r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
-                }
-
-                if (r < 0)
-                        return r;
-
-                i++;
-        }
-
-        if (m->n_fds != unix_fds)
-                return -EBADMSG;
-
-        switch (m->header->type) {
-
-        case SD_BUS_MESSAGE_SIGNAL:
-                if (!m->path || !m->interface || !m->member)
-                        return -EBADMSG;
-                break;
-
-        case SD_BUS_MESSAGE_METHOD_CALL:
-
-                if (!m->path || !m->member)
-                        return -EBADMSG;
-
-                break;
-
-        case SD_BUS_MESSAGE_METHOD_RETURN:
-
-                if (m->reply_cookie == 0)
-                        return -EBADMSG;
-                break;
-
-        case SD_BUS_MESSAGE_METHOD_ERROR:
-
-                if (m->reply_cookie == 0 || !m->error.name)
-                        return -EBADMSG;
-                break;
-        }
-
-        /* Refuse non-local messages that claim they are local */
-        if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
-                return -EBADMSG;
-        if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
-                return -EBADMSG;
-        if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
-                return -EBADMSG;
-
-        m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
-
-        if (BUS_MESSAGE_IS_GVARIANT(m)) {
-                r = build_struct_offsets(
-                                m,
-                                m->root_container.signature,
-                                BUS_MESSAGE_BODY_SIZE(m),
-                                &m->root_container.item_size,
-                                &m->root_container.offsets,
-                                &m->root_container.n_offsets);
-                if (r < 0)
-                        return r;
-        }
-
-        /* Try to read the error message, but if we can't it's a non-issue */
-        if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
-                sd_bus_message_read(m, "s", &m->error.message);
-
-        return 0;
-}
-
-_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
-        assert_return(m, -EINVAL);
-        assert_return(destination, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->destination, -EEXIST);
-
-        return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
-}
-
-int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
-        size_t total;
-        void *p, *e;
-        unsigned i;
-        struct bus_body_part *part;
-
-        assert(m);
-        assert(buffer);
-        assert(sz);
-
-        total = BUS_MESSAGE_SIZE(m);
-
-        p = malloc(total);
-        if (!p)
-                return -ENOMEM;
-
-        e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
-        MESSAGE_FOREACH_PART(part, i, m)
-                e = mempcpy(e, part->data, part->size);
-
-        assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
-
-        *buffer = p;
-        *sz = total;
-
-        return 0;
-}
-
-int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
-        int r;
-
-        assert(m);
-        assert(l);
-
-        r = sd_bus_message_enter_container(m, 'a', "s");
-        if (r <= 0)
-                return r;
-
-        for (;;) {
-                const char *s;
-
-                r = sd_bus_message_read_basic(m, 's', &s);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                r = strv_extend(l, s);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
-        char **strv = NULL;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(l, -EINVAL);
-
-        r = bus_message_read_strv_extend(m, &strv);
-        if (r <= 0) {
-                strv_free(strv);
-                return r;
-        }
-
-        *l = strv;
-        return 1;
-}
-
-const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
-        int r;
-        const char *t = NULL;
-        unsigned j;
-
-        assert(m);
-
-        r = sd_bus_message_rewind(m, true);
-        if (r < 0)
-                return NULL;
-
-        for (j = 0; j <= i; j++) {
-                char type;
-
-                r = sd_bus_message_peek_type(m, &type, NULL);
-                if (r < 0)
-                        return NULL;
-
-                if (type != SD_BUS_TYPE_STRING &&
-                    type != SD_BUS_TYPE_OBJECT_PATH &&
-                    type != SD_BUS_TYPE_SIGNATURE)
-                        return NULL;
-
-                r = sd_bus_message_read_basic(m, type, &t);
-                if (r < 0)
-                        return NULL;
-        }
-
-        return t;
-}
-
-bool bus_header_is_complete(struct bus_header *h, size_t size) {
-        size_t full;
-
-        assert(h);
-        assert(size);
-
-        if (size < sizeof(struct bus_header))
-                return false;
-
-        full = sizeof(struct bus_header) +
-                (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
-
-        return size >= full;
-}
-
-int bus_header_message_size(struct bus_header *h, size_t *sum) {
-        size_t fs, bs;
-
-        assert(h);
-        assert(sum);
-
-        if (h->endian == BUS_NATIVE_ENDIAN) {
-                fs = h->fields_size;
-                bs = h->body_size;
-        } else if (h->endian == BUS_REVERSE_ENDIAN) {
-                fs = bswap_32(h->fields_size);
-                bs = bswap_32(h->body_size);
-        } else
-                return -EBADMSG;
-
-        *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
-        return 0;
-}
-
-_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
-        assert_return(m, -EINVAL);
-
-        if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
-                return 0;
-
-        return sd_bus_error_get_errno(&m->error);
-}
-
-_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
-        struct bus_container *c;
-
-        assert_return(m, NULL);
-
-        c = complete ? &m->root_container : message_get_container(m);
-        return strempty(c->signature);
-}
-
-_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
-        bool done_something = false;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(source, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(source->sealed, -EPERM);
-
-        do {
-                const char *contents;
-                char type;
-                union {
-                        uint8_t u8;
-                        uint16_t u16;
-                        int16_t s16;
-                        uint32_t u32;
-                        int32_t s32;
-                        uint64_t u64;
-                        int64_t s64;
-                        double d64;
-                        const char *string;
-                        int i;
-                } basic;
-
-                r = sd_bus_message_peek_type(source, &type, &contents);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                done_something = true;
-
-                if (bus_type_is_container(type) > 0) {
-
-                        r = sd_bus_message_enter_container(source, type, contents);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_open_container(m, type, contents);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_copy(m, source, true);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_close_container(m);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_exit_container(source);
-                        if (r < 0)
-                                return r;
-
-                        continue;
-                }
-
-                r = sd_bus_message_read_basic(source, type, &basic);
-                if (r < 0)
-                        return r;
-
-                assert(r > 0);
-
-                if (type == SD_BUS_TYPE_OBJECT_PATH ||
-                    type == SD_BUS_TYPE_SIGNATURE ||
-                    type == SD_BUS_TYPE_STRING)
-                        r = sd_bus_message_append_basic(m, type, basic.string);
-                else
-                        r = sd_bus_message_append_basic(m, type, &basic);
-
-                if (r < 0)
-                        return r;
-
-        } while (all);
-
-        return done_something;
-}
-
-_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
-        const char *c;
-        char t;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->sealed, -EPERM);
-        assert_return(!type || bus_type_is_valid(type), -EINVAL);
-        assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
-        assert_return(type || contents, -EINVAL);
-        assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
-
-        r = sd_bus_message_peek_type(m, &t, &c);
-        if (r <= 0)
-                return r;
-
-        if (type != 0 && type != t)
-                return 0;
-
-        if (contents && !streq_ptr(contents, c))
-                return 0;
-
-        return 1;
-}
-
-_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
-        assert_return(m, NULL);
-
-        return m->bus;
-}
-
-int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
-        _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
-        usec_t timeout;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(*m);
-
-        switch ((*m)->header->type) {
-
-        case SD_BUS_MESSAGE_SIGNAL:
-                r = sd_bus_message_new_signal(bus, (*m)->path, (*m)->interface, (*m)->member, &n);
-                if (r < 0)
-                        return r;
-
-                break;
-
-        case SD_BUS_MESSAGE_METHOD_CALL:
-                r = sd_bus_message_new_method_call(bus, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member, &n);
-                if (r < 0)
-                        return r;
-
-                break;
-
-        case SD_BUS_MESSAGE_METHOD_RETURN:
-        case SD_BUS_MESSAGE_METHOD_ERROR:
-
-                n = message_new(bus, (*m)->header->type);
-                if (!n)
-                        return -ENOMEM;
-
-                n->reply_cookie = (*m)->reply_cookie;
-                r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_cookie);
-                if (r < 0)
-                        return r;
-
-                if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
-                        r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
-                        if (r < 0)
-                                return r;
-
-                        n->error._need_free = -1;
-                }
-
-                break;
-
-        default:
-                return -EINVAL;
-        }
-
-        if ((*m)->destination && !n->destination) {
-                r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
-                if (r < 0)
-                        return r;
-        }
-
-        if ((*m)->sender && !n->sender) {
-                r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
-                if (r < 0)
-                        return r;
-        }
-
-        n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
-
-        r = sd_bus_message_copy(n, *m, true);
-        if (r < 0)
-                return r;
-
-        timeout = (*m)->timeout;
-        if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED))
-                timeout = BUS_DEFAULT_TIMEOUT;
-
-        r = bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
-        if (r < 0)
-                return r;
-
-        sd_bus_message_unref(*m);
-        *m = n;
-        n = NULL;
-
-        return 0;
-}
-
-int bus_message_append_sender(sd_bus_message *m, const char *sender) {
-        assert(m);
-        assert(sender);
-
-        assert_return(!m->sealed, -EPERM);
-        assert_return(!m->sender, -EPERM);
-
-        return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
-}
diff --git a/src/libsystemd/bus-message.h b/src/libsystemd/bus-message.h
deleted file mode 100644
index 5322375..0000000
--- a/src/libsystemd/bus-message.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*-*- 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 <stdbool.h>
-#include <byteswap.h>
-#include <sys/socket.h>
-
-#include "macro.h"
-#include "sd-bus.h"
-#include "kdbus.h"
-#include "time-util.h"
-#include "bus-creds.h"
-#include "bus-protocol.h"
-
-struct bus_container {
-        char enclosing;
-        bool need_offsets:1;
-
-        /* Indexes into the signature  string */
-        unsigned index, saved_index;
-        char *signature;
-
-        size_t before, begin, end;
-
-        /* dbus1: pointer to the array size value, if this is a value */
-        uint32_t *array_size;
-
-        /* gvariant: list of offsets to end of children if this is struct/dict entry/array */
-        size_t *offsets, n_offsets, offsets_allocated, offset_index;
-        size_t item_size;
-
-        char *peeked_signature;
-};
-
-struct bus_header {
-        uint8_t endian;
-        uint8_t type;
-        uint8_t flags;
-        uint8_t version;
-        uint32_t body_size;
-
-        /* Note that what the bus spec calls "serial" we'll call
-        "cookie" instead, because we don't want to imply that the
-        cookie was in any way monotonically increasing. */
-        uint32_t serial;
-        uint32_t fields_size;
-} _packed_;
-
-struct bus_body_part {
-        struct bus_body_part *next;
-        void *data;
-        size_t size;
-        size_t mapped;
-        size_t allocated;
-        int memfd;
-        bool free_this:1;
-        bool munmap_this:1;
-        bool sealed:1;
-        bool is_zero:1;
-};
-
-struct sd_bus_message {
-        unsigned n_ref;
-
-        sd_bus *bus;
-
-        uint32_t reply_cookie;
-
-        const char *path;
-        const char *interface;
-        const char *member;
-        const char *destination;
-        const char *sender;
-
-        sd_bus_error error;
-
-        sd_bus_creds creds;
-
-        usec_t monotonic;
-        usec_t realtime;
-
-        bool sealed:1;
-        bool dont_send:1;
-        bool allow_fds:1;
-        bool free_header:1;
-        bool free_kdbus:1;
-        bool free_fds:1;
-        bool release_kdbus:1;
-        bool poisoned:1;
-
-        struct bus_header *header;
-        struct bus_body_part body;
-        struct bus_body_part *body_end;
-        unsigned n_body_parts;
-
-        size_t rindex;
-        struct bus_body_part *cached_rindex_part;
-        size_t cached_rindex_part_begin;
-
-        uint32_t n_fds;
-        int *fds;
-
-        struct bus_container root_container, *containers;
-        unsigned n_containers;
-        size_t containers_allocated;
-
-        struct iovec *iovec;
-        struct iovec iovec_fixed[2];
-        unsigned n_iovec;
-
-        struct kdbus_msg *kdbus;
-
-        char *peeked_signature;
-
-        /* If set replies to this message must carry the signature
-         * specified here to successfully seal. This is initialized
-         * from the vtable data */
-        const char *enforced_reply_signature;
-
-        usec_t timeout;
-
-        char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
-        char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
-
-        size_t header_offsets[_BUS_MESSAGE_HEADER_MAX];
-        unsigned n_header_offsets;
-};
-
-#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != BUS_NATIVE_ENDIAN)
-
-static inline uint16_t BUS_MESSAGE_BSWAP16(sd_bus_message *m, uint16_t u) {
-        return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_16(u) : u;
-}
-
-static inline uint32_t BUS_MESSAGE_BSWAP32(sd_bus_message *m, uint32_t u) {
-        return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_32(u) : u;
-}
-
-static inline uint64_t BUS_MESSAGE_BSWAP64(sd_bus_message *m, uint64_t u) {
-        return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_64(u) : u;
-}
-
-static inline uint32_t BUS_MESSAGE_COOKIE(sd_bus_message *m) {
-        return BUS_MESSAGE_BSWAP32(m, m->header->serial);
-}
-
-static inline uint32_t BUS_MESSAGE_BODY_SIZE(sd_bus_message *m) {
-        return BUS_MESSAGE_BSWAP32(m, m->header->body_size);
-}
-
-static inline uint32_t BUS_MESSAGE_FIELDS_SIZE(sd_bus_message *m) {
-        return BUS_MESSAGE_BSWAP32(m, m->header->fields_size);
-}
-
-static inline uint32_t BUS_MESSAGE_SIZE(sd_bus_message *m) {
-        return
-                sizeof(struct bus_header) +
-                ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) +
-                BUS_MESSAGE_BODY_SIZE(m);
-}
-
-static inline uint32_t BUS_MESSAGE_BODY_BEGIN(sd_bus_message *m) {
-        return
-                sizeof(struct bus_header) +
-                ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
-}
-
-static inline void* BUS_MESSAGE_FIELDS(sd_bus_message *m) {
-        return (uint8_t*) m->header + sizeof(struct bus_header);
-}
-
-static inline bool BUS_MESSAGE_IS_GVARIANT(sd_bus_message *m) {
-        return m->header->version == 2;
-}
-
-int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout);
-int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);
-int bus_message_read_strv_extend(sd_bus_message *m, char ***l);
-
-int bus_message_from_header(
-                sd_bus *bus,
-                void *header,
-                size_t length,
-                int *fds,
-                unsigned n_fds,
-                const struct ucred *ucred,
-                const char *label,
-                size_t extra,
-                sd_bus_message **ret);
-
-int bus_message_from_malloc(
-                sd_bus *bus,
-                void *buffer,
-                size_t length,
-                int *fds,
-                unsigned n_fds,
-                const struct ucred *ucred,
-                const char *label,
-                sd_bus_message **ret);
-
-const char* bus_message_get_arg(sd_bus_message *m, unsigned i);
-
-int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
-
-int bus_message_parse_fields(sd_bus_message *m);
-
-bool bus_header_is_complete(struct bus_header *h, size_t size);
-int bus_header_message_size(struct bus_header *h, size_t *sum);
-
-struct bus_body_part *message_append_part(sd_bus_message *m);
-
-#define MESSAGE_FOREACH_PART(part, i, m) \
-        for ((i) = 0, (part) = &(m)->body; (i) < (m)->n_body_parts; (i)++, (part) = (part)->next)
-
-int bus_body_part_map(struct bus_body_part *part);
-void bus_body_part_unmap(struct bus_body_part *part);
-
-int bus_message_to_errno(sd_bus_message *m);
-
-int bus_message_new_synthetic_error(sd_bus *bus, uint64_t serial, const sd_bus_error *e, sd_bus_message **m);
-
-int bus_message_remarshal(sd_bus *bus, sd_bus_message **m);
-
-int bus_message_append_sender(sd_bus_message *m, const char *sender);
diff --git a/src/libsystemd/bus-objects.c b/src/libsystemd/bus-objects.c
deleted file mode 100644
index b116a5d..0000000
--- a/src/libsystemd/bus-objects.c
+++ /dev/null
@@ -1,2507 +0,0 @@
-/*-*- 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 <sys/capability.h>
-
-#include "strv.h"
-#include "set.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-type.h"
-#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,
-                const char *path,
-                struct node_vtable *c,
-                void **userdata,
-                sd_bus_error *error) {
-
-        void *u;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(c);
-
-        u = c->userdata;
-        if (c->find) {
-                r = c->find(bus, path, c->interface, u, &u, error);
-                if (r < 0)
-                        return r;
-                if (sd_bus_error_is_set(error))
-                        return -sd_bus_error_get_errno(error);
-                if (r == 0)
-                        return r;
-        }
-
-        if (userdata)
-                *userdata = u;
-
-        return 1;
-}
-
-static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
-        assert(p);
-
-        return (uint8_t*) u + p->x.property.offset;
-}
-
-static int vtable_property_get_userdata(
-                sd_bus *bus,
-                const char *path,
-                struct vtable_member *p,
-                void **userdata,
-                sd_bus_error *error) {
-
-        void *u;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(p);
-        assert(userdata);
-
-        r = node_vtable_get_userdata(bus, path, p->parent, &u, error);
-        if (r <= 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        *userdata = vtable_property_convert_userdata(p->vtable, u);
-        return 1;
-}
-
-static int add_enumerated_to_set(
-                sd_bus *bus,
-                const char *prefix,
-                struct node_enumerator *first,
-                Set *s,
-                sd_bus_error *error) {
-
-        struct node_enumerator *c;
-        int r;
-
-        assert(bus);
-        assert(prefix);
-        assert(s);
-
-        LIST_FOREACH(enumerators, c, first) {
-                char **children = NULL, **k;
-
-                if (bus->nodes_modified)
-                        return 0;
-
-                r = c->callback(bus, prefix, c->userdata, &children, error);
-                if (r < 0)
-                        return r;
-                if (sd_bus_error_is_set(error))
-                        return -sd_bus_error_get_errno(error);
-
-                STRV_FOREACH(k, children) {
-                        if (r < 0) {
-                                free(*k);
-                                continue;
-                        }
-
-                        if (!object_path_is_valid(*k)){
-                                free(*k);
-                                r = -EINVAL;
-                                continue;
-                        }
-
-                        if (!object_path_startswith(*k, prefix)) {
-                                free(*k);
-                                continue;
-                        }
-
-                        r = set_consume(s, *k);
-                        if (r == -EEXIST)
-                                r = 0;
-                }
-
-                free(children);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int add_subtree_to_set(
-                sd_bus *bus,
-                const char *prefix,
-                struct node *n,
-                Set *s,
-                sd_bus_error *error) {
-
-        struct node *i;
-        int r;
-
-        assert(bus);
-        assert(prefix);
-        assert(n);
-        assert(s);
-
-        r = add_enumerated_to_set(bus, prefix, n->enumerators, s, error);
-        if (r < 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        LIST_FOREACH(siblings, i, n->child) {
-                char *t;
-
-                if (!object_path_startswith(i->path, prefix))
-                        continue;
-
-                t = strdup(i->path);
-                if (!t)
-                        return -ENOMEM;
-
-                r = set_consume(s, t);
-                if (r < 0 && r != -EEXIST)
-                        return r;
-
-                r = add_subtree_to_set(bus, prefix, i, s, error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        return 0;
-}
-
-static int get_child_nodes(
-                sd_bus *bus,
-                const char *prefix,
-                struct node *n,
-                Set **_s,
-                sd_bus_error *error) {
-
-        Set *s = NULL;
-        int r;
-
-        assert(bus);
-        assert(prefix);
-        assert(n);
-        assert(_s);
-
-        s = set_new(string_hash_func, string_compare_func);
-        if (!s)
-                return -ENOMEM;
-
-        r = add_subtree_to_set(bus, prefix, n, s, error);
-        if (r < 0) {
-                set_free_free(s);
-                return r;
-        }
-
-        *_s = s;
-        return 0;
-}
-
-static int node_callbacks_run(
-                sd_bus *bus,
-                sd_bus_message *m,
-                struct node_callback *first,
-                bool require_fallback,
-                bool *found_object) {
-
-        struct node_callback *c;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(found_object);
-
-        LIST_FOREACH(callbacks, c, first) {
-                _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-
-                if (bus->nodes_modified)
-                        return 0;
-
-                if (require_fallback && !c->is_fallback)
-                        continue;
-
-                *found_object = true;
-
-                if (c->last_iteration == bus->iteration_counter)
-                        continue;
-
-                c->last_iteration = bus->iteration_counter;
-
-                r = sd_bus_message_rewind(m, true);
-                if (r < 0)
-                        return r;
-
-                r = c->callback(bus, m, c->userdata, &error_buffer);
-                r = bus_maybe_reply_error(m, r, &error_buffer);
-                if (r != 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-#define CAPABILITY_SHIFT(x) (((x) >> __builtin_ctzll(_SD_BUS_VTABLE_CAPABILITY_MASK)) & 0xFFFF)
-
-static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) {
-        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-        uint64_t cap;
-        uid_t uid;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(c);
-
-        /* If the entire bus is trusted let's grant access */
-        if (bus->trusted)
-                return 0;
-
-        /* If the member is marked UNPRIVILEGED let's grant access */
-        if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED)
-                return 0;
-
-        /* If we are not connected to kdbus we cannot retrieve the
-         * effective capability set without race. Since we need this
-         * for a security decision we cannot use racy data, hence
-         * don't request it. */
-        if (bus->is_kernel)
-                r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
-        else
-                r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
-        if (r < 0)
-                return r;
-
-        /* Check have the caller has the requested capability
-         * set. Note that the flags value contains the capability
-         * number plus one, which we need to subtract here. We do this
-         * so that we have 0 as special value for "default
-         * capability". */
-        cap = CAPABILITY_SHIFT(c->vtable->flags);
-        if (cap == 0)
-                cap = CAPABILITY_SHIFT(c->parent->vtable[0].flags);
-        if (cap == 0)
-                cap = CAP_SYS_ADMIN;
-        else
-                cap --;
-
-        r = sd_bus_creds_has_effective_cap(creds, cap);
-        if (r > 0)
-                return 1;
-
-        /* Caller has same UID as us, then let's grant access */
-        r = sd_bus_creds_get_uid(creds, &uid);
-        if (r >= 0) {
-                if (uid == getuid())
-                        return 1;
-        }
-
-        return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member);
-}
-
-static int method_callbacks_run(
-                sd_bus *bus,
-                sd_bus_message *m,
-                struct vtable_member *c,
-                bool require_fallback,
-                bool *found_object) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *signature;
-        void *u;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(c);
-        assert(found_object);
-
-        if (require_fallback && !c->parent->is_fallback)
-                return 0;
-
-        r = check_access(bus, m, c, &error);
-        if (r < 0)
-                return bus_maybe_reply_error(m, r, &error);
-
-        r = node_vtable_get_userdata(bus, m->path, c->parent, &u, &error);
-        if (r <= 0)
-                return bus_maybe_reply_error(m, r, &error);
-        if (bus->nodes_modified)
-                return 0;
-
-        *found_object = true;
-
-        if (c->last_iteration == bus->iteration_counter)
-                return 0;
-
-        c->last_iteration = bus->iteration_counter;
-
-        r = sd_bus_message_rewind(m, true);
-        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))
-                return sd_bus_reply_method_errorf(
-                                m,
-                                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));
-
-        /* Keep track what the signature of the reply to this message
-         * should be, so that this can be enforced when sealing the
-         * reply. */
-        m->enforced_reply_signature = strempty(c->vtable->x.method.result);
-
-        if (c->vtable->x.method.handler) {
-                r = c->vtable->x.method.handler(bus, m, u, &error);
-                return bus_maybe_reply_error(m, r, &error);
-        }
-
-        /* If the method callback is NULL, make this a successful NOP */
-        r = sd_bus_reply_method_return(m, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int invoke_property_get(
-                sd_bus *bus,
-                const sd_bus_vtable *v,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        const void *p;
-        int r;
-
-        assert(bus);
-        assert(v);
-        assert(path);
-        assert(interface);
-        assert(property);
-        assert(reply);
-
-        if (v->x.property.get) {
-                r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
-                if (r < 0)
-                        return r;
-                if (sd_bus_error_is_set(error))
-                        return -sd_bus_error_get_errno(error);
-                return r;
-        }
-
-        /* Automatic handling if no callback is defined. */
-
-        if (streq(v->x.property.signature, "as"))
-                return sd_bus_message_append_strv(reply, *(char***) userdata);
-
-        assert(signature_is_single(v->x.property.signature, false));
-        assert(bus_type_is_basic(v->x.property.signature[0]));
-
-        switch (v->x.property.signature[0]) {
-
-        case SD_BUS_TYPE_STRING:
-        case SD_BUS_TYPE_SIGNATURE:
-                p = strempty(*(char**) userdata);
-                break;
-
-        case SD_BUS_TYPE_OBJECT_PATH:
-                p = *(char**) userdata;
-                assert(p);
-                break;
-
-        default:
-                p = userdata;
-                break;
-        }
-
-        return sd_bus_message_append_basic(reply, v->x.property.signature[0], p);
-}
-
-static int invoke_property_set(
-                sd_bus *bus,
-                const sd_bus_vtable *v,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *value,
-                void *userdata,
-                sd_bus_error *error) {
-
-        int r;
-
-        assert(bus);
-        assert(v);
-        assert(path);
-        assert(interface);
-        assert(property);
-        assert(value);
-
-        if (v->x.property.set) {
-                r = v->x.property.set(bus, path, interface, property, value, userdata, error);
-                if (r < 0)
-                        return r;
-                if (sd_bus_error_is_set(error))
-                        return -sd_bus_error_get_errno(error);
-                return r;
-        }
-
-        /*  Automatic handling if no callback is defined. */
-
-        assert(signature_is_single(v->x.property.signature, false));
-        assert(bus_type_is_basic(v->x.property.signature[0]));
-
-        switch (v->x.property.signature[0]) {
-
-        case SD_BUS_TYPE_STRING:
-        case SD_BUS_TYPE_OBJECT_PATH:
-        case SD_BUS_TYPE_SIGNATURE: {
-                const char *p;
-                char *n;
-
-                r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p);
-                if (r < 0)
-                        return r;
-
-                n = strdup(p);
-                if (!n)
-                        return -ENOMEM;
-
-                free(*(char**) userdata);
-                *(char**) userdata = n;
-
-                break;
-        }
-
-        default:
-                r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata);
-                if (r < 0)
-                        return r;
-
-                break;
-        }
-
-        return 1;
-}
-
-static int property_get_set_callbacks_run(
-                sd_bus *bus,
-                sd_bus_message *m,
-                struct vtable_member *c,
-                bool require_fallback,
-                bool is_get,
-                bool *found_object) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        void *u;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(c);
-        assert(found_object);
-
-        if (require_fallback && !c->parent->is_fallback)
-                return 0;
-
-        r = vtable_property_get_userdata(bus, m->path, c, &u, &error);
-        if (r <= 0)
-                return bus_maybe_reply_error(m, r, &error);
-        if (bus->nodes_modified)
-                return 0;
-
-        *found_object = true;
-
-        r = sd_bus_message_new_method_return(m, &reply);
-        if (r < 0)
-                return r;
-
-        if (is_get) {
-                /* Note that we do not protect against reexecution
-                 * here (using the last_iteration check, see below),
-                 * should the node tree have changed and we got called
-                 * again. We assume that property Get() calls are
-                 * ultimately without side-effects or if they aren't
-                 * then at least idempotent. */
-
-                r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature);
-                if (r < 0)
-                        return r;
-
-                /* Note that we do not do an access check here. Read
-                 * access to properties is always unrestricted, since
-                 * PropertiesChanged signals broadcast contents
-                 * anyway. */
-
-                r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, u, &error);
-                if (r < 0)
-                        return bus_maybe_reply_error(m, r, &error);
-
-                if (bus->nodes_modified)
-                        return 0;
-
-                r = sd_bus_message_close_container(reply);
-                if (r < 0)
-                        return r;
-
-        } else {
-                if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
-                        return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
-
-                /* Avoid that we call the set routine more than once
-                 * if the processing of this message got restarted
-                 * because the node tree changed. */
-                if (c->last_iteration == bus->iteration_counter)
-                        return 0;
-
-                c->last_iteration = bus->iteration_counter;
-
-                r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
-                if (r < 0)
-                        return r;
-
-                r = check_access(bus, m, c, &error);
-                if (r < 0)
-                        return bus_maybe_reply_error(m, r, &error);
-
-                r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, u, &error);
-                if (r < 0)
-                        return bus_maybe_reply_error(m, r, &error);
-
-                if (bus->nodes_modified)
-                        return 0;
-
-                r = sd_bus_message_exit_container(m);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_bus_send(bus, reply, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int vtable_append_one_property(
-                sd_bus *bus,
-                sd_bus_message *reply,
-                const char *path,
-                struct node_vtable *c,
-                const sd_bus_vtable *v,
-                void *userdata,
-                sd_bus_error *error) {
-
-        int r;
-
-        assert(bus);
-        assert(reply);
-        assert(path);
-        assert(c);
-        assert(v);
-
-        r = sd_bus_message_open_container(reply, 'e', "sv");
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append(reply, "s", v->x.property.member);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
-        if (r < 0)
-                return r;
-
-        r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
-        if (r < 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        r = sd_bus_message_close_container(reply);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_close_container(reply);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static int vtable_append_all_properties(
-                sd_bus *bus,
-                sd_bus_message *reply,
-                const char *path,
-                struct node_vtable *c,
-                void *userdata,
-                sd_bus_error *error) {
-
-        const sd_bus_vtable *v;
-        int r;
-
-        assert(bus);
-        assert(reply);
-        assert(path);
-        assert(c);
-
-        if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
-                return 1;
-
-        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
-                if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
-                        continue;
-
-                if (v->flags & SD_BUS_VTABLE_HIDDEN)
-                        continue;
-
-                r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        return 1;
-}
-
-static int property_get_all_callbacks_run(
-                sd_bus *bus,
-                sd_bus_message *m,
-                struct node_vtable *first,
-                bool require_fallback,
-                const char *iface,
-                bool *found_object) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        struct node_vtable *c;
-        bool found_interface;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(found_object);
-
-        r = sd_bus_message_new_method_return(m, &reply);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_open_container(reply, 'a', "{sv}");
-        if (r < 0)
-                return r;
-
-        found_interface = !iface ||
-                streq(iface, "org.freedesktop.DBus.Properties") ||
-                streq(iface, "org.freedesktop.DBus.Peer") ||
-                streq(iface, "org.freedesktop.DBus.Introspectable");
-
-        LIST_FOREACH(vtables, c, first) {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-                void *u;
-
-                if (require_fallback && !c->is_fallback)
-                        continue;
-
-                r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
-                if (r < 0)
-                        return bus_maybe_reply_error(m, r, &error);
-                if (bus->nodes_modified)
-                        return 0;
-                if (r == 0)
-                        continue;
-
-                *found_object = true;
-
-                if (iface && !streq(c->interface, iface))
-                        continue;
-                found_interface = true;
-
-                r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
-                if (r < 0)
-                        return bus_maybe_reply_error(m, r, &error);
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        if (!found_interface) {
-                r = sd_bus_reply_method_errorf(
-                                m,
-                                SD_BUS_ERROR_UNKNOWN_INTERFACE,
-                                "Unknown interface '%s'.", iface);
-                if (r < 0)
-                        return r;
-
-                return 1;
-        }
-
-        r = sd_bus_message_close_container(reply);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_send(bus, reply, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
-        assert(bus);
-        assert(n);
-
-        if (n->object_manager)
-                return true;
-
-        if (n->parent)
-                return bus_node_with_object_manager(bus, n->parent);
-
-        return false;
-}
-
-static bool bus_node_exists(
-                sd_bus *bus,
-                struct node *n,
-                const char *path,
-                bool require_fallback) {
-
-        struct node_vtable *c;
-        struct node_callback *k;
-
-        assert(bus);
-        assert(n);
-        assert(path);
-
-        /* Tests if there's anything attached directly to this node
-         * for the specified path */
-
-        LIST_FOREACH(callbacks, k, n->callbacks) {
-                if (require_fallback && !k->is_fallback)
-                        continue;
-
-                return true;
-        }
-
-        LIST_FOREACH(vtables, c, n->vtables) {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
-                if (require_fallback && !c->is_fallback)
-                        continue;
-
-                if (node_vtable_get_userdata(bus, path, c, NULL, &error) > 0)
-                        return true;
-                if (bus->nodes_modified)
-                        return false;
-        }
-
-        return !require_fallback && (n->enumerators || n->object_manager);
-}
-
-static int process_introspect(
-                sd_bus *bus,
-                sd_bus_message *m,
-                struct node *n,
-                bool require_fallback,
-                bool *found_object) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_set_free_free_ Set *s = NULL;
-        const char *previous_interface = NULL;
-        struct introspect intro;
-        struct node_vtable *c;
-        bool empty;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(n);
-        assert(found_object);
-
-        r = get_child_nodes(bus, m->path, n, &s, &error);
-        if (r < 0)
-                return bus_maybe_reply_error(m, r, &error);
-        if (bus->nodes_modified)
-                return 0;
-
-        r = introspect_begin(&intro, bus->trusted);
-        if (r < 0)
-                return r;
-
-        r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
-        if (r < 0)
-                return r;
-
-        empty = set_isempty(s);
-
-        LIST_FOREACH(vtables, c, n->vtables) {
-                if (require_fallback && !c->is_fallback)
-                        continue;
-
-                r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
-                if (r < 0) {
-                        r = bus_maybe_reply_error(m, r, &error);
-                        goto finish;
-                }
-                if (bus->nodes_modified) {
-                        r = 0;
-                        goto finish;
-                }
-                if (r == 0)
-                        continue;
-
-                empty = false;
-
-                if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
-                        continue;
-
-                if (!streq_ptr(previous_interface, c->interface)) {
-
-                        if (previous_interface)
-                                fputs(" </interface>\n", intro.f);
-
-                        fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
-                }
-
-                r = introspect_write_interface(&intro, c->vtable);
-                if (r < 0)
-                        goto finish;
-
-                previous_interface = c->interface;
-        }
-
-        if (previous_interface)
-                fputs(" </interface>\n", intro.f);
-
-        if (empty) {
-                /* Nothing?, let's see if we exist at all, and if not
-                 * refuse to do anything */
-                r = bus_node_exists(bus, n, m->path, require_fallback);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-                if (r == 0)
-                        goto finish;
-        }
-
-        *found_object = true;
-
-        r = introspect_write_child_nodes(&intro, s, m->path);
-        if (r < 0)
-                goto finish;
-
-        r = introspect_finish(&intro, bus, m, &reply);
-        if (r < 0)
-                goto finish;
-
-        r = sd_bus_send(bus, reply, NULL);
-        if (r < 0)
-                goto finish;
-
-        r = 1;
-
-finish:
-        introspect_free(&intro);
-        return r;
-}
-
-static int object_manager_serialize_path(
-                sd_bus *bus,
-                sd_bus_message *reply,
-                const char *prefix,
-                const char *path,
-                bool require_fallback,
-                sd_bus_error *error) {
-
-        const char *previous_interface = NULL;
-        bool found_something = false;
-        struct node_vtable *i;
-        struct node *n;
-        int r;
-
-        assert(bus);
-        assert(reply);
-        assert(prefix);
-        assert(path);
-        assert(error);
-
-        n = hashmap_get(bus->nodes, prefix);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(vtables, i, n->vtables) {
-                void *u;
-
-                if (require_fallback && !i->is_fallback)
-                        continue;
-
-                r = node_vtable_get_userdata(bus, path, i, &u, error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-                if (r == 0)
-                        continue;
-
-                if (!found_something) {
-
-                        /* Open the object part */
-
-                        r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_append(reply, "o", path);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
-                        if (r < 0)
-                                return r;
-
-                        found_something = true;
-                }
-
-                if (!streq_ptr(previous_interface, i->interface)) {
-
-                        /* Maybe close the previous interface part */
-
-                        if (previous_interface) {
-                                r = sd_bus_message_close_container(reply);
-                                if (r < 0)
-                                        return r;
-
-                                r = sd_bus_message_close_container(reply);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        /* Open the new interface part */
-
-                        r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_append(reply, "s", i->interface);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_open_container(reply, 'a', "{sv}");
-                        if (r < 0)
-                                return r;
-                }
-
-                r = vtable_append_all_properties(bus, reply, path, i, u, error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-
-                previous_interface = i->interface;
-        }
-
-        if (previous_interface) {
-                r = sd_bus_message_close_container(reply);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_close_container(reply);
-                if (r < 0)
-                        return r;
-        }
-
-        if (found_something) {
-                r = sd_bus_message_close_container(reply);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_close_container(reply);
-                if (r < 0)
-                        return r;
-        }
-
-        return 1;
-}
-
-static int object_manager_serialize_path_and_fallbacks(
-                sd_bus *bus,
-                sd_bus_message *reply,
-                const char *path,
-                sd_bus_error *error) {
-
-        char *prefix;
-        int r;
-
-        assert(bus);
-        assert(reply);
-        assert(path);
-        assert(error);
-
-        /* First, add all vtables registered for this path */
-        r = object_manager_serialize_path(bus, reply, path, path, false, error);
-        if (r < 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        /* Second, add fallback vtables registered for any of the prefixes */
-        prefix = alloca(strlen(path) + 1);
-        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
-                r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        return 0;
-}
-
-static int process_get_managed_objects(
-                sd_bus *bus,
-                sd_bus_message *m,
-                struct node *n,
-                bool require_fallback,
-                bool *found_object) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_set_free_free_ Set *s = NULL;
-        bool empty;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(n);
-        assert(found_object);
-
-        if (!bus_node_with_object_manager(bus, n))
-                return 0;
-
-        r = get_child_nodes(bus, m->path, n, &s, &error);
-        if (r < 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        r = sd_bus_message_new_method_return(m, &reply);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
-        if (r < 0)
-                return r;
-
-        empty = set_isempty(s);
-        if (empty) {
-                struct node_vtable *c;
-
-                /* Hmm, so we have no children? Then let's check
-                 * whether we exist at all, i.e. whether at least one
-                 * vtable exists. */
-
-                LIST_FOREACH(vtables, c, n->vtables) {
-
-                        if (require_fallback && !c->is_fallback)
-                                continue;
-
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                continue;
-
-                        empty = false;
-                        break;
-                }
-
-                if (empty)
-                        return 0;
-        } else {
-                Iterator i;
-                char *path;
-
-                SET_FOREACH(path, s, i) {
-                        r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
-                        if (r < 0)
-                                return r;
-
-                        if (bus->nodes_modified)
-                                return 0;
-                }
-        }
-
-        r = sd_bus_message_close_container(reply);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_send(bus, reply, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int object_find_and_run(
-                sd_bus *bus,
-                sd_bus_message *m,
-                const char *p,
-                bool require_fallback,
-                bool *found_object) {
-
-        struct node *n;
-        struct vtable_member vtable_key, *v;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(p);
-        assert(found_object);
-
-        n = hashmap_get(bus->nodes, p);
-        if (!n)
-                return 0;
-
-        /* First, try object callbacks */
-        r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
-        if (r != 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        if (!m->interface || !m->member)
-                return 0;
-
-        /* Then, look for a known method */
-        vtable_key.path = (char*) p;
-        vtable_key.interface = m->interface;
-        vtable_key.member = m->member;
-
-        v = hashmap_get(bus->vtable_methods, &vtable_key);
-        if (v) {
-                r = method_callbacks_run(bus, m, v, require_fallback, found_object);
-                if (r != 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        /* Then, look for a known property */
-        if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
-                bool get = false;
-
-                get = streq(m->member, "Get");
-
-                if (get || streq(m->member, "Set")) {
-
-                        r = sd_bus_message_rewind(m, true);
-                        if (r < 0)
-                                return r;
-
-                        vtable_key.path = (char*) p;
-
-                        r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
-                        if (r < 0)
-                                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
-
-                        v = hashmap_get(bus->vtable_properties, &vtable_key);
-                        if (v) {
-                                r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
-                                if (r != 0)
-                                        return r;
-                        }
-
-                } else if (streq(m->member, "GetAll")) {
-                        const char *iface;
-
-                        r = sd_bus_message_rewind(m, true);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_read(m, "s", &iface);
-                        if (r < 0)
-                                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
-
-                        if (iface[0] == 0)
-                                iface = NULL;
-
-                        r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
-                        if (r != 0)
-                                return r;
-                }
-
-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-
-                if (!isempty(sd_bus_message_get_signature(m, true)))
-                        return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
-
-                r = process_introspect(bus, m, n, require_fallback, found_object);
-                if (r != 0)
-                        return r;
-
-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
-
-                if (!isempty(sd_bus_message_get_signature(m, true)))
-                        return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
-
-                r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
-                if (r != 0)
-                        return r;
-        }
-
-        if (bus->nodes_modified)
-                return 0;
-
-        if (!*found_object) {
-                r = bus_node_exists(bus, n, m->path, require_fallback);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        *found_object = true;
-        }
-
-        return 0;
-}
-
-int bus_process_object(sd_bus *bus, sd_bus_message *m) {
-        int r;
-        size_t pl;
-        bool found_object = false;
-
-        assert(bus);
-        assert(m);
-
-        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
-                return 0;
-
-        if (hashmap_isempty(bus->nodes))
-                return 0;
-
-        /* Never respond to broadcast messages */
-        if (bus->bus_client && !m->destination)
-                return 0;
-
-        assert(m->path);
-        assert(m->member);
-
-        pl = strlen(m->path);
-        do {
-                char prefix[pl+1];
-
-                bus->nodes_modified = false;
-
-                r = object_find_and_run(bus, m, m->path, false, &found_object);
-                if (r != 0)
-                        return r;
-
-                /* Look for fallback prefixes */
-                OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
-
-                        if (bus->nodes_modified)
-                                break;
-
-                        r = object_find_and_run(bus, m, prefix, true, &found_object);
-                        if (r != 0)
-                                return r;
-                }
-
-        } while (bus->nodes_modified);
-
-        if (!found_object)
-                return 0;
-
-        if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
-            sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
-                r = sd_bus_reply_method_errorf(
-                                m,
-                                SD_BUS_ERROR_UNKNOWN_PROPERTY,
-                                "Unknown property or interface.");
-        else
-                r = sd_bus_reply_method_errorf(
-                                m,
-                                SD_BUS_ERROR_UNKNOWN_METHOD,
-                                "Unknown method '%s' or interface '%s'.", m->member, m->interface);
-
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
-        struct node *n, *parent;
-        const char *e;
-        _cleanup_free_ char *s = NULL;
-        char *p;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(path[0] == '/');
-
-        n = hashmap_get(bus->nodes, path);
-        if (n)
-                return n;
-
-        r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
-        if (r < 0)
-                return NULL;
-
-        s = strdup(path);
-        if (!s)
-                return NULL;
-
-        if (streq(path, "/"))
-                parent = NULL;
-        else {
-                e = strrchr(path, '/');
-                assert(e);
-
-                p = strndupa(path, MAX(1, path - e));
-
-                parent = bus_node_allocate(bus, p);
-                if (!parent)
-                        return NULL;
-        }
-
-        n = new0(struct node, 1);
-        if (!n)
-                return NULL;
-
-        n->parent = parent;
-        n->path = s;
-        s = NULL; /* do not free */
-
-        r = hashmap_put(bus->nodes, n->path, n);
-        if (r < 0) {
-                free(n->path);
-                free(n);
-                return NULL;
-        }
-
-        if (parent)
-                LIST_PREPEND(siblings, parent->child, n);
-
-        return n;
-}
-
-static void bus_node_gc(sd_bus *b, struct node *n) {
-        assert(b);
-
-        if (!n)
-                return;
-
-        if (n->child ||
-            n->callbacks ||
-            n->vtables ||
-            n->enumerators ||
-            n->object_manager)
-                return;
-
-        assert(hashmap_remove(b->nodes, n->path) == n);
-
-        if (n->parent)
-                LIST_REMOVE(siblings, n->parent->child, n);
-
-        free(n->path);
-        bus_node_gc(b, n->parent);
-        free(n);
-}
-
-static int bus_add_object(
-                sd_bus *bus,
-                bool fallback,
-                const char *path,
-                sd_bus_message_handler_t callback,
-                void *userdata) {
-
-        struct node_callback *c;
-        struct node *n;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = bus_node_allocate(bus, path);
-        if (!n)
-                return -ENOMEM;
-
-        c = new0(struct node_callback, 1);
-        if (!c) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        c->node = n;
-        c->callback = callback;
-        c->userdata = userdata;
-        c->is_fallback = fallback;
-
-        LIST_PREPEND(callbacks, n->callbacks, c);
-        bus->nodes_modified = true;
-
-        return 0;
-
-fail:
-        free(c);
-        bus_node_gc(bus, n);
-        return r;
-}
-
-static int bus_remove_object(
-                sd_bus *bus,
-                bool fallback,
-                const char *path,
-                sd_bus_message_handler_t callback,
-                void *userdata) {
-
-        struct node_callback *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(callbacks, c, n->callbacks)
-                if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
-                        break;
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(callbacks, n->callbacks, c);
-        free(c);
-
-        bus_node_gc(bus, n);
-        bus->nodes_modified = true;
-
-        return 1;
-}
-
-_public_ int sd_bus_add_object(sd_bus *bus,
-                               const char *path,
-                               sd_bus_message_handler_t callback,
-                               void *userdata) {
-
-        return bus_add_object(bus, false, path, callback, userdata);
-}
-
-_public_ int sd_bus_remove_object(sd_bus *bus,
-                                  const char *path,
-                                  sd_bus_message_handler_t callback,
-                                  void *userdata) {
-
-        return bus_remove_object(bus, false, path, callback, userdata);
-}
-
-_public_ int sd_bus_add_fallback(sd_bus *bus,
-                                 const char *prefix,
-                                 sd_bus_message_handler_t callback,
-                                 void *userdata) {
-
-        return bus_add_object(bus, true, prefix, callback, userdata);
-}
-
-_public_ int sd_bus_remove_fallback(sd_bus *bus,
-                                    const char *prefix,
-                                    sd_bus_message_handler_t callback,
-                                    void *userdata) {
-
-        return bus_remove_object(bus, true, prefix, callback, userdata);
-}
-
-static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
-        assert(bus);
-
-        if (!w)
-                return;
-
-        if (w->interface && w->node && w->vtable) {
-                const sd_bus_vtable *v;
-
-                for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
-                        struct vtable_member *x = NULL;
-
-                        switch (v->type) {
-
-                        case _SD_BUS_VTABLE_METHOD: {
-                                struct vtable_member key;
-
-                                key.path = w->node->path;
-                                key.interface = w->interface;
-                                key.member = v->x.method.member;
-
-                                x = hashmap_remove(bus->vtable_methods, &key);
-                                break;
-                        }
-
-                        case _SD_BUS_VTABLE_PROPERTY:
-                        case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
-                                struct vtable_member key;
-
-                                key.path = w->node->path;
-                                key.interface = w->interface;
-                                key.member = v->x.property.member;
-                                x = hashmap_remove(bus->vtable_properties, &key);
-                                break;
-                        }}
-
-                        free(x);
-                }
-        }
-
-        free(w->interface);
-        free(w);
-}
-
-static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
-        const struct vtable_member *m = a;
-        uint8_t hash_key2[HASH_KEY_SIZE];
-        unsigned long ret;
-
-        assert(m);
-
-        ret = string_hash_func(m->path, hash_key);
-
-        /* Use a slightly different hash key for the interface */
-        memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
-        hash_key2[0]++;
-        ret ^= string_hash_func(m->interface, hash_key2);
-
-        /* And an even different one for the  member */
-        hash_key2[0]++;
-        ret ^= string_hash_func(m->member, hash_key2);
-
-        return ret;
-}
-
-static int vtable_member_compare_func(const void *a, const void *b) {
-        const struct vtable_member *x = a, *y = b;
-        int r;
-
-        assert(x);
-        assert(y);
-
-        r = strcmp(x->path, y->path);
-        if (r != 0)
-                return r;
-
-        r = strcmp(x->interface, y->interface);
-        if (r != 0)
-                return r;
-
-        return strcmp(x->member, y->member);
-}
-
-static int add_object_vtable_internal(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                bool fallback,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        struct node_vtable *c = NULL, *i, *existing = NULL;
-        const sd_bus_vtable *v;
-        struct node *n;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(vtable, -EINVAL);
-        assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
-        assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
-                      !streq(interface, "org.freedesktop.DBus.Introspectable") &&
-                      !streq(interface, "org.freedesktop.DBus.Peer") &&
-                      !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
-
-        r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
-        if (r < 0)
-                return r;
-
-        r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
-        if (r < 0)
-                return r;
-
-        n = bus_node_allocate(bus, path);
-        if (!n)
-                return -ENOMEM;
-
-        LIST_FOREACH(vtables, i, n->vtables) {
-                if (i->is_fallback != fallback) {
-                        r = -EPROTOTYPE;
-                        goto fail;
-                }
-
-                if (streq(i->interface, interface)) {
-
-                        if (i->vtable == vtable) {
-                                r = -EEXIST;
-                                goto fail;
-                        }
-
-                        existing = i;
-                }
-        }
-
-        c = new0(struct node_vtable, 1);
-        if (!c) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        c->node = n;
-        c->is_fallback = fallback;
-        c->vtable = vtable;
-        c->userdata = userdata;
-        c->find = find;
-
-        c->interface = strdup(interface);
-        if (!c->interface) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
-
-                switch (v->type) {
-
-                case _SD_BUS_VTABLE_METHOD: {
-                        struct vtable_member *m;
-
-                        if (!member_name_is_valid(v->x.method.member) ||
-                            !signature_is_valid(strempty(v->x.method.signature), false) ||
-                            !signature_is_valid(strempty(v->x.method.result), false) ||
-                            !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
-                            v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
-                                r = -EINVAL;
-                                goto fail;
-                        }
-
-                        m = new0(struct vtable_member, 1);
-                        if (!m) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        m->parent = c;
-                        m->path = n->path;
-                        m->interface = c->interface;
-                        m->member = v->x.method.member;
-                        m->vtable = v;
-
-                        r = hashmap_put(bus->vtable_methods, m, m);
-                        if (r < 0) {
-                                free(m);
-                                goto fail;
-                        }
-
-                        break;
-                }
-
-                case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
-
-                        if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
-                                r = -EINVAL;
-                                goto fail;
-                        }
-
-                        /* Fall through */
-
-                case _SD_BUS_VTABLE_PROPERTY: {
-                        struct vtable_member *m;
-
-                        if (!member_name_is_valid(v->x.property.member) ||
-                            !signature_is_single(v->x.property.signature, false) ||
-                            !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
-                            v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
-                            (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
-                            (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
-                                r = -EINVAL;
-                                goto fail;
-                        }
-
-                        m = new0(struct vtable_member, 1);
-                        if (!m) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        m->parent = c;
-                        m->path = n->path;
-                        m->interface = c->interface;
-                        m->member = v->x.property.member;
-                        m->vtable = v;
-
-                        r = hashmap_put(bus->vtable_properties, m, m);
-                        if (r < 0) {
-                                free(m);
-                                goto fail;
-                        }
-
-                        break;
-                }
-
-                case _SD_BUS_VTABLE_SIGNAL:
-
-                        if (!member_name_is_valid(v->x.signal.member) ||
-                            !signature_is_valid(strempty(v->x.signal.signature), false) ||
-                            v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
-                                r = -EINVAL;
-                                goto fail;
-                        }
-
-                        break;
-
-                default:
-                        r = -EINVAL;
-                        goto fail;
-                }
-        }
-
-        LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
-        bus->nodes_modified = true;
-
-        return 0;
-
-fail:
-        if (c)
-                free_node_vtable(bus, c);
-
-        bus_node_gc(bus, n);
-        return r;
-}
-
-static int remove_object_vtable_internal(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                bool fallback,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        struct node_vtable *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(vtables, c, n->vtables)
-                if (streq(c->interface, interface) &&
-                    c->is_fallback == fallback &&
-                    c->vtable == vtable &&
-                    c->find == find &&
-                    c->userdata == userdata)
-                        break;
-
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(vtables, n->vtables, c);
-
-        free_node_vtable(bus, c);
-        bus_node_gc(bus, n);
-
-        bus->nodes_modified = true;
-
-        return 1;
-}
-
-_public_ int sd_bus_add_object_vtable(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                void *userdata) {
-
-        return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
-}
-
-_public_ int sd_bus_remove_object_vtable(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                void *userdata) {
-
-        return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
-}
-
-_public_ int sd_bus_add_fallback_vtable(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
-}
-
-_public_ int sd_bus_remove_fallback_vtable(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
-}
-
-_public_ int sd_bus_add_node_enumerator(
-                sd_bus *bus,
-                const char *path,
-                sd_bus_node_enumerator_t callback,
-                void *userdata) {
-
-        struct node_enumerator *c;
-        struct node *n;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = bus_node_allocate(bus, path);
-        if (!n)
-                return -ENOMEM;
-
-        c = new0(struct node_enumerator, 1);
-        if (!c) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        c->node = n;
-        c->callback = callback;
-        c->userdata = userdata;
-
-        LIST_PREPEND(enumerators, n->enumerators, c);
-
-        bus->nodes_modified = true;
-
-        return 0;
-
-fail:
-        free(c);
-        bus_node_gc(bus, n);
-        return r;
-}
-
-_public_ int sd_bus_remove_node_enumerator(
-                sd_bus *bus,
-                const char *path,
-                sd_bus_node_enumerator_t callback,
-                void *userdata) {
-
-        struct node_enumerator *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(enumerators, c, n->enumerators)
-                if (c->callback == callback && c->userdata == userdata)
-                        break;
-
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(enumerators, n->enumerators, c);
-        free(c);
-
-        bus_node_gc(bus, n);
-
-        bus->nodes_modified = true;
-
-        return 1;
-}
-
-static int emit_properties_changed_on_interface(
-                sd_bus *bus,
-                const char *prefix,
-                const char *path,
-                const char *interface,
-                bool require_fallback,
-                bool *found_interface,
-                char **names) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        bool has_invalidating = false, has_changing = false;
-        struct vtable_member key = {};
-        struct node_vtable *c;
-        struct node *n;
-        char **property;
-        void *u = NULL;
-        int r;
-
-        assert(bus);
-        assert(prefix);
-        assert(path);
-        assert(interface);
-        assert(found_interface);
-
-        n = hashmap_get(bus->nodes, prefix);
-        if (!n)
-                return 0;
-
-        r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append(m, "s", interface);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_open_container(m, 'a', "{sv}");
-        if (r < 0)
-                return r;
-
-        key.path = prefix;
-        key.interface = interface;
-
-        LIST_FOREACH(vtables, c, n->vtables) {
-                if (require_fallback && !c->is_fallback)
-                        continue;
-
-                if (!streq(c->interface, interface))
-                        continue;
-
-                r = node_vtable_get_userdata(bus, path, c, &u, &error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-                if (r == 0)
-                        continue;
-
-                *found_interface = true;
-
-                if (names) {
-                        /* If the caller specified a list of
-                         * properties we include exactly those in the
-                         * PropertiesChanged message */
-
-                        STRV_FOREACH(property, names) {
-                                struct vtable_member *v;
-
-                                assert_return(member_name_is_valid(*property), -EINVAL);
-
-                                key.member = *property;
-                                v = hashmap_get(bus->vtable_properties, &key);
-                                if (!v)
-                                        return -ENOENT;
-
-                                /* If there are two vtables for the same
-                                 * interface, let's handle this property when
-                                 * we come to that vtable. */
-                                if (c != v->parent)
-                                        continue;
-
-                                assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
-                                              v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
-
-                                assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
-
-                                if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
-                                        has_invalidating = true;
-                                        continue;
-                                }
-
-                                has_changing = true;
-
-                                r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
-                                if (r < 0)
-                                        return r;
-                                if (bus->nodes_modified)
-                                        return 0;
-                        }
-                } else {
-                        const sd_bus_vtable *v;
-
-                        /* If the caller specified no properties list
-                         * we include all properties that are marked
-                         * as changing in the message. */
-
-                        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
-                                if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
-                                        continue;
-
-                                if (v->flags & SD_BUS_VTABLE_HIDDEN)
-                                        continue;
-
-                                if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
-                                        has_invalidating = true;
-                                        continue;
-                                }
-
-                                if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
-                                        continue;
-
-                                has_changing = true;
-
-                                r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
-                                if (r < 0)
-                                        return r;
-                                if (bus->nodes_modified)
-                                        return 0;
-                        }
-                }
-        }
-
-        if (!has_invalidating && !has_changing)
-                return 0;
-
-        r = sd_bus_message_close_container(m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_open_container(m, 'a', "s");
-        if (r < 0)
-                return r;
-
-        if (has_invalidating) {
-                LIST_FOREACH(vtables, c, n->vtables) {
-                        if (require_fallback && !c->is_fallback)
-                                continue;
-
-                        if (!streq(c->interface, interface))
-                                continue;
-
-                        r = node_vtable_get_userdata(bus, path, c, &u, &error);
-                        if (r < 0)
-                                return r;
-                        if (bus->nodes_modified)
-                                return 0;
-                        if (r == 0)
-                                continue;
-
-                        if (names) {
-                                STRV_FOREACH(property, names) {
-                                        struct vtable_member *v;
-
-                                        key.member = *property;
-                                        assert_se(v = hashmap_get(bus->vtable_properties, &key));
-                                        assert(c == v->parent);
-
-                                        if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
-                                                continue;
-
-                                        r = sd_bus_message_append(m, "s", *property);
-                                        if (r < 0)
-                                                return r;
-                                }
-                        } else {
-                                const sd_bus_vtable *v;
-
-                                for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
-                                        if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
-                                                continue;
-
-                                        if (v->flags & SD_BUS_VTABLE_HIDDEN)
-                                                continue;
-
-                                        if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
-                                                continue;
-
-                                        r = sd_bus_message_append(m, "s", v->x.property.member);
-                                        if (r < 0)
-                                                return r;
-                                }
-                        }
-                }
-        }
-
-        r = sd_bus_message_close_container(m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_send(bus, m, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-_public_ int sd_bus_emit_properties_changed_strv(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                char **names) {
-
-        BUS_DONT_DESTROY(bus);
-        bool found_interface = false;
-        char *prefix;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-
-        /* A non-NULL but empty names list means nothing needs to be
-           generated. A NULL list OTOH indicates that all properties
-           that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
-           included in the PropertiesChanged message. */
-        if (names && names[0] == NULL)
-                return 0;
-
-        do {
-                bus->nodes_modified = false;
-
-                r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
-                if (r != 0)
-                        return r;
-                if (bus->nodes_modified)
-                        continue;
-
-                prefix = alloca(strlen(path) + 1);
-                OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
-                        r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
-                        if (r != 0)
-                                return r;
-                        if (bus->nodes_modified)
-                                break;
-                }
-
-        } while (bus->nodes_modified);
-
-        return found_interface ? 0 : -ENOENT;
-}
-
-_public_ int sd_bus_emit_properties_changed(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *name, ...)  {
-
-        char **names;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (!name)
-                return 0;
-
-        names = strv_from_stdarg_alloca(name);
-
-        return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
-}
-
-static int interfaces_added_append_one_prefix(
-                sd_bus *bus,
-                sd_bus_message *m,
-                const char *prefix,
-                const char *path,
-                const char *interface,
-                bool require_fallback) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        bool found_interface = false;
-        struct node_vtable *c;
-        struct node *n;
-        void *u = NULL;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(prefix);
-        assert(path);
-        assert(interface);
-
-        n = hashmap_get(bus->nodes, prefix);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(vtables, c, n->vtables) {
-                if (require_fallback && !c->is_fallback)
-                        continue;
-
-                if (!streq(c->interface, interface))
-                        continue;
-
-                r = node_vtable_get_userdata(bus, path, c, &u, &error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-                if (r == 0)
-                        continue;
-
-                if (!found_interface) {
-                        r = sd_bus_message_append_basic(m, 's', interface);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_open_container(m, 'a', "{sv}");
-                        if (r < 0)
-                                return r;
-
-                        found_interface = true;
-                }
-
-                r = vtable_append_all_properties(bus, m, path, c, u, &error);
-                if (r < 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        if (found_interface) {
-                r = sd_bus_message_close_container(m);
-                if (r < 0)
-                        return r;
-        }
-
-        return found_interface;
-}
-
-static int interfaces_added_append_one(
-                sd_bus *bus,
-                sd_bus_message *m,
-                const char *path,
-                const char *interface) {
-
-        char *prefix;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(path);
-        assert(interface);
-
-        r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
-        if (r != 0)
-                return r;
-        if (bus->nodes_modified)
-                return 0;
-
-        prefix = alloca(strlen(path) + 1);
-        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
-                r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
-                if (r != 0)
-                        return r;
-                if (bus->nodes_modified)
-                        return 0;
-        }
-
-        return -ENOENT;
-}
-
-_public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
-        BUS_DONT_DESTROY(bus);
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        char **i;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (strv_isempty(interfaces))
-                return 0;
-
-        do {
-                bus->nodes_modified = false;
-
-                if (m)
-                        m = sd_bus_message_unref(m);
-
-                r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_append_basic(m, 'o', path);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
-                if (r < 0)
-                        return r;
-
-                STRV_FOREACH(i, interfaces) {
-                        assert_return(interface_name_is_valid(*i), -EINVAL);
-
-                        r = sd_bus_message_open_container(m, 'e', "sa{sv}");
-                        if (r < 0)
-                                return r;
-
-                        r = interfaces_added_append_one(bus, m, path, *i);
-                        if (r < 0)
-                                return r;
-
-                        if (bus->nodes_modified)
-                                break;
-
-                        r = sd_bus_message_close_container(m);
-                        if (r < 0)
-                                return r;
-                }
-
-                if (bus->nodes_modified)
-                        continue;
-
-                r = sd_bus_message_close_container(m);
-                if (r < 0)
-                        return r;
-
-        } while (bus->nodes_modified);
-
-        return sd_bus_send(bus, m, NULL);
-}
-
-_public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
-        char **interfaces;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        interfaces = strv_from_stdarg_alloca(interface);
-
-        return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
-}
-
-_public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (strv_isempty(interfaces))
-                return 0;
-
-        r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append_basic(m, 'o', path);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_append_strv(m, interfaces);
-        if (r < 0)
-                return r;
-
-        return sd_bus_send(bus, m, NULL);
-}
-
-_public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
-        char **interfaces;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        interfaces = strv_from_stdarg_alloca(interface);
-
-        return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
-}
-
-_public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = bus_node_allocate(bus, path);
-        if (!n)
-                return -ENOMEM;
-
-        n->object_manager = true;
-        bus->nodes_modified = true;
-        return 0;
-}
-
-_public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        if (!n->object_manager)
-                return 0;
-
-        n->object_manager = false;
-        bus->nodes_modified = true;
-        bus_node_gc(bus, n);
-
-        return 1;
-}
diff --git a/src/libsystemd/bus-objects.h b/src/libsystemd/bus-objects.h
deleted file mode 100644
index 420edd9..0000000
--- a/src/libsystemd/bus-objects.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- 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 "bus-internal.h"
-
-int bus_process_object(sd_bus *bus, sd_bus_message *m);
diff --git a/src/libsystemd/bus-protocol.h b/src/libsystemd/bus-protocol.h
deleted file mode 100644
index 5046d17..0000000
--- a/src/libsystemd/bus-protocol.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*-*- 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/>.
-***/
-
-
-/* Endianness */
-
-enum {
-        _BUS_INVALID_ENDIAN = 0,
-        BUS_LITTLE_ENDIAN   = 'l',
-        BUS_BIG_ENDIAN      = 'B',
-#if __BYTE_ORDER == __BIG_ENDIAN
-        BUS_NATIVE_ENDIAN   = BUS_BIG_ENDIAN,
-        BUS_REVERSE_ENDIAN  = BUS_LITTLE_ENDIAN
-#else
-        BUS_NATIVE_ENDIAN   = BUS_LITTLE_ENDIAN,
-        BUS_REVERSE_ENDIAN  = BUS_BIG_ENDIAN
-#endif
-};
-
-/* Flags */
-
-enum {
-        BUS_MESSAGE_NO_REPLY_EXPECTED = 1,
-        BUS_MESSAGE_NO_AUTO_START = 2
-};
-
-/* Header fields */
-
-enum {
-        _BUS_MESSAGE_HEADER_INVALID = 0,
-        BUS_MESSAGE_HEADER_PATH,
-        BUS_MESSAGE_HEADER_INTERFACE,
-        BUS_MESSAGE_HEADER_MEMBER,
-        BUS_MESSAGE_HEADER_ERROR_NAME,
-        BUS_MESSAGE_HEADER_REPLY_SERIAL,
-        BUS_MESSAGE_HEADER_DESTINATION,
-        BUS_MESSAGE_HEADER_SENDER,
-        BUS_MESSAGE_HEADER_SIGNATURE,
-        BUS_MESSAGE_HEADER_UNIX_FDS,
-        _BUS_MESSAGE_HEADER_MAX
-};
-
-/* RequestName parameters */
-
-enum  {
-        BUS_NAME_ALLOW_REPLACEMENT = 1,
-        BUS_NAME_REPLACE_EXISTING = 2,
-        BUS_NAME_DO_NOT_QUEUE = 4
-};
-
-/* RequestName returns */
-enum  {
-        BUS_NAME_PRIMARY_OWNER = 1,
-        BUS_NAME_IN_QUEUE = 2,
-        BUS_NAME_EXISTS = 3,
-        BUS_NAME_ALREADY_OWNER = 4
-};
-
-/* ReleaseName returns */
-enum {
-        BUS_NAME_RELEASED = 1,
-        BUS_NAME_NON_EXISTENT = 2,
-        BUS_NAME_NOT_OWNER = 3,
-};
-
-/* StartServiceByName returns */
-enum {
-        BUS_START_REPLY_SUCCESS = 1,
-        BUS_START_REPLY_ALREADY_RUNNING = 2,
-};
-
-#define 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"
-
-#define BUS_INTROSPECT_INTERFACE_PEER                                \
-        " <interface name=\"org.freedesktop.DBus.Peer\">\n"             \
-        "  <method name=\"Ping\"/>\n"                                   \
-        "  <method name=\"GetMachineId\">\n"                            \
-        "   <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE                      \
-        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"   \
-        "  <method name=\"Introspect\">\n"                              \
-        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_PROPERTIES                          \
-        " <interface name=\"org.freedesktop.DBus.Properties\">\n"       \
-        "  <method name=\"Get\">\n"                                     \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
-        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetAll\">\n"                                  \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"Set\">\n"                                     \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
-        "   <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <signal name=\"PropertiesChanged\">\n"                       \
-        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
-        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
-        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
-        "  </signal>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER                      \
-        " <interface name=\"org.freedesktop.DBus.ObjectManager\">\n"    \
-        "  <method name=\"GetManagedObjects\">\n"                       \
-        "   <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <signal name=\"InterfacesAdded\">\n"                         \
-        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
-        "   <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"InterfacesRemoved\">\n"                       \
-        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
-        "   <arg type=\"as\" name=\"interfaces\"/>\n"                   \
-        "  </signal>\n"                                                 \
-        " </interface>\n"
diff --git a/src/libsystemd/bus-signature.c b/src/libsystemd/bus-signature.c
deleted file mode 100644
index 1e5bf48..0000000
--- a/src/libsystemd/bus-signature.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*-*- 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 <util.h>
-
-#include "bus-signature.h"
-#include "bus-type.h"
-
-static int signature_element_length_internal(
-                const char *s,
-                bool allow_dict_entry,
-                unsigned array_depth,
-                unsigned struct_depth,
-                size_t *l) {
-
-        int r;
-
-        if (!s)
-                return -EINVAL;
-
-        assert(l);
-
-        if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
-                *l = 1;
-                return 0;
-        }
-
-        if (*s == SD_BUS_TYPE_ARRAY) {
-                size_t t;
-
-                if (array_depth >= 32)
-                        return -EINVAL;
-
-                r = signature_element_length_internal(s + 1, true, array_depth+1, struct_depth, &t);
-                if (r < 0)
-                        return r;
-
-                *l = t + 1;
-                return 0;
-        }
-
-        if (*s == SD_BUS_TYPE_STRUCT_BEGIN) {
-                const char *p = s + 1;
-
-                if (struct_depth >= 32)
-                        return -EINVAL;
-
-                while (*p != SD_BUS_TYPE_STRUCT_END) {
-                        size_t t;
-
-                        r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
-                        if (r < 0)
-                                return r;
-
-                        p += t;
-                }
-
-                *l = p - s + 1;
-                return 0;
-        }
-
-        if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) {
-                const char *p = s + 1;
-                unsigned n = 0;
-
-                if (struct_depth >= 32)
-                        return -EINVAL;
-
-                while (*p != SD_BUS_TYPE_DICT_ENTRY_END) {
-                        size_t t;
-
-                        if (n == 0 && !bus_type_is_basic(*p))
-                                return -EINVAL;
-
-                        r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
-                        if (r < 0)
-                                return r;
-
-                        p += t;
-                        n++;
-                }
-
-                if (n != 2)
-                        return -EINVAL;
-
-                *l = p - s + 1;
-                return 0;
-        }
-
-        return -EINVAL;
-}
-
-
-int signature_element_length(const char *s, size_t *l) {
-        return signature_element_length_internal(s, true, 0, 0, l);
-}
-
-bool signature_is_single(const char *s, bool allow_dict_entry) {
-        int r;
-        size_t t;
-
-        if (!s)
-                return false;
-
-        r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t);
-        if (r < 0)
-                return false;
-
-        return s[t] == 0;
-}
-
-bool signature_is_pair(const char *s) {
-
-        if (!s)
-                return false;
-
-        if (!bus_type_is_basic(*s))
-                return false;
-
-        return signature_is_single(s + 1, false);
-}
-
-bool signature_is_valid(const char *s, bool allow_dict_entry) {
-        const char *p;
-        int r;
-
-        if (!s)
-                return false;
-
-        p = s;
-        while (*p) {
-                size_t t;
-
-                r = signature_element_length_internal(p, allow_dict_entry, 0, 0, &t);
-                if (r < 0)
-                        return false;
-
-                p += t;
-        }
-
-        return p - s <= 255;
-}
diff --git a/src/libsystemd/bus-signature.h b/src/libsystemd/bus-signature.h
deleted file mode 100644
index 2e06e30..0000000
--- a/src/libsystemd/bus-signature.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- 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 <stdbool.h>
-#include <sys/types.h>
-
-bool signature_is_single(const char *s, bool allow_dict_entry);
-bool signature_is_pair(const char *s);
-bool signature_is_valid(const char *s, bool allow_dict_entry);
-
-int signature_element_length(const char *s, size_t *l);
diff --git a/src/libsystemd/bus-socket.c b/src/libsystemd/bus-socket.c
deleted file mode 100644
index 0c4b6af..0000000
--- a/src/libsystemd/bus-socket.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*-*- 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 <endian.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/poll.h>
-#include <byteswap.h>
-
-#include "util.h"
-#include "macro.h"
-#include "missing.h"
-#include "strv.h"
-#include "utf8.h"
-#include "sd-daemon.h"
-
-#include "sd-bus.h"
-#include "bus-socket.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-
-#define SNDBUF_SIZE (8*1024*1024)
-
-static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) {
-
-        while (size > 0) {
-                struct iovec *i = iov + *idx;
-
-                if (i->iov_len > size) {
-                        i->iov_base = (uint8_t*) i->iov_base + size;
-                        i->iov_len -= size;
-                        return;
-                }
-
-                size -= i->iov_len;
-
-                i->iov_base = NULL;
-                i->iov_len = 0;
-
-                (*idx) ++;
-        }
-}
-
-static int append_iovec(sd_bus_message *m, const void *p, size_t sz) {
-        assert(m);
-        assert(p);
-        assert(sz > 0);
-
-        m->iovec[m->n_iovec].iov_base = (void*) p;
-        m->iovec[m->n_iovec].iov_len = sz;
-        m->n_iovec++;
-
-        return 0;
-}
-
-static int bus_message_setup_iovec(sd_bus_message *m) {
-        struct bus_body_part *part;
-        unsigned n, i;
-        int r;
-
-        assert(m);
-        assert(m->sealed);
-
-        if (m->n_iovec > 0)
-                return 0;
-
-        assert(!m->iovec);
-
-        n = 1 + m->n_body_parts;
-        if (n < ELEMENTSOF(m->iovec_fixed))
-                m->iovec = m->iovec_fixed;
-        else {
-                m->iovec = new(struct iovec, n);
-                if (!m->iovec) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        r = append_iovec(m, m->header, BUS_MESSAGE_BODY_BEGIN(m));
-        if (r < 0)
-                goto fail;
-
-        MESSAGE_FOREACH_PART(part, i, m)  {
-                r = bus_body_part_map(part);
-                if (r < 0)
-                        goto fail;
-
-                r = append_iovec(m, part->data, part->size);
-                if (r < 0)
-                        goto fail;
-        }
-
-        assert(n == m->n_iovec);
-
-        return 0;
-
-fail:
-        m->poisoned = true;
-        return r;
-}
-
-bool bus_socket_auth_needs_write(sd_bus *b) {
-
-        unsigned i;
-
-        if (b->auth_index >= ELEMENTSOF(b->auth_iovec))
-                return false;
-
-        for (i = b->auth_index; i < ELEMENTSOF(b->auth_iovec); i++) {
-                struct iovec *j = b->auth_iovec + i;
-
-                if (j->iov_len > 0)
-                        return true;
-        }
-
-        return false;
-}
-
-static int bus_socket_write_auth(sd_bus *b) {
-        ssize_t k;
-
-        assert(b);
-        assert(b->state == BUS_AUTHENTICATING);
-
-        if (!bus_socket_auth_needs_write(b))
-                return 0;
-
-        if (b->prefer_writev)
-                k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
-        else {
-                struct msghdr mh;
-                zero(mh);
-
-                mh.msg_iov = b->auth_iovec + b->auth_index;
-                mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index;
-
-                k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
-                if (k < 0 && errno == ENOTSOCK) {
-                        b->prefer_writev = true;
-                        k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
-                }
-        }
-
-        if (k < 0)
-                return errno == EAGAIN ? 0 : -errno;
-
-        iovec_advance(b->auth_iovec, &b->auth_index, (size_t) k);
-        return 1;
-}
-
-static int bus_socket_auth_verify_client(sd_bus *b) {
-        char *e, *f, *start;
-        sd_id128_t peer;
-        unsigned i;
-        int r;
-
-        assert(b);
-
-        /* We expect two response lines: "OK" and possibly
-         * "AGREE_UNIX_FD" */
-
-        e = memmem(b->rbuffer, b->rbuffer_size, "\r\n", 2);
-        if (!e)
-                return 0;
-
-        if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) {
-                f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2);
-                if (!f)
-                        return 0;
-
-                start = f + 2;
-        } else {
-                f = NULL;
-                start = e + 2;
-        }
-
-        /* Nice! We got all the lines we need. First check the OK
-         * line */
-
-        if (e - (char*) b->rbuffer != 3 + 32)
-                return -EPERM;
-
-        if (memcmp(b->rbuffer, "OK ", 3))
-                return -EPERM;
-
-        b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL;
-
-        for (i = 0; i < 32; i += 2) {
-                int x, y;
-
-                x = unhexchar(((char*) b->rbuffer)[3 + i]);
-                y = unhexchar(((char*) b->rbuffer)[3 + i + 1]);
-
-                if (x < 0 || y < 0)
-                        return -EINVAL;
-
-                peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y);
-        }
-
-        if (!sd_id128_equal(b->server_id, SD_ID128_NULL) &&
-            !sd_id128_equal(b->server_id, peer))
-                return -EPERM;
-
-        b->server_id = peer;
-
-        /* And possibly check the second line, too */
-
-        if (f)
-                b->can_fds =
-                        (f - e == sizeof("\r\nAGREE_UNIX_FD") - 1) &&
-                        memcmp(e + 2, "AGREE_UNIX_FD", sizeof("AGREE_UNIX_FD") - 1) == 0;
-
-        b->rbuffer_size -= (start - (char*) b->rbuffer);
-        memmove(b->rbuffer, start, b->rbuffer_size);
-
-        r = bus_start_running(b);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static bool line_equals(const char *s, size_t m, const char *line) {
-        size_t l;
-
-        l = strlen(line);
-        if (l != m)
-                return false;
-
-        return memcmp(s, line, l) == 0;
-}
-
-static bool line_begins(const char *s, size_t m, const char *word) {
-        size_t l;
-
-        l = strlen(word);
-        if (m < l)
-                return false;
-
-        if (memcmp(s, word, l) != 0)
-                return false;
-
-        return m == l || (m > l && s[l] == ' ');
-}
-
-static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
-        _cleanup_free_ char *token = NULL;
-
-        if (!b->anonymous_auth)
-                return 0;
-
-        if (l <= 0)
-                return 1;
-
-        assert(p[0] == ' ');
-        p++; l--;
-
-        if (l % 2 != 0)
-                return 0;
-        token = unhexmem(p, l);
-        if (!token)
-                return -ENOMEM;
-
-        if (memchr(token, 0, l/2))
-                return 0;
-
-        return !!utf8_is_valid(token);
-}
-
-static int verify_external_token(sd_bus *b, const char *p, size_t l) {
-        _cleanup_free_ char *token = NULL;
-        uid_t u;
-        int r;
-
-        /* We don't do any real authentication here. Instead, we if
-         * the owner of this bus wanted authentication he should have
-         * checked SO_PEERCRED before even creating the bus object. */
-
-        if (!b->anonymous_auth && !b->ucred_valid)
-                return 0;
-
-        if (l <= 0)
-                return 1;
-
-        assert(p[0] == ' ');
-        p++; l--;
-
-        if (l % 2 != 0)
-                return 0;
-
-        token = unhexmem(p, l);
-        if (!token)
-                return -ENOMEM;
-
-        if (memchr(token, 0, l/2))
-                return 0;
-
-        r = parse_uid(token, &u);
-        if (r < 0)
-                return 0;
-
-        /* We ignore the passed value if anonymous authentication is
-         * on anyway. */
-        if (!b->anonymous_auth && u != b->ucred.uid)
-                return 0;
-
-        return 1;
-}
-
-static int bus_socket_auth_write(sd_bus *b, const char *t) {
-        char *p;
-        size_t l;
-
-        assert(b);
-        assert(t);
-
-        /* We only make use of the first iovec */
-        assert(b->auth_index == 0 || b->auth_index == 1);
-
-        l = strlen(t);
-        p = malloc(b->auth_iovec[0].iov_len + l);
-        if (!p)
-                return -ENOMEM;
-
-        memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len);
-        memcpy(p + b->auth_iovec[0].iov_len, t, l);
-
-        b->auth_iovec[0].iov_base = p;
-        b->auth_iovec[0].iov_len += l;
-
-        free(b->auth_buffer);
-        b->auth_buffer = p;
-        b->auth_index = 0;
-        return 0;
-}
-
-static int bus_socket_auth_write_ok(sd_bus *b) {
-        char t[3 + 32 + 2 + 1];
-
-        assert(b);
-
-        snprintf(t, sizeof(t), "OK " SD_ID128_FORMAT_STR "\r\n", SD_ID128_FORMAT_VAL(b->server_id));
-        char_array_0(t);
-
-        return bus_socket_auth_write(b, t);
-}
-
-static int bus_socket_auth_verify_server(sd_bus *b) {
-        char *e;
-        const char *line;
-        size_t l;
-        bool processed = false;
-        int r;
-
-        assert(b);
-
-        if (b->rbuffer_size < 1)
-                return 0;
-
-        /* First char must be a NUL byte */
-        if (*(char*) b->rbuffer != 0)
-                return -EIO;
-
-        if (b->rbuffer_size < 3)
-                return 0;
-
-        /* Begin with the first line */
-        if (b->auth_rbegin <= 0)
-                b->auth_rbegin = 1;
-
-        for (;;) {
-                /* Check if line is complete */
-                line = (char*) b->rbuffer + b->auth_rbegin;
-                e = memmem(line, b->rbuffer_size - b->auth_rbegin, "\r\n", 2);
-                if (!e)
-                        return processed;
-
-                l = e - line;
-
-                if (line_begins(line, l, "AUTH ANONYMOUS")) {
-
-                        r = verify_anonymous_token(b, line + 14, l - 14);
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                r = bus_socket_auth_write(b, "REJECTED\r\n");
-                        else {
-                                b->auth = BUS_AUTH_ANONYMOUS;
-                                r = bus_socket_auth_write_ok(b);
-                        }
-
-                } else if (line_begins(line, l, "AUTH EXTERNAL")) {
-
-                        r = verify_external_token(b, line + 13, l - 13);
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                r = bus_socket_auth_write(b, "REJECTED\r\n");
-                        else {
-                                b->auth = BUS_AUTH_EXTERNAL;
-                                r = bus_socket_auth_write_ok(b);
-                        }
-
-                } else if (line_begins(line, l, "AUTH"))
-                        r = bus_socket_auth_write(b, "REJECTED EXTERNAL ANONYMOUS\r\n");
-                else if (line_equals(line, l, "CANCEL") ||
-                         line_begins(line, l, "ERROR")) {
-
-                        b->auth = _BUS_AUTH_INVALID;
-                        r = bus_socket_auth_write(b, "REJECTED\r\n");
-
-                } else if (line_equals(line, l, "BEGIN")) {
-
-                        if (b->auth == _BUS_AUTH_INVALID)
-                                r = bus_socket_auth_write(b, "ERROR\r\n");
-                        else {
-                                /* We can't leave from the auth phase
-                                 * before we haven't written
-                                 * everything queued, so let's check
-                                 * that */
-
-                                if (bus_socket_auth_needs_write(b))
-                                        return 1;
-
-                                b->rbuffer_size -= (e + 2 - (char*) b->rbuffer);
-                                memmove(b->rbuffer, e + 2, b->rbuffer_size);
-                                return bus_start_running(b);
-                        }
-
-                } else if (line_begins(line, l, "DATA")) {
-
-                        if (b->auth == _BUS_AUTH_INVALID)
-                                r = bus_socket_auth_write(b, "ERROR\r\n");
-                        else {
-                                if (b->auth == BUS_AUTH_ANONYMOUS)
-                                        r = verify_anonymous_token(b, line + 4, l - 4);
-                                else
-                                        r = verify_external_token(b, line + 4, l - 4);
-
-                                if (r < 0)
-                                        return r;
-                                if (r == 0) {
-                                        b->auth = _BUS_AUTH_INVALID;
-                                        r = bus_socket_auth_write(b, "REJECTED\r\n");
-                                } else
-                                        r = bus_socket_auth_write_ok(b);
-                        }
-                } else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) {
-                        if (b->auth == _BUS_AUTH_INVALID || !(b->hello_flags & KDBUS_HELLO_ACCEPT_FD))
-                                r = bus_socket_auth_write(b, "ERROR\r\n");
-                        else {
-                                b->can_fds = true;
-                                r = bus_socket_auth_write(b, "AGREE_UNIX_FD\r\n");
-                        }
-                } else
-                        r = bus_socket_auth_write(b, "ERROR\r\n");
-
-                if (r < 0)
-                        return r;
-
-                b->auth_rbegin = e + 2 - (char*) b->rbuffer;
-
-                processed = true;
-        }
-}
-
-static int bus_socket_auth_verify(sd_bus *b) {
-        assert(b);
-
-        if (b->is_server)
-                return bus_socket_auth_verify_server(b);
-        else
-                return bus_socket_auth_verify_client(b);
-}
-
-static int bus_socket_read_auth(sd_bus *b) {
-        struct msghdr mh;
-        struct iovec iov;
-        size_t n;
-        ssize_t k;
-        int r;
-        void *p;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) +
-                            CMSG_SPACE(sizeof(struct ucred)) +
-                            CMSG_SPACE(NAME_MAX)]; /*selinux label */
-        } control;
-        struct cmsghdr *cmsg;
-        bool handle_cmsg = false;
-
-        assert(b);
-        assert(b->state == BUS_AUTHENTICATING);
-
-        r = bus_socket_auth_verify(b);
-        if (r != 0)
-                return r;
-
-        n = MAX(256u, b->rbuffer_size * 2);
-
-        if (n > BUS_AUTH_SIZE_MAX)
-                n = BUS_AUTH_SIZE_MAX;
-
-        if (b->rbuffer_size >= n)
-                return -ENOBUFS;
-
-        p = realloc(b->rbuffer, n);
-        if (!p)
-                return -ENOMEM;
-
-        b->rbuffer = p;
-
-        zero(iov);
-        iov.iov_base = (uint8_t*) b->rbuffer + b->rbuffer_size;
-        iov.iov_len = n - b->rbuffer_size;
-
-        if (b->prefer_readv)
-                k = readv(b->input_fd, &iov, 1);
-        else {
-                zero(mh);
-                mh.msg_iov = &iov;
-                mh.msg_iovlen = 1;
-                mh.msg_control = &control;
-                mh.msg_controllen = sizeof(control);
-
-                k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
-                if (k < 0 && errno == ENOTSOCK) {
-                        b->prefer_readv = true;
-                        k = readv(b->input_fd, &iov, 1);
-                } else
-                        handle_cmsg = true;
-        }
-        if (k < 0)
-                return errno == EAGAIN ? 0 : -errno;
-        if (k == 0)
-                return -ECONNRESET;
-
-        b->rbuffer_size += k;
-
-        if (handle_cmsg) {
-                for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
-                        if (cmsg->cmsg_level == SOL_SOCKET &&
-                            cmsg->cmsg_type == SCM_RIGHTS) {
-                                int j;
-
-                                /* Whut? We received fds during the auth
-                                 * protocol? Somebody is playing games with
-                                 * us. Close them all, and fail */
-                                j = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-                                close_many((int*) CMSG_DATA(cmsg), j);
-                                return -EIO;
-
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SCM_CREDENTIALS &&
-                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-
-                                /* Ignore bogus data, which we might
-                                 * get on socketpair() sockets */
-                                if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) {
-                                        memcpy(&b->ucred, CMSG_DATA(cmsg), sizeof(struct ucred));
-                                        b->ucred_valid = true;
-                                }
-
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SCM_SECURITY) {
-
-                                size_t l;
-
-                                l = cmsg->cmsg_len - CMSG_LEN(0);
-                                if (l > 0) {
-                                        memcpy(&b->label, CMSG_DATA(cmsg), l);
-                                        b->label[l] = 0;
-                                }
-                        }
-                }
-        }
-
-        r = bus_socket_auth_verify(b);
-        if (r != 0)
-                return r;
-
-        return 1;
-}
-
-void bus_socket_setup(sd_bus *b) {
-        int enable;
-
-        assert(b);
-
-        /* Enable SO_PASSCRED + SO_PASSEC. We try this on any
-         * socket, just in case. */
-        enable = !b->bus_client;
-        setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
-
-        enable = !b->bus_client && (b->attach_flags & KDBUS_ATTACH_SECLABEL);
-        setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable));
-
-        /* Increase the buffers to 8 MB */
-        fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
-        fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
-
-        b->is_kernel = false;
-        b->message_version = 1;
-        b->message_endian = 0;
-}
-
-static void bus_get_peercred(sd_bus *b) {
-        assert(b);
-
-        /* Get the peer for socketpair() sockets */
-        b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;
-}
-
-static int bus_socket_start_auth_client(sd_bus *b) {
-        size_t l;
-        const char *auth_suffix, *auth_prefix;
-
-        assert(b);
-
-        if (b->anonymous_auth) {
-                auth_prefix = "\0AUTH ANONYMOUS ";
-
-                /* For ANONYMOUS auth we send some arbitrary "trace" string */
-                l = 9;
-                b->auth_buffer = hexmem("anonymous", l);
-        } else {
-                char text[20 + 1]; /* enough space for a 64bit integer plus NUL */
-
-                auth_prefix = "\0AUTH EXTERNAL ";
-
-                snprintf(text, sizeof(text), "%lu", (unsigned long) geteuid());
-                char_array_0(text);
-
-                l = strlen(text);
-                b->auth_buffer = hexmem(text, l);
-        }
-
-        if (!b->auth_buffer)
-                return -ENOMEM;
-
-        if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD)
-                auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
-        else
-                auth_suffix = "\r\nBEGIN\r\n";
-
-        b->auth_iovec[0].iov_base = (void*) auth_prefix;
-        b->auth_iovec[0].iov_len = 1 + strlen(auth_prefix + 1);
-        b->auth_iovec[1].iov_base = (void*) b->auth_buffer;
-        b->auth_iovec[1].iov_len = l * 2;
-        b->auth_iovec[2].iov_base = (void*) auth_suffix;
-        b->auth_iovec[2].iov_len = strlen(auth_suffix);
-
-        return bus_socket_write_auth(b);
-}
-
-int bus_socket_start_auth(sd_bus *b) {
-        assert(b);
-
-        bus_get_peercred(b);
-
-        b->state = BUS_AUTHENTICATING;
-        b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT;
-
-        if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0)
-                b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
-
-        if (b->output_fd != b->input_fd)
-                if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0)
-                        b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
-
-        if (b->is_server)
-                return bus_socket_read_auth(b);
-        else
-                return bus_socket_start_auth_client(b);
-}
-
-int bus_socket_connect(sd_bus *b) {
-        int r;
-
-        assert(b);
-        assert(b->input_fd < 0);
-        assert(b->output_fd < 0);
-        assert(b->sockaddr.sa.sa_family != AF_UNSPEC);
-
-        b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (b->input_fd < 0)
-                return -errno;
-
-        b->output_fd = b->input_fd;
-
-        bus_socket_setup(b);
-
-        r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
-        if (r < 0) {
-                if (errno == EINPROGRESS)
-                        return 1;
-
-                return -errno;
-        }
-
-        return bus_socket_start_auth(b);
-}
-
-int bus_socket_exec(sd_bus *b) {
-        int s[2], r;
-        pid_t pid;
-
-        assert(b);
-        assert(b->input_fd < 0);
-        assert(b->output_fd < 0);
-        assert(b->exec_path);
-
-        r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s);
-        if (r < 0)
-                return -errno;
-
-        pid = fork();
-        if (pid < 0) {
-                close_pipe(s);
-                return -errno;
-        }
-        if (pid == 0) {
-                /* Child */
-
-                reset_all_signal_handlers();
-
-                close_all_fds(s+1, 1);
-
-                assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
-                assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
-
-                if (s[1] != STDIN_FILENO && s[1] != STDOUT_FILENO)
-                        close_nointr_nofail(s[1]);
-
-                fd_cloexec(STDIN_FILENO, false);
-                fd_cloexec(STDOUT_FILENO, false);
-                fd_nonblock(STDIN_FILENO, false);
-                fd_nonblock(STDOUT_FILENO, false);
-
-                if (b->exec_argv)
-                        execvp(b->exec_path, b->exec_argv);
-                else {
-                        const char *argv[] = { b->exec_path, NULL };
-                        execvp(b->exec_path, (char**) argv);
-                }
-
-                _exit(EXIT_FAILURE);
-        }
-
-        close_nointr_nofail(s[1]);
-        b->output_fd = b->input_fd = s[0];
-
-        bus_socket_setup(b);
-
-        return bus_socket_start_auth(b);
-}
-
-int bus_socket_take_fd(sd_bus *b) {
-        assert(b);
-
-        bus_socket_setup(b);
-
-        return bus_socket_start_auth(b);
-}
-
-int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
-        struct iovec *iov;
-        ssize_t k;
-        size_t n;
-        unsigned j;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(idx);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        if (*idx >= BUS_MESSAGE_SIZE(m))
-                return 0;
-
-        r = bus_message_setup_iovec(m);
-        if (r < 0)
-                return r;
-
-        n = m->n_iovec * sizeof(struct iovec);
-        iov = alloca(n);
-        memcpy(iov, m->iovec, n);
-
-        j = 0;
-        iovec_advance(iov, &j, *idx);
-
-        if (bus->prefer_writev)
-                k = writev(bus->output_fd, iov, m->n_iovec);
-        else {
-                struct msghdr mh;
-                zero(mh);
-
-                if (m->n_fds > 0) {
-                        struct cmsghdr *control;
-                        control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
-
-                        mh.msg_control = control;
-                        control->cmsg_level = SOL_SOCKET;
-                        control->cmsg_type = SCM_RIGHTS;
-                        mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
-                        memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds);
-                }
-
-                mh.msg_iov = iov;
-                mh.msg_iovlen = m->n_iovec;
-
-                k = sendmsg(bus->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
-                if (k < 0 && errno == ENOTSOCK) {
-                        bus->prefer_writev = true;
-                        k = writev(bus->output_fd, iov, m->n_iovec);
-                }
-        }
-
-        if (k < 0)
-                return errno == EAGAIN ? 0 : -errno;
-
-        *idx += (size_t) k;
-        return 1;
-}
-
-static int bus_socket_read_message_need(sd_bus *bus, size_t *need) {
-        uint32_t a, b;
-        uint8_t e;
-        uint64_t sum;
-
-        assert(bus);
-        assert(need);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        if (bus->rbuffer_size < sizeof(struct bus_header)) {
-                *need = sizeof(struct bus_header) + 8;
-
-                /* Minimum message size:
-                 *
-                 * Header +
-                 *
-                 *  Method Call: +2 string headers
-                 *       Signal: +3 string headers
-                 * Method Error: +1 string headers
-                 *               +1 uint32 headers
-                 * Method Reply: +1 uint32 headers
-                 *
-                 * A string header is at least 9 bytes
-                 * A uint32 header is at least 8 bytes
-                 *
-                 * Hence the minimum message size of a valid message
-                 * is header + 8 bytes */
-
-                return 0;
-        }
-
-        a = ((const uint32_t*) bus->rbuffer)[1];
-        b = ((const uint32_t*) bus->rbuffer)[3];
-
-        e = ((const uint8_t*) bus->rbuffer)[0];
-        if (e == BUS_LITTLE_ENDIAN) {
-                a = le32toh(a);
-                b = le32toh(b);
-        } else if (e == BUS_BIG_ENDIAN) {
-                a = be32toh(a);
-                b = be32toh(b);
-        } else
-                return -EBADMSG;
-
-        sum = (uint64_t) sizeof(struct bus_header) + (uint64_t) ALIGN_TO(b, 8) + (uint64_t) a;
-        if (sum >= BUS_MESSAGE_SIZE_MAX)
-                return -ENOBUFS;
-
-        *need = (size_t) sum;
-        return 0;
-}
-
-static int bus_socket_make_message(sd_bus *bus, size_t size) {
-        sd_bus_message *t;
-        void *b;
-        int r;
-
-        assert(bus);
-        assert(bus->rbuffer_size >= size);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        r = bus_rqueue_make_room(bus);
-        if (r < 0)
-                return r;
-
-        if (bus->rbuffer_size > size) {
-                b = memdup((const uint8_t*) bus->rbuffer + size,
-                           bus->rbuffer_size - size);
-                if (!b)
-                        return -ENOMEM;
-        } else
-                b = NULL;
-
-        r = bus_message_from_malloc(bus,
-                                    bus->rbuffer, size,
-                                    bus->fds, bus->n_fds,
-                                    !bus->bus_client && bus->ucred_valid ? &bus->ucred : NULL,
-                                    !bus->bus_client && bus->label[0] ? bus->label : NULL,
-                                    &t);
-        if (r < 0) {
-                free(b);
-                return r;
-        }
-
-        bus->rbuffer = b;
-        bus->rbuffer_size -= size;
-
-        bus->fds = NULL;
-        bus->n_fds = 0;
-
-        bus->rqueue[bus->rqueue_size++] = t;
-
-        return 1;
-}
-
-int bus_socket_read_message(sd_bus *bus) {
-        struct msghdr mh;
-        struct iovec iov;
-        ssize_t k;
-        size_t need;
-        int r;
-        void *b;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) +
-                            CMSG_SPACE(sizeof(struct ucred)) +
-                            CMSG_SPACE(NAME_MAX)]; /*selinux label */
-        } control;
-        struct cmsghdr *cmsg;
-        bool handle_cmsg = false;
-
-        assert(bus);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        r = bus_socket_read_message_need(bus, &need);
-        if (r < 0)
-                return r;
-
-        if (bus->rbuffer_size >= need)
-                return bus_socket_make_message(bus, need);
-
-        b = realloc(bus->rbuffer, need);
-        if (!b)
-                return -ENOMEM;
-
-        bus->rbuffer = b;
-
-        zero(iov);
-        iov.iov_base = (uint8_t*) bus->rbuffer + bus->rbuffer_size;
-        iov.iov_len = need - bus->rbuffer_size;
-
-        if (bus->prefer_readv)
-                k = readv(bus->input_fd, &iov, 1);
-        else {
-                zero(mh);
-                mh.msg_iov = &iov;
-                mh.msg_iovlen = 1;
-                mh.msg_control = &control;
-                mh.msg_controllen = sizeof(control);
-
-                k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
-                if (k < 0 && errno == ENOTSOCK) {
-                        bus->prefer_readv = true;
-                        k = readv(bus->input_fd, &iov, 1);
-                } else
-                        handle_cmsg = true;
-        }
-        if (k < 0)
-                return errno == EAGAIN ? 0 : -errno;
-        if (k == 0)
-                return -ECONNRESET;
-
-        bus->rbuffer_size += k;
-
-        if (handle_cmsg) {
-                for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
-                        if (cmsg->cmsg_level == SOL_SOCKET &&
-                            cmsg->cmsg_type == SCM_RIGHTS) {
-                                int n, *f;
-
-                                n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
-                                if (!bus->can_fds) {
-                                        /* Whut? We received fds but this
-                                         * isn't actually enabled? Close them,
-                                         * and fail */
-
-                                        close_many((int*) CMSG_DATA(cmsg), n);
-                                        return -EIO;
-                                }
-
-                                f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n));
-                                if (!f) {
-                                        close_many((int*) CMSG_DATA(cmsg), n);
-                                        return -ENOMEM;
-                                }
-
-                                memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int));
-                                bus->fds = f;
-                                bus->n_fds += n;
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SCM_CREDENTIALS &&
-                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-
-                                /* Ignore bogus data, which we might
-                                 * get on socketpair() sockets */
-                                if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) {
-                                        memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred));
-                                        bus->ucred_valid = true;
-                                }
-
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SCM_SECURITY) {
-
-                                size_t l;
-                                l = cmsg->cmsg_len - CMSG_LEN(0);
-                                if (l > 0) {
-                                        memcpy(&bus->label, CMSG_DATA(cmsg), l);
-                                        bus->label[l] = 0;
-                                }
-                        }
-                }
-        }
-
-        r = bus_socket_read_message_need(bus, &need);
-        if (r < 0)
-                return r;
-
-        if (bus->rbuffer_size >= need)
-                return bus_socket_make_message(bus, need);
-
-        return 1;
-}
-
-int bus_socket_process_opening(sd_bus *b) {
-        int error = 0;
-        socklen_t slen = sizeof(error);
-        struct pollfd p = {
-                .fd = b->output_fd,
-                .events = POLLOUT,
-        };
-        int r;
-
-        assert(b->state == BUS_OPENING);
-
-        r = poll(&p, 1, 0);
-        if (r < 0)
-                return -errno;
-
-        if (!(p.revents & (POLLOUT|POLLERR|POLLHUP)))
-                return 0;
-
-        r = getsockopt(b->output_fd, SOL_SOCKET, SO_ERROR, &error, &slen);
-        if (r < 0)
-                b->last_connect_error = errno;
-        else if (error != 0)
-                b->last_connect_error = error;
-        else if (p.revents & (POLLERR|POLLHUP))
-                b->last_connect_error = ECONNREFUSED;
-        else
-                return bus_socket_start_auth(b);
-
-        return bus_next_address(b);
-}
-
-int bus_socket_process_authenticating(sd_bus *b) {
-        int r;
-
-        assert(b);
-        assert(b->state == BUS_AUTHENTICATING);
-
-        if (now(CLOCK_MONOTONIC) >= b->auth_timeout)
-                return -ETIMEDOUT;
-
-        r = bus_socket_write_auth(b);
-        if (r != 0)
-                return r;
-
-        return bus_socket_read_auth(b);
-}
diff --git a/src/libsystemd/bus-socket.h b/src/libsystemd/bus-socket.h
deleted file mode 100644
index 5a1c7d4..0000000
--- a/src/libsystemd/bus-socket.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-*- 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-bus.h"
-
-void bus_socket_setup(sd_bus *b);
-
-int bus_socket_connect(sd_bus *b);
-int bus_socket_exec(sd_bus *b);
-int bus_socket_take_fd(sd_bus *b);
-int bus_socket_start_auth(sd_bus *b);
-
-int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx);
-int bus_socket_read_message(sd_bus *bus);
-
-int bus_socket_process_opening(sd_bus *b);
-int bus_socket_process_authenticating(sd_bus *b);
-
-bool bus_socket_auth_needs_write(sd_bus *b);
diff --git a/src/libsystemd/bus-type.c b/src/libsystemd/bus-type.c
deleted file mode 100644
index b7914d1..0000000
--- a/src/libsystemd/bus-type.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*-*- 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 "util.h"
-#include "bus-type.h"
-
-bool bus_type_is_valid(char c) {
-        static const char valid[] = {
-                SD_BUS_TYPE_BYTE,
-                SD_BUS_TYPE_BOOLEAN,
-                SD_BUS_TYPE_INT16,
-                SD_BUS_TYPE_UINT16,
-                SD_BUS_TYPE_INT32,
-                SD_BUS_TYPE_UINT32,
-                SD_BUS_TYPE_INT64,
-                SD_BUS_TYPE_UINT64,
-                SD_BUS_TYPE_DOUBLE,
-                SD_BUS_TYPE_STRING,
-                SD_BUS_TYPE_OBJECT_PATH,
-                SD_BUS_TYPE_SIGNATURE,
-                SD_BUS_TYPE_ARRAY,
-                SD_BUS_TYPE_VARIANT,
-                SD_BUS_TYPE_STRUCT,
-                SD_BUS_TYPE_DICT_ENTRY,
-                SD_BUS_TYPE_UNIX_FD
-        };
-
-        return !!memchr(valid, c, sizeof(valid));
-}
-
-bool bus_type_is_valid_in_signature(char c) {
-        static const char valid[] = {
-                SD_BUS_TYPE_BYTE,
-                SD_BUS_TYPE_BOOLEAN,
-                SD_BUS_TYPE_INT16,
-                SD_BUS_TYPE_UINT16,
-                SD_BUS_TYPE_INT32,
-                SD_BUS_TYPE_UINT32,
-                SD_BUS_TYPE_INT64,
-                SD_BUS_TYPE_UINT64,
-                SD_BUS_TYPE_DOUBLE,
-                SD_BUS_TYPE_STRING,
-                SD_BUS_TYPE_OBJECT_PATH,
-                SD_BUS_TYPE_SIGNATURE,
-                SD_BUS_TYPE_ARRAY,
-                SD_BUS_TYPE_VARIANT,
-                SD_BUS_TYPE_STRUCT_BEGIN,
-                SD_BUS_TYPE_STRUCT_END,
-                SD_BUS_TYPE_DICT_ENTRY_BEGIN,
-                SD_BUS_TYPE_DICT_ENTRY_END,
-                SD_BUS_TYPE_UNIX_FD
-        };
-
-        return !!memchr(valid, c, sizeof(valid));
-}
-
-bool bus_type_is_basic(char c) {
-        static const char valid[] = {
-                SD_BUS_TYPE_BYTE,
-                SD_BUS_TYPE_BOOLEAN,
-                SD_BUS_TYPE_INT16,
-                SD_BUS_TYPE_UINT16,
-                SD_BUS_TYPE_INT32,
-                SD_BUS_TYPE_UINT32,
-                SD_BUS_TYPE_INT64,
-                SD_BUS_TYPE_UINT64,
-                SD_BUS_TYPE_DOUBLE,
-                SD_BUS_TYPE_STRING,
-                SD_BUS_TYPE_OBJECT_PATH,
-                SD_BUS_TYPE_SIGNATURE,
-                SD_BUS_TYPE_UNIX_FD
-        };
-
-        return !!memchr(valid, c, sizeof(valid));
-}
-
-bool bus_type_is_trivial(char c) {
-        static const char valid[] = {
-                SD_BUS_TYPE_BYTE,
-                SD_BUS_TYPE_BOOLEAN,
-                SD_BUS_TYPE_INT16,
-                SD_BUS_TYPE_UINT16,
-                SD_BUS_TYPE_INT32,
-                SD_BUS_TYPE_UINT32,
-                SD_BUS_TYPE_INT64,
-                SD_BUS_TYPE_UINT64,
-                SD_BUS_TYPE_DOUBLE
-        };
-
-        return !!memchr(valid, c, sizeof(valid));
-}
-
-bool bus_type_is_container(char c) {
-        static const char valid[] = {
-                SD_BUS_TYPE_ARRAY,
-                SD_BUS_TYPE_VARIANT,
-                SD_BUS_TYPE_STRUCT,
-                SD_BUS_TYPE_DICT_ENTRY
-        };
-
-        return !!memchr(valid, c, sizeof(valid));
-}
-
-int bus_type_get_alignment(char c) {
-
-        switch (c) {
-        case SD_BUS_TYPE_BYTE:
-        case SD_BUS_TYPE_SIGNATURE:
-        case SD_BUS_TYPE_VARIANT:
-                return 1;
-
-        case SD_BUS_TYPE_INT16:
-        case SD_BUS_TYPE_UINT16:
-                return 2;
-
-        case SD_BUS_TYPE_BOOLEAN:
-        case SD_BUS_TYPE_INT32:
-        case SD_BUS_TYPE_UINT32:
-        case SD_BUS_TYPE_STRING:
-        case SD_BUS_TYPE_OBJECT_PATH:
-        case SD_BUS_TYPE_ARRAY:
-        case SD_BUS_TYPE_UNIX_FD:
-                return 4;
-
-        case SD_BUS_TYPE_INT64:
-        case SD_BUS_TYPE_UINT64:
-        case SD_BUS_TYPE_DOUBLE:
-        case SD_BUS_TYPE_STRUCT:
-        case SD_BUS_TYPE_STRUCT_BEGIN:
-        case SD_BUS_TYPE_DICT_ENTRY:
-        case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
-                return 8;
-        }
-
-        return -EINVAL;
-}
-
-int bus_type_get_size(char c) {
-
-        switch (c) {
-        case SD_BUS_TYPE_BYTE:
-                return 1;
-
-        case SD_BUS_TYPE_INT16:
-        case SD_BUS_TYPE_UINT16:
-                return 2;
-
-        case SD_BUS_TYPE_BOOLEAN:
-        case SD_BUS_TYPE_INT32:
-        case SD_BUS_TYPE_UINT32:
-        case SD_BUS_TYPE_UNIX_FD:
-                return 4;
-
-        case SD_BUS_TYPE_INT64:
-        case SD_BUS_TYPE_UINT64:
-        case SD_BUS_TYPE_DOUBLE:
-                return 8;
-        }
-
-        return -EINVAL;
-}
diff --git a/src/libsystemd/bus-type.h b/src/libsystemd/bus-type.h
deleted file mode 100644
index 2e423bb..0000000
--- a/src/libsystemd/bus-type.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- 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 <stdbool.h>
-
-#include "sd-bus.h"
-#include "sd-bus-protocol.h"
-
-bool bus_type_is_valid(char c) _const_;
-bool bus_type_is_valid_in_signature(char c) _const_;
-bool bus_type_is_basic(char c) _const_;
-bool bus_type_is_trivial(char c) _const_;
-bool bus_type_is_container(char c) _const_;
-
-int bus_type_get_alignment(char c) _const_;
-int bus_type_get_size(char c) _const_;
diff --git a/src/libsystemd/bus-util.c b/src/libsystemd/bus-util.c
deleted file mode 100644
index a468bca..0000000
--- a/src/libsystemd/bus-util.c
+++ /dev/null
@@ -1,1232 +0,0 @@
-/*-*- 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 <sys/socket.h>
-#include <sys/capability.h>
-
-#include "util.h"
-#include "strv.h"
-#include "macro.h"
-#include "def.h"
-#include "missing.h"
-
-#include "sd-event.h"
-#include "sd-bus.h"
-#include "bus-error.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "bus-internal.h"
-
-static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        sd_event *e = userdata;
-
-        assert(bus);
-        assert(m);
-        assert(e);
-
-        sd_event_exit(e, 0);
-        return 1;
-}
-
-int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
-        _cleanup_free_ char *match = NULL;
-        const char *unique;
-        int r;
-
-        assert(e);
-        assert(bus);
-        assert(name);
-
-        /* We unregister the name here and then wait for the
-         * NameOwnerChanged signal for this event to arrive before we
-         * quit. We do this in order to make sure that any queued
-         * requests are still processed before we really exit. */
-
-        r = sd_bus_get_unique_name(bus, &unique);
-        if (r < 0)
-                return r;
-
-        r = asprintf(&match,
-                     "sender='org.freedesktop.DBus',"
-                     "type='signal',"
-                     "interface='org.freedesktop.DBus',"
-                     "member='NameOwnerChanged',"
-                     "path='/org/freedesktop/DBus',"
-                     "arg0='%s',"
-                     "arg1='%s',"
-                     "arg2=''", name, unique);
-        if (r < 0)
-                return -ENOMEM;
-
-        r = sd_bus_add_match(bus, match, name_owner_change_callback, e);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_release_name(bus, name);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int bus_event_loop_with_idle(
-                sd_event *e,
-                sd_bus *bus,
-                const char *name,
-                usec_t timeout,
-                check_idle_t check_idle,
-                void *userdata) {
-        bool exiting = false;
-        int r, code;
-
-        assert(e);
-        assert(bus);
-        assert(name);
-
-        for (;;) {
-                bool idle;
-
-                r = sd_event_get_state(e);
-                if (r < 0)
-                        return r;
-                if (r == SD_EVENT_FINISHED)
-                        break;
-
-                if (check_idle)
-                        idle = check_idle(userdata);
-                else
-                        idle = true;
-
-                r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
-                if (r < 0)
-                        return r;
-
-                if (r == 0 && !exiting) {
-                        r = bus_async_unregister_and_exit(e, bus, name);
-                        if (r < 0)
-                                return r;
-
-                        exiting = true;
-                }
-        }
-
-        r = sd_event_get_exit_code(e, &code);
-        if (r < 0)
-                return r;
-
-        return code;
-}
-
-int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
-        _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
-        int r, has_owner = 0;
-
-        assert(c);
-        assert(name);
-
-        r = sd_bus_call_method(c,
-                               "org.freedesktop.DBus",
-                               "/org/freedesktop/dbus",
-                               "org.freedesktop.DBus",
-                               "NameHasOwner",
-                               error,
-                               &rep,
-                               "s",
-                               name);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read_basic(rep, 'b', &has_owner);
-        if (r < 0)
-                return sd_bus_error_set_errno(error, r);
-
-        return has_owner;
-}
-
-int bus_verify_polkit(
-                sd_bus *bus,
-                sd_bus_message *m,
-                const char *action,
-                bool interactive,
-                bool *_challenge,
-                sd_bus_error *e) {
-
-        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-        uid_t uid;
-        int r;
-
-        assert(bus);
-        assert(m);
-        assert(action);
-
-        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_creds_get_uid(creds, &uid);
-        if (r < 0)
-                return r;
-
-        if (uid == 0)
-                return 1;
-
-#ifdef ENABLE_POLKIT
-        else {
-                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-                int authorized = false, challenge = false;
-                const char *sender;
-
-                sender = sd_bus_message_get_sender(m);
-                if (!sender)
-                        return -EBADMSG;
-
-                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_enter_container(reply, 'r', "bba{ss}");
-                if (r < 0)
-                        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;
-        Hashmap *registry;
-} AsyncPolkitQuery;
-
-static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
-
-        if (!q)
-                return;
-
-        if (q->serial > 0 && b)
-                sd_bus_call_async_cancel(b, q->serial);
-
-        if (q->registry && q->request)
-                hashmap_remove(q->registry, q->request);
-
-        sd_bus_message_unref(q->request);
-        sd_bus_message_unref(q->reply);
-
-        free(q);
-}
-
-static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        AsyncPolkitQuery *q = userdata;
-        int r;
-
-        assert(bus);
-        assert(reply);
-        assert(q);
-
-        q->reply = sd_bus_message_ref(reply);
-        q->serial = 0;
-
-        r = sd_bus_message_rewind(q->request, true);
-        if (r < 0) {
-                r = sd_bus_reply_method_errno(q->request, r, NULL);
-                goto finish;
-        }
-
-        r = q->callback(bus, q->request, q->userdata, &error_buffer);
-        r = bus_maybe_reply_error(q->request, r, &error_buffer);
-
-finish:
-        async_polkit_query_free(bus, q);
-        return r;
-}
-
-#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;
-        const char *sender;
-#endif
-        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-        uid_t uid;
-        int r;
-
-        assert(bus);
-        assert(registry);
-        assert(m);
-        assert(action);
-
-#ifdef ENABLE_POLKIT
-        q = hashmap_get(*registry, m);
-        if (q) {
-                int 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;
-
-                        /* Copy error from polkit reply */
-                        e = sd_bus_message_get_error(q->reply);
-                        sd_bus_error_copy(error, e);
-
-                        /* Treat no PK available as access denied */
-                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
-                                return -EACCES;
-
-                        return -sd_bus_error_get_errno(e);
-                }
-
-                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
-                if (r >= 0)
-                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
-
-                if (r < 0)
-                        return r;
-
-                if (authorized)
-                        return 1;
-
-                return -EACCES;
-        }
-#endif
-
-        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_creds_get_uid(creds, &uid);
-        if (r < 0)
-                return r;
-
-        if (uid == 0)
-                return 1;
-
-#ifdef ENABLE_POLKIT
-        sender = sd_bus_message_get_sender(m);
-        if (!sender)
-                return -EBADMSG;
-
-        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,
-                        NULL);
-        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;
-        }
-
-        q->registry = *registry;
-
-        r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
-        if (r < 0) {
-                async_polkit_query_free(bus, q);
-                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
-}
-
-int bus_check_peercred(sd_bus *c) {
-        struct ucred ucred;
-        socklen_t l;
-        int fd;
-
-        assert(c);
-
-        fd = sd_bus_get_fd(c);
-        if (fd < 0)
-                return fd;
-
-        l = sizeof(struct ucred);
-        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
-                return -errno;
-
-        if (l != sizeof(struct ucred))
-                return -E2BIG;
-
-        if (ucred.uid != 0 && ucred.uid != geteuid())
-                return -EPERM;
-
-        return 1;
-}
-
-int bus_open_system_systemd(sd_bus **_bus) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-        int r;
-
-        assert(_bus);
-
-        if (geteuid() != 0)
-                return sd_bus_open_system(_bus);
-
-        /* If we are root and kdbus is not available, then let's talk
-         * directly to the system instance, instead of going via the
-         * bus */
-
-#ifdef ENABLE_KDBUS
-        r = sd_bus_new(&bus);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH);
-        if (r < 0)
-                return r;
-
-        bus->bus_client = true;
-
-        r = sd_bus_start(bus);
-        if (r >= 0) {
-                *_bus = bus;
-                bus = NULL;
-                return 0;
-        }
-
-        bus = sd_bus_unref(bus);
-#endif
-
-        r = sd_bus_new(&bus);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
-        if (r < 0)
-                return r;
-
-        r = sd_bus_start(bus);
-        if (r < 0)
-                return sd_bus_open_system(_bus);
-
-        r = bus_check_peercred(bus);
-        if (r < 0)
-                return r;
-
-        *_bus = bus;
-        bus = NULL;
-
-        return 0;
-}
-
-int bus_open_user_systemd(sd_bus **_bus) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-        _cleanup_free_ char *ee = NULL;
-        const char *e;
-        int r;
-
-        /* Try via kdbus first, and then directly */
-
-        assert(_bus);
-
-#ifdef ENABLE_KDBUS
-        r = sd_bus_new(&bus);
-        if (r < 0)
-                return r;
-
-        if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid()) < 0)
-                return -ENOMEM;
-
-        bus->bus_client = true;
-
-        r = sd_bus_start(bus);
-        if (r >= 0) {
-                *_bus = bus;
-                bus = NULL;
-                return 0;
-        }
-
-        bus = sd_bus_unref(bus);
-#endif
-
-        e = secure_getenv("XDG_RUNTIME_DIR");
-        if (!e)
-                return sd_bus_open_user(_bus);
-
-        ee = bus_address_escape(e);
-        if (!ee)
-                return -ENOMEM;
-
-        r = sd_bus_new(&bus);
-        if (r < 0)
-                return r;
-
-        bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
-        if (!bus->address)
-                return -ENOMEM;
-
-        r = sd_bus_start(bus);
-        if (r < 0)
-                return sd_bus_open_user(_bus);
-
-        r = bus_check_peercred(bus);
-        if (r < 0)
-                return r;
-
-        *_bus = bus;
-        bus = NULL;
-
-        return 0;
-}
-
-int bus_print_property(const char *name, sd_bus_message *property, bool all) {
-        char type;
-        const char *contents;
-        int r;
-
-        assert(name);
-        assert(property);
-
-        r = sd_bus_message_peek_type(property, &type, &contents);
-        if (r < 0)
-                return r;
-
-        switch (type) {
-
-        case SD_BUS_TYPE_STRING: {
-                const char *s;
-
-                r = sd_bus_message_read_basic(property, type, &s);
-                if (r < 0)
-                        return r;
-
-                if (all || !isempty(s))
-                        printf("%s=%s\n", name, s);
-
-                return 1;
-        }
-
-        case SD_BUS_TYPE_BOOLEAN: {
-                bool b;
-
-                r = sd_bus_message_read_basic(property, type, &b);
-                if (r < 0)
-                        return r;
-
-                printf("%s=%s\n", name, yes_no(b));
-
-                return 1;
-        }
-
-        case SD_BUS_TYPE_UINT64: {
-                uint64_t u;
-
-                r = sd_bus_message_read_basic(property, type, &u);
-                if (r < 0)
-                        return r;
-
-                /* Yes, heuristics! But we can change this check
-                 * should it turn out to not be sufficient */
-
-                if (endswith(name, "Timestamp")) {
-                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
-
-                        t = format_timestamp(timestamp, sizeof(timestamp), u);
-                        if (t || all)
-                                printf("%s=%s\n", name, strempty(t));
-
-                } else if (strstr(name, "USec")) {
-                        char timespan[FORMAT_TIMESPAN_MAX];
-
-                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
-                } else
-                        printf("%s=%llu\n", name, (unsigned long long) u);
-
-                return 1;
-        }
-
-        case SD_BUS_TYPE_UINT32: {
-                uint32_t u;
-
-                r = sd_bus_message_read_basic(property, type, &u);
-                if (r < 0)
-                        return r;
-
-                if (strstr(name, "UMask") || strstr(name, "Mode"))
-                        printf("%s=%04o\n", name, u);
-                else
-                        printf("%s=%u\n", name, (unsigned) u);
-
-                return 1;
-        }
-
-        case SD_BUS_TYPE_INT32: {
-                int32_t i;
-
-                r = sd_bus_message_read_basic(property, type, &i);
-                if (r < 0)
-                        return r;
-
-                printf("%s=%i\n", name, (int) i);
-                return 1;
-        }
-
-        case SD_BUS_TYPE_DOUBLE: {
-                double d;
-
-                r = sd_bus_message_read_basic(property, type, &d);
-                if (r < 0)
-                        return r;
-
-                printf("%s=%g\n", name, d);
-                return 1;
-        }
-
-        case SD_BUS_TYPE_ARRAY:
-                if (streq(contents, "s")) {
-                        bool first = true;
-                        const char *str;
-
-                        r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
-                        if (r < 0)
-                                return r;
-
-                        while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
-                                if (first)
-                                        printf("%s=", name);
-
-                                printf("%s%s", first ? "" : " ", str);
-
-                                first = false;
-                        }
-                        if (r < 0)
-                                return r;
-
-                        if (first && all)
-                                printf("%s=", name);
-                        if (!first || all)
-                                puts("");
-
-                        r = sd_bus_message_exit_container(property);
-                        if (r < 0)
-                                return r;
-
-                        return 1;
-
-                } else if (streq(contents, "y")) {
-                        const uint8_t *u;
-                        size_t n;
-
-                        r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
-                        if (r < 0)
-                                return r;
-
-                        if (all || n > 0) {
-                                unsigned int i;
-
-                                printf("%s=", name);
-
-                                for (i = 0; i < n; i++)
-                                        printf("%02x", u[i]);
-
-                                puts("");
-                        }
-
-                        return 1;
-
-                } else if (streq(contents, "u")) {
-                        uint32_t *u;
-                        size_t n;
-
-                        r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
-                        if (r < 0)
-                                return r;
-
-                        if (all || n > 0) {
-                                unsigned int i;
-
-                                printf("%s=", name);
-
-                                for (i = 0; i < n; i++)
-                                        printf("%08x", u[i]);
-
-                                puts("");
-                        }
-
-                        return 1;
-                }
-
-                break;
-        }
-
-        return 0;
-}
-
-int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        int r;
-
-        assert(bus);
-        assert(path);
-
-        r = sd_bus_call_method(bus,
-                        dest,
-                        path,
-                        "org.freedesktop.DBus.Properties",
-                        "GetAll",
-                        &error,
-                        &reply,
-                        "s", "");
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
-        if (r < 0)
-                return r;
-
-        while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
-                const char *name;
-                const char *contents;
-
-                r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
-                if (r < 0)
-                        return r;
-
-                if (!filter || strv_find(filter, name)) {
-                        r = sd_bus_message_peek_type(reply, NULL, &contents);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
-                        if (r < 0)
-                                return r;
-
-                        r = bus_print_property(name, reply, all);
-                        if (r < 0)
-                                return r;
-                        if (r == 0) {
-                                if (all)
-                                        printf("%s=[unprintable]\n", name);
-                                /* skip what we didn't read */
-                                r = sd_bus_message_skip(reply, contents);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        r = sd_bus_message_exit_container(reply);
-                        if (r < 0)
-                                return r;
-                } else {
-                        r = sd_bus_message_skip(reply, "v");
-                        if (r < 0)
-                                return r;
-                }
-
-                r = sd_bus_message_exit_container(reply);
-                if (r < 0)
-                        return r;
-        }
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        sd_id128_t *p = userdata;
-        const void *v;
-        size_t n;
-        int r;
-
-        r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
-        if (r < 0)
-                return r;
-
-        if (n == 0)
-                *p = SD_ID128_NULL;
-        else if (n == 16)
-                memcpy((*p).bytes, v, n);
-        else
-                return -EINVAL;
-
-        return 0;
-}
-
-static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        char type;
-        int r;
-
-        r = sd_bus_message_peek_type(m, &type, NULL);
-        if (r < 0)
-                return r;
-
-        switch (type) {
-        case SD_BUS_TYPE_STRING: {
-                const char *s;
-                char *str;
-                char **p = userdata;
-
-                r = sd_bus_message_read_basic(m, type, &s);
-                if (r < 0)
-                        break;
-
-                if (isempty(s))
-                        break;
-
-                str = strdup(s);
-                if (!str) {
-                        r = -ENOMEM;
-                        break;
-                }
-                free(*p);
-                *p = str;
-
-                break;
-        }
-
-        case SD_BUS_TYPE_ARRAY: {
-               _cleanup_strv_free_ char **l = NULL;
-               char ***p = userdata;
-
-                r = bus_message_read_strv_extend(m, &l);
-                if (r < 0)
-                        break;
-
-                strv_free(*p);
-                *p = l;
-                l = NULL;
-
-                break;
-        }
-
-        case SD_BUS_TYPE_BOOLEAN: {
-                unsigned b;
-                bool *p = userdata;
-
-                r = sd_bus_message_read_basic(m, type, &b);
-                if (r < 0)
-                        break;
-
-                *p = b;
-
-                break;
-        }
-
-        case SD_BUS_TYPE_UINT32: {
-                uint64_t u;
-                uint32_t *p = userdata;
-
-                r = sd_bus_message_read_basic(m, type, &u);
-                if (r < 0)
-                        break;
-
-                *p = u;
-
-                break;
-        }
-
-        case SD_BUS_TYPE_UINT64: {
-                uint64_t t;
-                uint64_t *p = userdata;
-
-                r = sd_bus_message_read_basic(m, type, &t);
-                if (r < 0)
-                        break;
-
-                *p = t;
-
-                break;
-        }
-
-        default:
-                break;
-        }
-
-        return r;
-}
-
-int bus_map_all_properties(sd_bus *bus,
-                           const char *destination,
-                           const char *path,
-                           const struct bus_properties_map *map,
-                           void *userdata) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        int r;
-
-        assert(bus);
-        assert(destination);
-        assert(path);
-        assert(map);
-
-        r = sd_bus_call_method(
-                        bus,
-                        destination,
-                        path,
-                        "org.freedesktop.DBus.Properties",
-                        "GetAll",
-                        &error,
-                        &m,
-                        "s", "");
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
-        if (r < 0)
-                return r;
-
-        while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
-                const struct bus_properties_map *prop;
-                const char *member;
-                const char *contents;
-                void *v;
-                unsigned i;
-
-                r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
-                if (r < 0)
-                        return r;
-
-                for (i = 0, prop = NULL; map[i].member; i++)
-                        if (streq(map[i].member, member)) {
-                                prop = &map[i];
-                                break;
-                        }
-
-                if (prop) {
-                        r = sd_bus_message_peek_type(m, NULL, &contents);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
-                        if (r < 0)
-                                return r;
-
-                        v = (uint8_t *)userdata + prop->offset;
-                        if (map[i].set)
-                                r = prop->set(bus, member, m, &error, v);
-                        else
-                                r = map_basic(bus, member, m, &error, v);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_bus_message_exit_container(m);
-                        if (r < 0)
-                                return r;
-                } else {
-                        r = sd_bus_message_skip(m, "v");
-                        if (r < 0)
-                                return r;
-                }
-
-                r = sd_bus_message_exit_container(m);
-                if (r < 0)
-                        return r;
-        }
-
-        return r;
-}
-
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
-        int r;
-
-        assert(transport >= 0);
-        assert(transport < _BUS_TRANSPORT_MAX);
-        assert(bus);
-
-        assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
-        assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
-
-        switch (transport) {
-
-        case BUS_TRANSPORT_LOCAL:
-                if (user)
-                        r = sd_bus_default_user(bus);
-                else
-                        r = sd_bus_default_system(bus);
-
-                break;
-
-        case BUS_TRANSPORT_REMOTE:
-                r = sd_bus_open_system_remote(host, bus);
-                break;
-
-        case BUS_TRANSPORT_CONTAINER:
-                r = sd_bus_open_system_container(host, bus);
-                break;
-
-        default:
-                assert_not_reached("Hmm, unknown transport type.");
-        }
-
-        return r;
-}
-
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
-        int r;
-
-        assert(transport >= 0);
-        assert(transport < _BUS_TRANSPORT_MAX);
-        assert(bus);
-
-        assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
-        assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
-
-        switch (transport) {
-
-        case BUS_TRANSPORT_LOCAL:
-                if (user)
-                        r = bus_open_user_systemd(bus);
-                else
-                        r = bus_open_system_systemd(bus);
-
-                break;
-
-        case BUS_TRANSPORT_REMOTE:
-                r = sd_bus_open_system_remote(host, bus);
-                break;
-
-        case BUS_TRANSPORT_CONTAINER:
-                r = sd_bus_open_system_container(host, bus);
-                break;
-
-        default:
-                assert_not_reached("Hmm, unknown transport type.");
-        }
-
-        return r;
-}
-
-int bus_property_get_tristate(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        int *tristate = userdata;
-
-        return sd_bus_message_append(reply, "b", *tristate > 0);
-}
-
-int bus_property_get_bool(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        int b = *(bool*) userdata;
-
-        return sd_bus_message_append_basic(reply, 'b', &b);
-}
-
-#if __SIZEOF_SIZE_T__ != 8
-int bus_property_get_size(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        uint64_t sz = *(size_t*) userdata;
-
-        return sd_bus_message_append_basic(reply, 't', &sz);
-}
-#endif
-
-#if __SIZEOF_LONG__ != 8
-int bus_property_get_long(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        int64_t l = *(long*) userdata;
-
-        return sd_bus_message_append_basic(reply, 'x', &l);
-}
-
-int bus_property_get_ulong(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        uint64_t ul = *(unsigned long*) userdata;
-
-        return sd_bus_message_append_basic(reply, 't', &ul);
-}
-#endif
-
-int bus_log_parse_error(int r) {
-        log_error("Failed to parse message: %s", strerror(-r));
-        return r;
-}
-
-int bus_log_create_error(int r) {
-        log_error("Failed to create message: %s", strerror(-r));
-        return r;
-}
-
-int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
-        assert(message);
-        assert(u);
-
-        return sd_bus_message_read(
-                        message,
-                        "(ssssssouso)",
-                        &u->id,
-                        &u->description,
-                        &u->load_state,
-                        &u->active_state,
-                        &u->sub_state,
-                        &u->following,
-                        &u->unit_path,
-                        &u->job_id,
-                        &u->job_type,
-                        &u->job_path);
-}
-
-int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
-        assert(m);
-
-        if (r < 0) {
-                if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
-                        sd_bus_reply_method_errno(m, r, error);
-
-        } else if (sd_bus_error_is_set(error)) {
-                if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
-                        sd_bus_reply_method_error(m, error);
-        } else
-                return r;
-
-        log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
-                  bus_message_type_to_string(m->header->type),
-                  strna(m->sender),
-                  strna(m->path),
-                  strna(m->interface),
-                  strna(m->member),
-                  strna(m->root_container.signature),
-                  bus_error_message(error, r));
-
-        return 1;
-}
diff --git a/src/libsystemd/bus-util.h b/src/libsystemd/bus-util.h
deleted file mode 100644
index 51e1613..0000000
--- a/src/libsystemd/bus-util.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*-*- 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"
-
-typedef enum BusTransport {
-        BUS_TRANSPORT_LOCAL,
-        BUS_TRANSPORT_REMOTE,
-        BUS_TRANSPORT_CONTAINER,
-        _BUS_TRANSPORT_MAX,
-        _BUS_TRANSPORT_INVALID = -1
-} BusTransport;
-
-typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
-
-struct bus_properties_map {
-        const char *member;
-        const char *signature;
-        bus_property_set_t set;
-        size_t offset;
-};
-
-int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
-
-int bus_map_all_properties(sd_bus *bus,
-                           const char *destination,
-                           const char *path,
-                           const struct bus_properties_map *map,
-                           void *userdata);
-
-int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name);
-
-typedef bool (*check_idle_t)(void *userdata);
-
-int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout, check_idle_t check_idle, void *userdata);
-
-int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
-
-int bus_check_peercred(sd_bus *c);
-
-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);
-
-int bus_open_system_systemd(sd_bus **_bus);
-int bus_open_user_systemd(sd_bus **_bus);
-
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
-
-int bus_print_property(const char *name, sd_bus_message *property, bool all);
-int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
-
-int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
-int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
-
-#define bus_property_get_usec ((sd_bus_property_get_t) NULL)
-#define bus_property_set_usec ((sd_bus_property_set_t) NULL)
-
-assert_cc(sizeof(int) == sizeof(int32_t));
-#define bus_property_get_int ((sd_bus_property_get_t) NULL)
-
-assert_cc(sizeof(unsigned) == sizeof(unsigned));
-#define bus_property_get_unsigned ((sd_bus_property_get_t) NULL)
-
-/* On 64bit machines we can use the default serializer for size_t and
- * friends, otherwise we need to cast this manually */
-#if __SIZEOF_SIZE_T__ == 8
-#define bus_property_get_size ((sd_bus_property_get_t) NULL)
-#else
-int bus_property_get_size(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
-#endif
-
-#if __SIZEOF_LONG__ == 8
-#define bus_property_get_long ((sd_bus_property_get_t) NULL)
-#define bus_property_get_ulong ((sd_bus_property_get_t) NULL)
-#else
-int bus_property_get_long(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
-int bus_property_get_ulong(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
-#endif
-
-/* uid_t and friends on Linux 32 bit. This means we can just use the
- * default serializer for 32bit unsigned, for serializing it, and map
- * it to NULL here */
-assert_cc(sizeof(uid_t) == sizeof(uint32_t));
-#define bus_property_get_uid ((sd_bus_property_get_t) NULL)
-
-assert_cc(sizeof(gid_t) == sizeof(uint32_t));
-#define bus_property_get_gid ((sd_bus_property_get_t) NULL)
-
-assert_cc(sizeof(pid_t) == sizeof(uint32_t));
-#define bus_property_get_pid ((sd_bus_property_get_t) NULL)
-
-assert_cc(sizeof(mode_t) == sizeof(uint32_t));
-#define bus_property_get_mode ((sd_bus_property_get_t) NULL)
-
-int bus_log_parse_error(int r);
-int bus_log_create_error(int r);
-
-typedef struct UnitInfo {
-        const char *id;
-        const char *description;
-        const char *load_state;
-        const char *active_state;
-        const char *sub_state;
-        const char *following;
-        const char *unit_path;
-        uint32_t job_id;
-        const char *job_type;
-        const char *job_path;
-} UnitInfo;
-
-int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref);
-
-#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
-#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
-#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp)
-#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
-
-#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type)              \
-        int function(sd_bus *bus,                                       \
-                     const char *path,                                  \
-                     const char *interface,                             \
-                     const char *property,                              \
-                     sd_bus_message *reply,                             \
-                     void *userdata,                                    \
-                     sd_bus_error *error) {                             \
-                                                                        \
-                const char *value;                                      \
-                type *field = userdata;                                 \
-                int r;                                                  \
-                                                                        \
-                assert(bus);                                            \
-                assert(reply);                                          \
-                assert(field);                                          \
-                                                                        \
-                value = strempty(name##_to_string(*field));             \
-                                                                        \
-                r = sd_bus_message_append_basic(reply, 's', value);     \
-                if (r < 0)                                              \
-                        return r;                                       \
-                                                                        \
-                return 1;                                               \
-        }                                                               \
-        struct __useless_struct_to_allow_trailing_semicolon__
-
-#define BUS_PROPERTY_DUAL_TIMESTAMP(name, offset, flags) \
-        SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \
-        SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags))
-
-int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
diff --git a/src/libsystemd/busctl.c b/src/libsystemd/busctl.c
deleted file mode 100644
index e962ba3..0000000
--- a/src/libsystemd/busctl.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*-*- 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 <getopt.h>
-
-#include "strv.h"
-#include "util.h"
-#include "log.h"
-#include "build.h"
-#include "pager.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-
-static bool arg_no_pager = false;
-static char *arg_address = NULL;
-static bool arg_unique = false;
-static bool arg_acquired = false;
-static bool arg_activatable = false;
-static bool arg_show_machine = false;
-static char **arg_matches = NULL;
-static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
-static bool arg_user = false;
-
-static void pager_open_if_enabled(void) {
-
-        /* Cache result before we open the pager */
-        if (arg_no_pager)
-                return;
-
-        pager_open(false);
-}
-
-static int list_bus_names(sd_bus *bus, char **argv) {
-        _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
-        _cleanup_free_ char **merged = NULL;
-        _cleanup_hashmap_free_ Hashmap *names = NULL;
-        char **i;
-        int r;
-        size_t max_i = 0;
-        unsigned n = 0;
-        void *v;
-        char *k;
-        Iterator iterator;
-
-        assert(bus);
-
-        r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
-        if (r < 0) {
-                log_error("Failed to list names: %s", strerror(-r));
-                return r;
-        }
-
-        pager_open_if_enabled();
-
-        names = hashmap_new(string_hash_func, string_compare_func);
-        if (!names)
-                return log_oom();
-
-        STRV_FOREACH(i, acquired) {
-                max_i = MAX(max_i, strlen(*i));
-
-                r = hashmap_put(names, *i, INT_TO_PTR(1));
-                if (r < 0) {
-                        log_error("Failed to add to hashmap: %s", strerror(-r));
-                        return r;
-                }
-        }
-
-        STRV_FOREACH(i, activatable) {
-                max_i = MAX(max_i, strlen(*i));
-
-                r = hashmap_put(names, *i, INT_TO_PTR(2));
-                if (r < 0 && r != -EEXIST) {
-                        log_error("Failed to add to hashmap: %s", strerror(-r));
-                        return r;
-                }
-        }
-
-        merged = new(char*, hashmap_size(names) + 1);
-        HASHMAP_FOREACH_KEY(v, k, names, iterator)
-                merged[n++] = k;
-
-        merged[n] = NULL;
-        strv_sort(merged);
-
-        printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s",
-               (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION");
-
-        if (arg_show_machine)
-                puts(" MACHINE");
-        else
-                putchar('\n');
-
-        STRV_FOREACH(i, merged) {
-                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-                sd_id128_t mid;
-
-                if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
-                        /* Activatable */
-
-                        printf("%-*s", (int) max_i, *i);
-                        printf("          - -               -                (activatable) -                         -         ");
-                        if (arg_show_machine)
-                                puts(" -");
-                        else
-                                putchar('\n');
-                        continue;
-
-                }
-
-                if (!arg_unique && (*i)[0] == ':')
-                        continue;
-
-                if (!arg_acquired && (*i)[0] != ':')
-                        continue;
-
-                printf("%-*s", (int) max_i, *i);
-
-                r = sd_bus_get_owner(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION, &creds);
-                if (r >= 0) {
-                        const char *unique, *session, *unit;
-                        pid_t pid;
-                        uid_t uid;
-
-                        r = sd_bus_creds_get_pid(creds, &pid);
-                        if (r >= 0) {
-                                const char *comm = NULL;
-
-                                sd_bus_creds_get_comm(creds, &comm);
-
-                                printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
-                        } else
-                                fputs("          - -              ", stdout);
-
-                        r = sd_bus_creds_get_uid(creds, &uid);
-                        if (r >= 0) {
-                                _cleanup_free_ char *u = NULL;
-
-                                u = uid_to_name(uid);
-                                if (!u)
-                                        return log_oom();
-
-                                if (strlen(u) > 16)
-                                        u[16] = 0;
-
-                                printf(" %-16s", u);
-                        } else
-                                fputs(" -               ", stdout);
-
-                        r = sd_bus_creds_get_unique_name(creds, &unique);
-                        if (r >= 0)
-                                printf(" %-13s", unique);
-                        else
-                                fputs(" -            ", stdout);
-
-                        r = sd_bus_creds_get_unit(creds, &unit);
-                        if (r >= 0) {
-                                _cleanup_free_ char *e;
-
-                                e = ellipsize(unit, 25, 100);
-                                if (!e)
-                                        return log_oom();
-
-                                printf(" %-25s", e);
-                        } else
-                                fputs(" -                        ", stdout);
-
-                        r = sd_bus_creds_get_session(creds, &session);
-                        if (r >= 0)
-                                printf(" %-10s", session);
-                        else
-                                fputs(" -         ", stdout);
-
-                } else
-                        printf("          - -               -                -             -                         -         ");
-
-                if (arg_show_machine) {
-                        r = sd_bus_get_owner_machine_id(bus, *i, &mid);
-                        if (r >= 0) {
-                                char m[SD_ID128_STRING_MAX];
-                                printf(" %s\n", sd_id128_to_string(mid, m));
-                        } else
-                                puts(" -");
-                } else
-                        putchar('\n');
-        }
-
-        return 0;
-}
-
-static int monitor(sd_bus *bus, char *argv[]) {
-        bool added_something = false;
-        char **i;
-        int r;
-
-        STRV_FOREACH(i, argv+1) {
-                _cleanup_free_ char *m = NULL;
-
-                if (!service_name_is_valid(*i)) {
-                        log_error("Invalid service name '%s'", *i);
-                        return -EINVAL;
-                }
-
-                m = strjoin("sender='", *i, "'", NULL);
-                if (!m)
-                        return log_oom();
-
-                r = sd_bus_add_match(bus, m, NULL, NULL);
-                if (r < 0) {
-                        log_error("Failed to add match: %s", strerror(-r));
-                        return r;
-                }
-
-                added_something = true;
-        }
-
-        STRV_FOREACH(i, arg_matches) {
-                r = sd_bus_add_match(bus, *i, NULL, NULL);
-                if (r < 0) {
-                        log_error("Failed to add match: %s", strerror(-r));
-                        return r;
-                }
-
-                added_something = true;
-        }
-
-        if (!added_something) {
-                r = sd_bus_add_match(bus, "", NULL, NULL);
-                if (r < 0) {
-                        log_error("Failed to add match: %s", strerror(-r));
-                        return r;
-                }
-        }
-
-        for (;;) {
-                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
-                r = sd_bus_process(bus, &m);
-                if (r < 0) {
-                        log_error("Failed to process bus: %s", strerror(-r));
-                        return r;
-                }
-
-                if (m) {
-                        bus_message_dump(m, stdout, true);
-                        continue;
-                }
-
-                if (r > 0)
-                        continue;
-
-                r = sd_bus_wait(bus, (uint64_t) -1);
-                if (r < 0) {
-                        log_error("Failed to wait for bus: %s", strerror(-r));
-                        return r;
-                }
-        }
-}
-
-static int status(sd_bus *bus, char *argv[]) {
-        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-        pid_t pid;
-        int r;
-
-        assert(bus);
-
-        if (strv_length(argv) != 2) {
-                log_error("Expects one argument.");
-                return -EINVAL;
-        }
-
-        r = parse_pid(argv[1], &pid);
-        if (r < 0)
-                r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
-        else
-                r = sd_bus_creds_new_from_pid(pid, _SD_BUS_CREDS_ALL, &creds);
-
-        if (r < 0) {
-                log_error("Failed to get credentials: %s", strerror(-r));
-                return r;
-        }
-
-        bus_creds_dump(creds, NULL);
-        return 0;
-}
-
-static int help(void) {
-
-        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
-               "Introspect the bus.\n\n"
-               "  -h --help               Show this help\n"
-               "     --version            Show package version\n"
-               "     --no-pager           Do not pipe output into a pager\n"
-               "     --system             Connect to system bus\n"
-               "     --user               Connect to user bus\n"
-               "  -H --host=[USER@]HOST   Operate on remote host\n"
-               "  -M --machine=CONTAINER  Operate on local container\n"
-               "     --address=ADDRESS    Connect to bus specified by address\n"
-               "     --show-machine       Show machine ID column in list\n"
-               "     --unique             Only show unique names\n"
-               "     --acquired           Only show acquired names\n"
-               "     --activatable        Only show activatable names\n"
-               "     --match=MATCH        Only show matching messages\n\n"
-               "Commands:\n"
-               "  list                    List bus names\n"
-               "  monitor [SERVICE...]    Show bus traffic\n"
-               "  status NAME             Show name status\n"
-               "  help                    Show this help\n",
-               program_invocation_short_name);
-
-        return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
-        enum {
-                ARG_VERSION = 0x100,
-                ARG_NO_PAGER,
-                ARG_SYSTEM,
-                ARG_USER,
-                ARG_ADDRESS,
-                ARG_MATCH,
-                ARG_SHOW_MACHINE,
-                ARG_UNIQUE,
-                ARG_ACQUIRED,
-                ARG_ACTIVATABLE
-        };
-
-        static const struct option options[] = {
-                { "help",         no_argument,       NULL, 'h'              },
-                { "version",      no_argument,       NULL, ARG_VERSION      },
-                { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
-                { "system",       no_argument,       NULL, ARG_SYSTEM       },
-                { "user",         no_argument,       NULL, ARG_USER         },
-                { "address",      required_argument, NULL, ARG_ADDRESS      },
-                { "show-machine", no_argument,       NULL, ARG_SHOW_MACHINE },
-                { "unique",       no_argument,       NULL, ARG_UNIQUE       },
-                { "acquired",     no_argument,       NULL, ARG_ACQUIRED     },
-                { "activatable",  no_argument,       NULL, ARG_ACTIVATABLE  },
-                { "match",        required_argument, NULL, ARG_MATCH        },
-                { "host",         required_argument, NULL, 'H'              },
-                { "machine",      required_argument, NULL, 'M'              },
-                {},
-        };
-
-        int c;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
-
-                switch (c) {
-
-                case 'h':
-                        return help();
-
-                case ARG_VERSION:
-                        puts(PACKAGE_STRING);
-                        puts(SYSTEMD_FEATURES);
-                        return 0;
-
-                case ARG_NO_PAGER:
-                        arg_no_pager = true;
-                        break;
-
-                case ARG_USER:
-                        arg_user = true;
-                        break;
-
-                case ARG_SYSTEM:
-                        arg_user = false;
-                        break;
-
-                case ARG_ADDRESS:
-                        arg_address = optarg;
-                        break;
-
-                case ARG_SHOW_MACHINE:
-                        arg_show_machine = true;
-                        break;
-
-                case ARG_UNIQUE:
-                        arg_unique = true;
-                        break;
-
-                case ARG_ACQUIRED:
-                        arg_acquired = true;
-                        break;
-
-                case ARG_ACTIVATABLE:
-                        arg_activatable = true;
-                        break;
-
-                case ARG_MATCH:
-                        if (strv_extend(&arg_matches, optarg) < 0)
-                                return log_oom();
-                        break;
-
-                case 'H':
-                        arg_transport = BUS_TRANSPORT_REMOTE;
-                        arg_host = optarg;
-                        break;
-
-                case 'M':
-                        arg_transport = BUS_TRANSPORT_CONTAINER;
-                        arg_host = optarg;
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached("Unhandled option");
-                }
-        }
-
-        if (!arg_unique && !arg_acquired && !arg_activatable)
-                arg_unique = arg_acquired = arg_activatable = true;
-
-        return 1;
-}
-
-static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
-        assert(bus);
-
-        if (optind >= argc ||
-            streq(argv[optind], "list"))
-                return list_bus_names(bus, argv + optind);
-
-        if (streq(argv[optind], "monitor"))
-                return monitor(bus, argv + optind);
-
-        if (streq(argv[optind], "status"))
-                return status(bus, argv + optind);
-
-        if (streq(argv[optind], "help"))
-                return help();
-
-        log_error("Unknown command '%s'", argv[optind]);
-        return -EINVAL;
-}
-
-int main(int argc, char *argv[]) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-        int r;
-
-        log_parse_environment();
-        log_open();
-
-        r = parse_argv(argc, argv);
-        if (r <= 0)
-                goto finish;
-
-        if (arg_address) {
-                r = sd_bus_new(&bus);
-                if (r < 0) {
-                        log_error("Failed to allocate bus: %s", strerror(-r));
-                        goto finish;
-                }
-
-                r = sd_bus_set_address(bus, arg_address);
-                if (r < 0) {
-                        log_error("Failed to set address: %s", strerror(-r));
-                        goto finish;
-                }
-
-                r = sd_bus_set_bus_client(bus, true);
-                if (r < 0) {
-                        log_error("Failed to set bus client: %s", strerror(-r));
-                        goto finish;
-                }
-
-                r = sd_bus_start(bus);
-        } else
-                r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
-
-        if (r < 0) {
-                log_error("Failed to connect to bus: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = busctl_main(bus, argc, argv);
-
-finish:
-        pager_close();
-
-        strv_free(arg_matches);
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/libsystemd/event-util.h b/src/libsystemd/event-util.h
deleted file mode 100644
index e58020d..0000000
--- a/src/libsystemd/event-util.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- 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/kdbus.h b/src/libsystemd/kdbus.h
deleted file mode 100644
index fe0bb48..0000000
--- a/src/libsystemd/kdbus.h
+++ /dev/null
@@ -1,900 +0,0 @@
-/*
- * Copyright (C) 2013 Kay Sievers
- * Copyright (C) 2013 Greg Kroah-Hartman <gregkh at linuxfoundation.org>
- * Copyright (C) 2013 Linux Foundation
- * Copyright (C) 2013 Lennart Poettering
- * Copyright (C) 2013 Daniel Mack <daniel at zonque.org>
- *
- * kdbus 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.
- *
- * "Everything should be made as simple as possible, but not simpler."
- *   -- Albert Einstein
- */
-
-#ifndef _KDBUS_H_
-#define _KDBUS_H_
-
-#ifndef __KERNEL__
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <linux/types.h>
-#endif
-
-#define KDBUS_IOC_MAGIC			0x95
-#define KDBUS_SRC_ID_KERNEL		(0)
-#define KDBUS_DST_ID_NAME		(0)
-#define KDBUS_MATCH_ID_ANY		(~0ULL)
-#define KDBUS_DST_ID_BROADCAST		(~0ULL)
-
-/**
- * struct kdbus_notify_id_change - name registry change message
- * @id:			New or former owner of the name
- * @flags:		flags field from KDBUS_HELLO_*
- *
- * Sent from kernel to userspace when the owner or activator of
- * a well-known name changes.
- *
- * Attached to:
- *   KDBUS_ITEM_ID_ADD
- *   KDBUS_ITEM_ID_REMOVE
- */
-struct kdbus_notify_id_change {
-	__u64 id;
-	__u64 flags;
-};
-
-/**
- * struct kdbus_notify_name_change - name registry change message
- * @old:		ID and flags of former owner of a name
- * @new:		ID and flags of new owner of a name
- * @name:		Well-known name
- *
- * Sent from kernel to userspace when the owner or activator of
- * a well-known name changes.
- *
- * Attached to:
- *   KDBUS_ITEM_NAME_ADD
- *   KDBUS_ITEM_NAME_REMOVE
- *   KDBUS_ITEM_NAME_CHANGE
- */
-struct kdbus_notify_name_change {
-	struct kdbus_notify_id_change old;
-	struct kdbus_notify_id_change new;
-	char name[0];
-};
-
-/**
- * struct kdbus_creds - process credentials
- * @uid:		User ID
- * @gid:		Group ID
- * @pid:		Process ID
- * @tid:		Thread ID
- * @starttime:		Starttime of the process
- *
- * The starttime of the process PID. This is useful to detect PID overruns
- * from the client side. i.e. if you use the PID to look something up in
- * /proc/$PID/ you can afterwards check the starttime field of it, to ensure
- * you didn't run into a PID overrun.
- *
- * Attached to:
- *   KDBUS_ITEM_CREDS
- */
-struct kdbus_creds {
-	__u64 uid;
-	__u64 gid;
-	__u64 pid;
-	__u64 tid;
-	__u64 starttime;
-};
-
-/**
- * struct kdbus_audit - audit information
- * @sessionid:		The audit session ID
- * @loginuid:		The audit login uid
- *
- * Attached to:
- *   KDBUS_ITEM_AUDIT
- */
-struct kdbus_audit {
-	__u64 sessionid;
-	__u64 loginuid;
-};
-
-/**
- * struct kdbus_timestamp
- * @seqnum:		Global per-namespace message sequence number
- * @monotonic_ns:	Monotonic timestamp, in nanoseconds
- * @realtime_ns:	Realtime timestamp, in nanoseconds
- *
- * Attached to:
- *   KDBUS_ITEM_TIMESTAMP
- */
-struct kdbus_timestamp {
-	__u64 seqnum;
-	__u64 monotonic_ns;
-	__u64 realtime_ns;
-};
-
-/**
- * struct kdbus_vec - I/O vector for kdbus payload items
- * @size:		The size of the vector
- * @address:		Memory address for memory addresses
- * @offset:		Offset in the in-message payload memory,
- *			relative to the message head
- *
- * Attached to:
- *   KDBUS_ITEM_PAYLOAD_VEC
- */
-struct kdbus_vec {
-	__u64 size;
-	union {
-		__u64 address;
-		__u64 offset;
-	};
-};
-
-/**
- * struct kdbus_memfd - a kdbus memfd
- * @size:		The memfd's size
- * @fd:			The file descriptor number
- * @__pad:		Padding to ensure proper alignement and size
- *
- * Attached to:
- *   KDBUS_ITEM_PAYLOAD_MEMFD
- */
-struct kdbus_memfd {
-	__u64 size;
-	int fd;
-	__u32 __pad;
-};
-
-/**
- * struct kdbus_name - a registered well-known name with its flags
- * @flags:		flags from KDBUS_NAME_*
- * @name:		well-known name
- *
- * Attached to:
- *   KDBUS_ITEM_NAME
- */
-struct kdbus_name {
-	__u64 flags;
-	char name[0];
-};
-
-/**
- * struct kdbus_policy_access - policy access item
- * @type:		One of KDBUS_POLICY_ACCESS_* types
- * @bits:		Access to grant. One of KDBUS_POLICY_*
- * @id:			For KDBUS_POLICY_ACCESS_USER, the uid
- *			For KDBUS_POLICY_ACCESS_GROUP, the gid
- *
- * Embedded in:
- *   struct kdbus_policy
- */
-struct kdbus_policy_access {
-	__u64 type;	/* USER, GROUP, WORLD */
-	__u64 bits;	/* RECV, SEND, OWN */
-	__u64 id;	/* uid, gid, 0 */
-};
-
-/**
- * struct kdbus_policy - a policy item
- * @access:		Policy access details
- * @name:		Well-known name to grant access to
- *
- * Attached to:
- *   KDBUS_POLICY_ACCESS
- *   KDBUS_ITEM_POLICY_NAME
- */
-struct kdbus_policy {
-	union {
-		struct kdbus_policy_access access;
-		char name[0];
-	};
-};
-
-/**
- * enum kdbus_item_type - item types to chain data in a list
- * @_KDBUS_ITEM_NULL:		Uninitialized/invalid
- * @_KDBUS_ITEM_USER_BASE:	Start of user items
- * @KDBUS_ITEM_PAYLOAD_VEC:	Vector to data
- * @KDBUS_ITEM_PAYLOAD_OFF:	Data at returned offset to message head
- * @KDBUS_ITEM_PAYLOAD_MEMFD:	Data as sealed memfd
- * @KDBUS_ITEM_FDS:		Attached file descriptors
- * @KDBUS_ITEM_BLOOM:		For broadcasts, carries bloom filter
- * @KDBUS_ITEM_BLOOM_SIZE:	Desired bloom size, used by KDBUS_CMD_BUS_MAKE
- * @KDBUS_ITEM_DST_NAME:	Destination's well-known name
- * @KDBUS_ITEM_MAKE_NAME:	Name of namespace, bus, endpoint
- * @KDBUS_ITEM_MEMFD_NAME:	The human readable name of a memfd (debugging)
- * @_KDBUS_ITEM_POLICY_BASE:	Start of policy items
- * @KDBUS_ITEM_POLICY_NAME:	Policy in struct kdbus_policy
- * @KDBUS_ITEM_POLICY_ACCESS:	Policy in struct kdbus_policy
- * @_KDBUS_ITEM_ATTACH_BASE:	Start of metadata attach items
- * @KDBUS_ITEM_NAME:		Well-know name with flags
- * @KDBUS_ITEM_ID:		Connection ID
- * @KDBUS_ITEM_TIMESTAMP:	Timestamp
- * @KDBUS_ITEM_CREDS:		Process credential
- * @KDBUS_ITEM_PID_COMM:	Process ID "comm" identifier
- * @KDBUS_ITEM_TID_COMM:	Thread ID "comm" identifier
- * @KDBUS_ITEM_EXE:		The path of the executable
- * @KDBUS_ITEM_CMDLINE:		The process command line
- * @KDBUS_ITEM_CGROUP:		The croup membership
- * @KDBUS_ITEM_CAPS:		The process capabilities
- * @KDBUS_ITEM_SECLABEL:	The security label
- * @KDBUS_ITEM_AUDIT:		The audit IDs
- * @KDBUS_ITEM_CONN_NAME:	The connection's human-readable name (debugging)
- * @_KDBUS_ITEM_KERNEL_BASE:	Start of kernel-generated message items
- * @KDBUS_ITEM_NAME_ADD:	Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_NAME_REMOVE:	Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_NAME_CHANGE:	Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_ID_ADD:		Notify in struct kdbus_notify_id_change
- * @KDBUS_ITEM_ID_REMOVE:	Notify in struct kdbus_notify_id_change
- * @KDBUS_ITEM_REPLY_TIMEOUT:	Timeout has been reached
- * @KDBUS_ITEM_REPLY_DEAD:	Destination died
- */
-enum kdbus_item_type {
-	_KDBUS_ITEM_NULL,
-	_KDBUS_ITEM_USER_BASE,
-	KDBUS_ITEM_PAYLOAD_VEC	= _KDBUS_ITEM_USER_BASE,
-	KDBUS_ITEM_PAYLOAD_OFF,
-	KDBUS_ITEM_PAYLOAD_MEMFD,
-	KDBUS_ITEM_FDS,
-	KDBUS_ITEM_BLOOM,
-	KDBUS_ITEM_BLOOM_SIZE,
-	KDBUS_ITEM_DST_NAME,
-	KDBUS_ITEM_MAKE_NAME,
-	KDBUS_ITEM_MEMFD_NAME,
-
-	_KDBUS_ITEM_POLICY_BASE	= 0x1000,
-	KDBUS_ITEM_POLICY_NAME = _KDBUS_ITEM_POLICY_BASE,
-	KDBUS_ITEM_POLICY_ACCESS,
-
-	_KDBUS_ITEM_ATTACH_BASE	= 0x2000,
-	KDBUS_ITEM_NAME		= _KDBUS_ITEM_ATTACH_BASE,
-	KDBUS_ITEM_ID,
-	KDBUS_ITEM_TIMESTAMP,
-	KDBUS_ITEM_CREDS,
-	KDBUS_ITEM_PID_COMM,
-	KDBUS_ITEM_TID_COMM,
-	KDBUS_ITEM_EXE,
-	KDBUS_ITEM_CMDLINE,
-	KDBUS_ITEM_CGROUP,
-	KDBUS_ITEM_CAPS,
-	KDBUS_ITEM_SECLABEL,
-	KDBUS_ITEM_AUDIT,
-	KDBUS_ITEM_CONN_NAME,
-
-	_KDBUS_ITEM_KERNEL_BASE	= 0x3000,
-	KDBUS_ITEM_NAME_ADD	= _KDBUS_ITEM_KERNEL_BASE,
-	KDBUS_ITEM_NAME_REMOVE,
-	KDBUS_ITEM_NAME_CHANGE,
-	KDBUS_ITEM_ID_ADD,
-	KDBUS_ITEM_ID_REMOVE,
-	KDBUS_ITEM_REPLY_TIMEOUT,
-	KDBUS_ITEM_REPLY_DEAD,
-};
-
-/**
- * struct kdbus_item - chain of data blocks
- * @size:		Overall data record size
- * @type:		Kdbus_item type of data
- * @data:		Generic bytes
- * @data32:		Generic 32 bit array
- * @data64:		Generic 64 bit array
- * @str:		Generic string
- * @id:			Connection ID
- * @vec:		KDBUS_ITEM_PAYLOAD_VEC
- * @creds:		KDBUS_ITEM_CREDS
- * @audit:		KDBUS_ITEM_AUDIT
- * @timestamp:		KDBUS_ITEM_TIMESTAMP
- * @name:		KDBUS_ITEM_NAME
- * @memfd:		KDBUS_ITEM_PAYLOAD_MEMFD
- * @name_change:	KDBUS_ITEM_NAME_ADD
- *			KDBUS_ITEM_NAME_REMOVE
- *			KDBUS_ITEM_NAME_CHANGE
- * @id_change:		KDBUS_ITEM_ID_ADD
- *			KDBUS_ITEM_ID_REMOVE
- * @policy:		KDBUS_ITEM_POLICY_NAME
- *			KDBUS_ITEM_POLICY_ACCESS
- */
-struct kdbus_item {
-	__u64 size;
-	__u64 type;
-	union {
-		__u8 data[0];
-		__u32 data32[0];
-		__u64 data64[0];
-		char str[0];
-
-		__u64 id;
-		struct kdbus_vec vec;
-		struct kdbus_creds creds;
-		struct kdbus_audit audit;
-		struct kdbus_timestamp timestamp;
-		struct kdbus_name name;
-		struct kdbus_memfd memfd;
-		int fds[0];
-		struct kdbus_notify_name_change name_change;
-		struct kdbus_notify_id_change id_change;
-		struct kdbus_policy policy;
-	};
-};
-
-/**
- * enum kdbus_msg_flags - type of message
- * @KDBUS_MSG_FLAGS_EXPECT_REPLY:	Expect a reply message, used for
- *					method calls. The userspace-supplied
- *					cookie identifies the message and the
- *					respective reply carries the cookie
- *					in cookie_reply
- * @KDBUS_MSG_FLAGS_SYNC_REPLY:		Wait for destination connection to
- * 					reply to this message. The
- * 					KDBUS_CMD_MSG_SEND ioctl() will block
- * 					until the reply is received, and
- * 					offset_reply in struct kdbus_msg will
- * 					yield the offset in the sender's pool
- * 					where the reply can be found.
- * 					This flag is only valid if
- * 					@KDBUS_MSG_FLAGS_EXPECT_REPLY is set as
- * 					well.
- * @KDBUS_MSG_FLAGS_NO_AUTO_START:	Do not start a service, if the addressed
- *					name is not currently active
- */
-enum kdbus_msg_flags {
-	KDBUS_MSG_FLAGS_EXPECT_REPLY	= 1 << 0,
-	KDBUS_MSG_FLAGS_SYNC_REPLY	= 1 << 1,
-	KDBUS_MSG_FLAGS_NO_AUTO_START	= 1 << 2,
-};
-
-/**
- * enum kdbus_payload_type - type of payload carried by message
- * @KDBUS_PAYLOAD_KERNEL:	Kernel-generated simple message
- * @KDBUS_PAYLOAD_DBUS:		D-Bus marshalling "DBusDBus"
- */
-enum kdbus_payload_type {
-	KDBUS_PAYLOAD_KERNEL,
-	KDBUS_PAYLOAD_DBUS	= 0x4442757344427573ULL,
-};
-
-/**
- * struct kdbus_msg - the representation of a kdbus message
- * @size:		Total size of the message
- * @flags:		Message flags (KDBUS_MSG_FLAGS_*)
- * @priority:		Message queue priority value
- * @dst_id:		64-bit ID of the destination connection
- * @src_id:		64-bit ID of the source connection
- * @payload_type:	Payload type (KDBUS_PAYLOAD_*)
- * @cookie:		Userspace-supplied cookie, for the connection
- *			to identify its messages
- * @timeout_ns:		The time to wait for a message reply from the peer.
- *			If there is no reply, a kernel-generated message
- *			with an attached KDBUS_ITEM_REPLY_TIMEOUT item
- *			is sent to @src_id.
- * @cookie_reply:	A reply to the requesting message with the same
- *			cookie. The requesting connection can match its
- *			request and the reply with this value
- * @offset_reply:	If KDBUS_MSG_FLAGS_WAIT_FOR_REPLY, this field will
- *			contain the offset in the sender's pool where the
- *			reply is stored.
- * @items:		A list of kdbus_items containing the message payload
- */
-struct kdbus_msg {
-	__u64 size;
-	__u64 flags;
-	__s64 priority;
-	__u64 dst_id;
-	__u64 src_id;
-	__u64 payload_type;
-	__u64 cookie;
-	union {
-		__u64 timeout_ns;
-		__u64 cookie_reply;
-		__u64 offset_reply;
-	};
-	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_recv_flags - flags for de-queuing messages
- * @KDBUS_RECV_PEEK:		Return the next queued message without
- *				actually de-queuing it, and without installing
- *				any file descriptors or other resources. It is
- *				usually used to determine the activating
- *				connection of a bus name.
- * @KDBUS_RECV_DROP:		Drop and free the next queued message and all
- *				its resources without actually receiving it.
- * @KDBUS_RECV_USE_PRIORITY:	Only de-queue messages with the specified or
- * 				higher priority (lowest values); if not set,
- * 				the priority value is ignored.
- */
-enum kdbus_recv_flags {
-	KDBUS_RECV_PEEK		= 1 <<  0,
-	KDBUS_RECV_DROP		= 1 <<  1,
-	KDBUS_RECV_USE_PRIORITY	= 1 <<  2,
-};
-
-/**
- * struct kdbus_cmd_recv - struct to de-queue a buffered message
- * @flags:		KDBUS_RECV_* flags
- * @priority:		Minimum priority of the messages to de-queue. Lowest
- *			values have the highest priority.
- * @offset:		Returned offset in the pool where the message is
- * 			stored. The user must use KDBUS_CMD_FREE to free
- * 			the allocated memory.
- *
- * This struct is used with the KDBUS_CMD_MSG_RECV ioctl.
- */
-struct kdbus_cmd_recv {
-	__u64 flags;
-	__s64 priority;
-	__u64 offset;
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_policy_access_type - permissions of a policy record
- * @_KDBUS_POLICY_ACCESS_NULL:	Uninitialized/invalid
- * @KDBUS_POLICY_ACCESS_USER:	Grant access to a uid
- * @KDBUS_POLICY_ACCESS_GROUP:	Grant access to gid
- * @KDBUS_POLICY_ACCESS_WORLD:	World-accessible
- */
-enum kdbus_policy_access_type {
-	_KDBUS_POLICY_ACCESS_NULL,
-	KDBUS_POLICY_ACCESS_USER,
-	KDBUS_POLICY_ACCESS_GROUP,
-	KDBUS_POLICY_ACCESS_WORLD,
-};
-
-/**
- * enum kdbus_policy_access_flags - mode flags
- * @KDBUS_POLICY_RECV:		Allow receive
- * @KDBUS_POLICY_SEND:		Allow send
- * @KDBUS_POLICY_OWN:		Allow to own a well-known name
- */
-enum kdbus_policy_type {
-	KDBUS_POLICY_RECV		= 1 <<  2,
-	KDBUS_POLICY_SEND		= 1 <<  1,
-	KDBUS_POLICY_OWN		= 1 <<  0,
-};
-
-/**
- * struct kdbus_cmd_policy - a series of policies to upload
- * @size:		The total size of the structure
- * @policies:		The policies to upload
- *
- * A KDBUS_POLICY_NAME must always preceeds a KDBUS_POLICY_ACCESS entry.
- * A new KDBUS_POLICY_NAME can be added after KDBUS_POLICY_ACCESS for
- * chaining multiple policies together.
- */
-struct kdbus_cmd_policy {
-	__u64 size;
-	struct kdbus_item policies[0];
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello
- * @KDBUS_HELLO_ACCEPT_FD:	The connection allows the receiving of
- *				any passed file descriptors
- * @KDBUS_HELLO_ACTIVATOR:	Special-purpose connection which registers
- *				a well-know name for a process to be started
- *				when traffic arrives
- * @KDBUS_HELLO_MONITOR:	Special-purpose connection to monitor
- *				bus traffic
- */
-enum kdbus_hello_flags {
-	KDBUS_HELLO_ACCEPT_FD		=  1 <<  0,
-	KDBUS_HELLO_ACTIVATOR		=  1 <<  1,
-	KDBUS_HELLO_MONITOR		=  1 <<  2,
-};
-
-/**
- * enum kdbus_attach_flags - flags for metadata attachments
- * @KDBUS_ATTACH_TIMESTAMP:	Timestamp
- * @KDBUS_ATTACH_CREDS:		Credentials
- * @KDBUS_ATTACH_NAMES:		Well-known names
- * @KDBUS_ATTACH_COMM:		The "comm" process identifier
- * @KDBUS_ATTACH_EXE:		The path of the executable
- * @KDBUS_ATTACH_CMDLINE:	The process command line
- * @KDBUS_ATTACH_CGROUP:	The croup membership
- * @KDBUS_ATTACH_CAPS:		The process capabilities
- * @KDBUS_ATTACH_SECLABEL:	The security label
- * @KDBUS_ATTACH_AUDIT:		The audit IDs
- * @KDBUS_ATTACH_CONN_NAME:	The human-readable connection name
- */
-enum kdbus_attach_flags {
-	KDBUS_ATTACH_TIMESTAMP		=  1 <<  0,
-	KDBUS_ATTACH_CREDS		=  1 <<  1,
-	KDBUS_ATTACH_NAMES		=  1 <<  2,
-	KDBUS_ATTACH_COMM		=  1 <<  3,
-	KDBUS_ATTACH_EXE		=  1 <<  4,
-	KDBUS_ATTACH_CMDLINE		=  1 <<  5,
-	KDBUS_ATTACH_CGROUP		=  1 <<  6,
-	KDBUS_ATTACH_CAPS		=  1 <<  7,
-	KDBUS_ATTACH_SECLABEL		=  1 <<  8,
-	KDBUS_ATTACH_AUDIT		=  1 <<  9,
-	KDBUS_ATTACH_CONN_NAME		=  1 << 10,
-};
-
-/**
- * struct kdbus_cmd_hello - struct to say hello to kdbus
- * @size:		The total size of the structure
- * @conn_flags:		Connection flags (KDBUS_HELLO_*). The kernel will
- *			return its capabilities in that field.
- * @attach_flags:	Mask of metadata to attach to each message sent
- *			(KDBUS_ATTACH_*)
- * @bus_flags:		The flags field copied verbatim from the original
- *			KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful
- *			to do negotiation of features of the payload that is
- *			transferred (kernel → userspace)
- * @id:			The ID of this connection (kernel → userspace)
- * @bloom_size:		The bloom filter size chosen by the owner
- *			(kernel → userspace)
- * @pool_size:		Size of the connection's buffer where the received
- *			messages are placed
- * @id128:		Unique 128-bit ID of the bus (kernel → userspace)
- * @items:		A list of items
- *
- * This struct is used with the KDBUS_CMD_HELLO ioctl.
- */
-struct kdbus_cmd_hello {
-	__u64 size;
-	__u64 conn_flags;
-	__u64 attach_flags;
-	__u64 bus_flags;
-	__u64 id;
-	__u64 bloom_size;
-	__u64 pool_size;
-	__u8 id128[16];
-	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
-
-/* Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE */
-enum kdbus_make_flags {
-	KDBUS_MAKE_ACCESS_GROUP		= 1 <<  0,
-	KDBUS_MAKE_ACCESS_WORLD		= 1 <<  1,
-	KDBUS_MAKE_POLICY_OPEN		= 1 <<  2,
-};
-
-/**
- * struct kdbus_cmd_make - struct to make a bus, an endpoint or a namespace
- * @size:		The total size of the struct
- * @flags:		Properties for the bus/ep/ns to create
- * @items:		Items describing details
- *
- * This structure is used with the KDBUS_CMD_BUS_MAKE, KDBUS_CMD_EP_MAKE and
- * KDBUS_CMD_NS_MAKE ioctls.
- */
-struct kdbus_cmd_make {
-	__u64 size;
-	__u64 flags;
-	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_name_flags - properties of a well-known name
- * @KDBUS_NAME_REPLACE_EXISTING:	Try to replace name of other connections
- * @KDBUS_NAME_ALLOW_REPLACEMENT:	Allow the replacement of the name
- * @KDBUS_NAME_QUEUE:			Name should be queued if busy
- * @KDBUS_NAME_IN_QUEUE:		Name is queued
- * @KDBUS_NAME_ACTIVATOR:		Name is owned by a activator connection
- */
-enum kdbus_name_flags {
-	KDBUS_NAME_REPLACE_EXISTING	= 1 <<  0,
-	KDBUS_NAME_ALLOW_REPLACEMENT	= 1 <<  1,
-	KDBUS_NAME_QUEUE		= 1 <<  2,
-	KDBUS_NAME_IN_QUEUE		= 1 <<  3,
-	KDBUS_NAME_ACTIVATOR		= 1 <<  4,
-};
-
-/**
- * struct kdbus_cmd_name - struct to describe a well-known name
- * @size:		The total size of the struct
- * @flags:		Flags for a name entry (KDBUS_NAME_*)
- * @owner_id:		The current owner of the name. For requests,
- *			privileged users may set this field to
- *			(de)register names on behalf of other connections.
- * @conn_flags:		The flags of the owning connection (KDBUS_HELLO_*)
- * @name:		The well-known name
- *
- * This structure is used with the KDBUS_CMD_NAME_ACQUIRE ioctl.
- */
-struct kdbus_cmd_name {
-	__u64 size;
-	__u64 flags;
-	__u64 owner_id;
-	__u64 conn_flags;
-	char name[0];
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_name_list_flags - what to include into the returned list
- * @KDBUS_NAME_LIST_UNIQUE:	All active connections
- * @KDBUS_NAME_LIST_NAMES:	All known well-known names
- * @KDBUS_NAME_LIST_ACTIVATORS:	All activator connections
- * @KDBUS_NAME_LIST_QUEUED:	All queued-up names
- */
-enum kdbus_name_list_flags {
-	KDBUS_NAME_LIST_UNIQUE		= 1 <<  0,
-	KDBUS_NAME_LIST_NAMES		= 1 <<  1,
-	KDBUS_NAME_LIST_ACTIVATORS	= 1 <<  2,
-	KDBUS_NAME_LIST_QUEUED		= 1 <<  3,
-};
-
-/**
- * struct kdbus_cmd_name_list - request a list of name entries
- * @flags:		Flags for the query (KDBUS_NAME_LIST_*)
- * @offset:		The returned offset in the caller's pool buffer.
- *			The user must use KDBUS_CMD_FREE to free the
- *			allocated memory.
- *
- * This structure is used with the KDBUS_CMD_NAME_LIST ioctl.
- */
-struct kdbus_cmd_name_list {
-	__u64 flags;
-	__u64 offset;
-} __attribute__((aligned(8)));
-
-/**
- * struct kdbus_name_list - information returned by KDBUS_CMD_NAME_LIST
- * @size:		The total size of the structure
- * @names:		A list of names
- *
- * Note that the user is responsible for freeing the allocated memory with
- * the KDBUS_CMD_FREE ioctl.
- */
-struct kdbus_name_list {
-	__u64 size;
-	struct kdbus_cmd_name names[0];
-};
-
-/**
- * struct kdbus_cmd_conn_info - struct used for KDBUS_CMD_CONN_INFO ioctl
- * @size:		The total size of the struct
- * @flags:		KDBUS_ATTACH_* flags
- * @id:			The 64-bit ID of the connection. If set to zero, passing
- *			@name is required. kdbus will look up the name to
- *			determine the ID in this case.
- * @offset:		Returned offset in the caller's pool buffer where the
- *			kdbus_conn_info struct result is stored. The user must
- *			use KDBUS_CMD_FREE to free the allocated memory.
- * @name:		The optional well-known name to look up. Only needed in
- *			case @id is zero.
- *
- * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will
- * tell the user the offset in the connection pool buffer at which to find the
- * result in a struct kdbus_conn_info.
- */
-struct kdbus_cmd_conn_info {
-	__u64 size;
-	__u64 flags;
-	__u64 id;
-	__u64 offset;
-	char name[0];
-} __attribute__((aligned(8)));
-
-/**
- * struct kdbus_conn_info - information returned by KDBUS_CMD_CONN_INFO
- * @size:		The total size of the struct
- * @id:			The connection's 64-bit ID
- * @flags:		The connection's flags
- * @items:		A list of struct kdbus_item
- *
- * Note that the user is responsible for freeing the allocated memory with
- * the KDBUS_CMD_FREE ioctl.
- */
-struct kdbus_conn_info {
-	__u64 size;
-	__u64 id;
-	__u64 flags;
-	struct kdbus_item items[0];
-};
-
-/**
- * struct kdbus_cmd_match - struct to add or remove matches
- * @size:		The total size of the struct
- * @owner_id:		Privileged users may (de)register matches on behalf
- *			of other peers
- * @cookie:		Userspace supplied cookie. When removing, the cookie
- *			identifies the match to remove
- * @items:		A list of items for additional information
- *
- * This structure is used with the KDBUS_CMD_ADD_MATCH and
- * KDBUS_CMD_REMOVE_MATCH ioctl.
- */
-struct kdbus_cmd_match {
-	__u64 size;
-	__u64 owner_id;
-	__u64 cookie;
-	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
-
-/**
- * struct kdbus_cmd_memfd_make - create a kdbus memfd
- * @size:		The total size of the struct
- * @file_size:		The initial file size
- * @fd:			The returned file descriptor number
- * @__pad:		Padding to ensure proper alignement
- * @items:		A list of items for additional information
- *
- * This structure is used with the KDBUS_CMD_MEMFD_NEW ioctl.
- */
-struct kdbus_cmd_memfd_make {
-	__u64 size;
-	__u64 file_size;
-	int fd;
-	__u32 __pad;
-	struct kdbus_item items[0];
-} __attribute__((aligned(8)));
-
-/**
- * enum kdbus_ioctl_type - Ioctl API
- * @KDBUS_CMD_BUS_MAKE:		After opening the "control" device node, this
- *				command creates a new bus with the specified
- *				name. The bus is immediately shut down and
- *				cleaned up when the opened "control" device node
- *				is closed.
- * @KDBUS_CMD_NS_MAKE:		Similar to KDBUS_CMD_BUS_MAKE, but it creates a
- *				new kdbus namespace.
- * @KDBUS_CMD_EP_MAKE:		Creates a new named special endpoint to talk to
- *				the bus. Such endpoints usually carry a more
- *				restrictive policy and grant restricted access
- *				to specific applications.
- * @KDBUS_CMD_HELLO:		By opening the bus device node a connection is
- *				created. After a HELLO the opened connection
- *				becomes an active peer on the bus.
- * @KDBUS_CMD_BYEBYE:		Disconnect a connection. If the connection's
- *				message list is empty, the calls succeeds, and
- *				the handle is rendered unusable. Otherwise,
- *				-EAGAIN is returned without any further side-
- *				effects.
- * @KDBUS_CMD_MSG_SEND:		Send a message and pass data from userspace to
- *				the kernel.
- * @KDBUS_CMD_MSG_RECV:		Receive a message from the kernel which is
- *				placed in the receiver's pool.
- * @KDBUS_CMD_FREE:		Release the allocated memory in the receiver's
- *				pool.
- * @KDBUS_CMD_NAME_ACQUIRE:	Request a well-known bus name to associate with
- *				the connection. Well-known names are used to
- *				address a peer on the bus.
- * @KDBUS_CMD_NAME_RELEASE:	Release a well-known name the connection
- *				currently owns.
- * @KDBUS_CMD_NAME_LIST:	Retrieve the list of all currently registered
- *				well-known and unique names.
- * @KDBUS_CMD_CONN_INFO:	Retrieve credentials and properties of the
- *				initial creator of the connection. The data was
- *				stored at registration time and does not
- *				necessarily represent the connected process or
- *				the actual state of the process.
- * @KDBUS_CMD_MATCH_ADD:	Install a match which broadcast messages should
- *				be delivered to the connection.
- * @KDBUS_CMD_MATCH_REMOVE:	Remove a current match for broadcast messages.
- * @KDBUS_CMD_EP_POLICY_SET:	Set the policy of an endpoint. It is used to
- *				restrict the access for endpoints created with
- *				KDBUS_CMD_EP_MAKE.
- * @KDBUS_CMD_MEMFD_NEW:	Return a new file descriptor which provides an
- *				anonymous shared memory file and which can be
- *				used to pass around larger chunks of data.
- *				Kdbus memfd files can be sealed, which allows
- *				the receiver to trust the data it has received.
- *				Kdbus memfd files expose only very limited
- *				operations, they can be mmap()ed, seek()ed,
- *				(p)read(v)() and (p)write(v)(); most other
- *				common file operations are not implemented.
- *				Special caution needs to be taken with
- *				read(v)()/write(v)() on a shared file; the
- *				underlying file position is always shared
- *				between all users of the file and race against
- *				each other, pread(v)()/pwrite(v)() avoid these
- *				issues.
- * @KDBUS_CMD_MEMFD_SIZE_GET:	Return the size of the underlying file, which
- *				changes with write().
- * @KDBUS_CMD_MEMFD_SIZE_SET:	Truncate the underlying file to the specified
- *				size.
- * @KDBUS_CMD_MEMFD_SEAL_GET:	Return the state of the file sealing.
- * @KDBUS_CMD_MEMFD_SEAL_SET:	Seal or break a seal of the file. Only files
- *				which are not shared with other processes and
- *				which are currently not mapped can be sealed.
- *				The current process needs to be the one and
- *				single owner of the file, the sealing cannot
- *				be changed as long as the file is shared.
- */
-enum kdbus_ioctl_type {
-	KDBUS_CMD_BUS_MAKE =		_IOW (KDBUS_IOC_MAGIC, 0x00, struct kdbus_cmd_make),
-	KDBUS_CMD_NS_MAKE =		_IOR (KDBUS_IOC_MAGIC, 0x10, struct kdbus_cmd_make),
-	KDBUS_CMD_EP_MAKE =		_IOW (KDBUS_IOC_MAGIC, 0x20, struct kdbus_cmd_make),
-
-	KDBUS_CMD_HELLO =		_IOWR(KDBUS_IOC_MAGIC, 0x30, struct kdbus_cmd_hello),
-	KDBUS_CMD_BYEBYE =		_IO  (KDBUS_IOC_MAGIC, 0x31),
-
-	KDBUS_CMD_MSG_SEND =		_IOW (KDBUS_IOC_MAGIC, 0x40, struct kdbus_msg),
-	KDBUS_CMD_MSG_RECV =		_IOWR(KDBUS_IOC_MAGIC, 0x41, struct kdbus_cmd_recv),
-	KDBUS_CMD_FREE =		_IOW (KDBUS_IOC_MAGIC, 0x42, __u64 *),
-
-	KDBUS_CMD_NAME_ACQUIRE =	_IOWR(KDBUS_IOC_MAGIC, 0x50, struct kdbus_cmd_name),
-	KDBUS_CMD_NAME_RELEASE =	_IOW (KDBUS_IOC_MAGIC, 0x51, struct kdbus_cmd_name),
-	KDBUS_CMD_NAME_LIST =		_IOWR(KDBUS_IOC_MAGIC, 0x52, struct kdbus_cmd_name_list),
-
-	KDBUS_CMD_CONN_INFO =		_IOWR(KDBUS_IOC_MAGIC, 0x60, struct kdbus_cmd_conn_info),
-
-	KDBUS_CMD_MATCH_ADD =		_IOW (KDBUS_IOC_MAGIC, 0x70, struct kdbus_cmd_match),
-	KDBUS_CMD_MATCH_REMOVE =	_IOW (KDBUS_IOC_MAGIC, 0x71, struct kdbus_cmd_match),
-
-	KDBUS_CMD_EP_POLICY_SET =	_IOW (KDBUS_IOC_MAGIC, 0x80, struct kdbus_cmd_policy),
-
-	KDBUS_CMD_MEMFD_NEW =		_IOWR(KDBUS_IOC_MAGIC, 0xc0, struct kdbus_cmd_memfd_make),
-	KDBUS_CMD_MEMFD_SIZE_GET =	_IOR (KDBUS_IOC_MAGIC, 0xc1, __u64 *),
-	KDBUS_CMD_MEMFD_SIZE_SET =	_IOW (KDBUS_IOC_MAGIC, 0xc2, __u64 *),
-	KDBUS_CMD_MEMFD_SEAL_GET =	_IOR (KDBUS_IOC_MAGIC, 0xc3, int *),
-	KDBUS_CMD_MEMFD_SEAL_SET =	_IO  (KDBUS_IOC_MAGIC, 0xc4),
-};
-
-/*
- * errno - api error codes
- * @E2BIG:		A message contains too many records or items.
- * @EADDRINUSE:		A well-known bus name is already taken by another
- *			connection.
- * @EADDRNOTAVAIL:	A message flagged not to activate a service, addressed
- *			a service which is not currently running.
- * @EAGAIN:		No messages are queued at the moment.
- * @EBADF:		File descriptors passed with the message are not valid.
- * @EBADFD:		A bus connection is in a corrupted state.
- * @EBADMSG:		Passed data contains a combination of conflicting or
- *			inconsistent types.
- * @EBUSY:		The user tried to say BYEBYE to a connection, but the
- *			connection had a non-empty message list.
- * @ECONNRESET:		A connection is shut down, no further operations are
- *			possible.
- * @ECOMM:		A peer does not accept the file descriptors addressed
- *			to it.
- * @EDESTADDRREQ:	The well-known bus name is required but missing.
- * @EDOM:		The size of data does not match the expectations. Used
- *			for the size of the bloom filter bit field.
- * @EEXIST:		A requested namespace, bus or endpoint with the same
- *			name already exists.  A specific data type, which is
- *			only expected once, is provided multiple times.
- * @EFAULT:		The supplied memory could not be accessed, or the data
- *			is not properly aligned.
- * @EINVAL:		The provided data does not match its type or other
- *			expectations, like a string which is not NUL terminated,
- *			or a string length that points behind the first
- *			\0-byte in the string.
- * @EMEDIUMTYPE:	A file descriptor which is not a kdbus memfd was
- *			refused to send as KDBUS_MSG_PAYLOAD_MEMFD.
- * @EMFILE:		Too many file descriptors have been supplied with a
- *			message.
- * @EMLINK:		Too many requests from this connection to other peers
- *			are queued and waiting for a reply
- * @EMSGSIZE:		The supplied data is larger than the allowed maximum
- *			size.
- * @ENAMETOOLONG:	The requested name is larger than the allowed maximum
- *			size.
- * @ENOBUFS:		There is no space left for the submitted data to fit
- *			into the receiver's pool.
- * @ENOENT:		The name to query information about is currently not on
- *			the bus.
- * @ENOMEM:		Out of memory.
- * @ENOMSG:		The queue is not empty, but no message with a matching
- * 			priority is currently queued.
- * @ENOSYS:		The requested functionality is not available.
- * @ENOTSUPP:		The feature negotiation failed, a not supported feature
- *			was requested, or an unknown item type was received.
- * @ENOTTY:		An unknown ioctl command was received.
- * @ENOTUNIQ:		A specific data type was addressed to a broadcast
- *			address, but only direct addresses support this kind of
- *			data.
- * @ENXIO:		A unique address does not exist, or an offset in the
- *			receiver's pool does not represent a queued message.
- * @EPERM:		The policy prevented an operation. The requested
- *			resource is owned by another entity.
- * @ESHUTDOWN:		A namespace or endpoint is currently shutting down;
- *			no further operations will be possible.
- * @ESRCH:		A requested well-known bus name is not found.
- * @ETXTBSY:		A kdbus memfd file cannot be sealed or the seal removed,
- *			because it is shared with other processes or still
- *			mmap()ed.
- * @EXFULL:		The size limits in the pool are reached, no data of
- *			the size tried to submit can be queued.
- */
-#endif
diff --git a/src/libsystemd/resolve-util.h b/src/libsystemd/resolve-util.h
deleted file mode 100644
index 58df738..0000000
--- a/src/libsystemd/resolve-util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Daniel Buch
-
-  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_resolve*, sd_resolve_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo*, sd_resolve_freeaddrinfo);
-#define _cleanup_resolve_free_ _cleanup_(sd_resolve_freep)
-#define _cleanup_resolve_addrinfo_free_ _cleanup_(sd_resolve_freeaddrinfop)
diff --git a/src/libsystemd/rtnl-internal.h b/src/libsystemd/rtnl-internal.h
deleted file mode 100644
index 2e0b7b8..0000000
--- a/src/libsystemd/rtnl-internal.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  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 <linux/netlink.h>
-
-#include "refcnt.h"
-#include "prioq.h"
-#include "list.h"
-
-#include "sd-rtnl.h"
-
-struct reply_callback {
-        sd_rtnl_message_handler_t callback;
-        void *userdata;
-        usec_t timeout;
-        uint64_t serial;
-        unsigned prioq_idx;
-};
-
-struct match_callback {
-        sd_rtnl_message_handler_t callback;
-        uint16_t type;
-        void *userdata;
-
-        LIST_FIELDS(struct match_callback, match_callbacks);
-};
-
-struct sd_rtnl {
-        RefCount n_ref;
-
-        int fd;
-
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sockaddr;
-
-        sd_rtnl_message **rqueue;
-        unsigned rqueue_size;
-
-        sd_rtnl_message **wqueue;
-        unsigned wqueue_size;
-
-        bool processing:1;
-
-        uint32_t serial;
-
-        struct Prioq *reply_callbacks_prioq;
-        Hashmap *reply_callbacks;
-
-        LIST_HEAD(struct match_callback, match_callbacks);
-
-        pid_t original_pid;
-
-        sd_event_source *io_event_source;
-        sd_event_source *time_event_source;
-        sd_event_source *exit_event_source;
-        sd_event *event;
-};
-
-#define RTNL_DEFAULT_TIMEOUT ((usec_t) (10 * USEC_PER_SEC))
-
-#define RTNL_WQUEUE_MAX 1024
-#define RTNL_RQUEUE_MAX 64*1024
-
-int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret);
-uint32_t message_get_serial(sd_rtnl_message *m);
-int message_seal(sd_rtnl *nl, sd_rtnl_message *m);
-
-bool message_type_is_link(uint16_t type);
-bool message_type_is_addr(uint16_t type);
-bool message_type_is_route(uint16_t type);
-
-int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m);
-int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret);
-
-/* Make sure callbacks don't destroy the rtnl connection */
-#define RTNL_DONT_DESTROY(rtnl) \
-        _cleanup_sd_rtnl_unref_ _unused_ sd_rtnl *_dont_destroy_##rtnl = sd_rtnl_ref(rtnl)
diff --git a/src/libsystemd/rtnl-message.c b/src/libsystemd/rtnl-message.c
deleted file mode 100644
index 984115c..0000000
--- a/src/libsystemd/rtnl-message.c
+++ /dev/null
@@ -1,887 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  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 <linux/rtnetlink.h>
-#include <netinet/in.h>
-#include <netinet/ether.h>
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "util.h"
-#include "refcnt.h"
-
-#include "sd-rtnl.h"
-#include "rtnl-internal.h"
-
-struct sd_rtnl_message {
-        RefCount n_ref;
-
-        struct nlmsghdr *hdr;
-        size_t container_offset; /* offset from hdr to container start */
-        size_t next_rta_offset; /* offset from hdr to next rta */
-
-        bool sealed:1;
-};
-
-#define CURRENT_CONTAINER(m) ((m)->container_offset ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offset) : NULL)
-#define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
-#define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
-
-static int message_new(sd_rtnl_message **ret, size_t initial_size) {
-        sd_rtnl_message *m;
-
-        assert_return(ret, -EINVAL);
-        assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
-
-        m = new0(sd_rtnl_message, 1);
-        if (!m)
-                return -ENOMEM;
-
-        m->hdr = malloc0(initial_size);
-        if (!m->hdr) {
-                free(m);
-                return -ENOMEM;
-        }
-
-        m->n_ref = REFCNT_INIT;
-
-        m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-        m->sealed = false;
-
-        *ret = m;
-
-        return 0;
-}
-
-int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
-        struct nlmsgerr *err;
-        int r;
-
-        assert(error <= 0);
-
-        r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
-        (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
-        (*ret)->hdr->nlmsg_seq = serial;
-
-        err = NLMSG_DATA((*ret)->hdr);
-
-        err->error = error;
-
-        return 0;
-}
-
-bool message_type_is_route(uint16_t type) {
-        switch (type) {
-                case RTM_NEWROUTE:
-                case RTM_GETROUTE:
-                case RTM_DELROUTE:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-bool message_type_is_link(uint16_t type) {
-        switch (type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
-                case RTM_DELLINK:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-bool message_type_is_addr(uint16_t type) {
-        switch (type) {
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        return true;
-                default:
-                        return false;
-        }
-}
-
-int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
-        struct rtmsg *rtm;
-
-        rtm = NLMSG_DATA(m->hdr);
-
-        rtm->rtm_dst_len = prefixlen;
-
-        return 0;
-}
-
-int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
-                              sd_rtnl_message **ret) {
-        struct rtmsg *rtm;
-        int r;
-
-        assert_return(message_type_is_route(nlmsg_type), -EINVAL);
-        assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-        (*ret)->hdr->nlmsg_type = nlmsg_type;
-        if (nlmsg_type == RTM_NEWROUTE)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-
-        rtm = NLMSG_DATA((*ret)->hdr);
-
-        UPDATE_RTA(*ret, RTM_RTA(rtm));
-
-        rtm->rtm_family = rtm_family;
-        rtm->rtm_scope = RT_SCOPE_UNIVERSE;
-        rtm->rtm_type = RTN_UNICAST;
-        rtm->rtm_table = RT_TABLE_MAIN;
-        rtm->rtm_protocol = RTPROT_BOOT;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags) {
-        struct ifinfomsg *ifi;
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_flags = flags;
-        ifi->ifi_change = 0xffffffff;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
-        struct ifinfomsg *ifi;
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        ifi->ifi_type = type;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
-        struct ifinfomsg *ifi;
-        int r;
-
-        assert_return(message_type_is_link(nlmsg_type), -EINVAL);
-        assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-        (*ret)->hdr->nlmsg_type = nlmsg_type;
-        if (nlmsg_type == RTM_NEWLINK)
-                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
-
-        ifi = NLMSG_DATA((*ret)->hdr);
-
-        ifi->ifi_family = AF_UNSPEC;
-        ifi->ifi_index = index;
-
-        UPDATE_RTA(*ret, IFLA_RTA(ifi));
-
-        return 0;
-}
-
-int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
-        struct ifaddrmsg *ifa;
-        int r;
-
-        assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
-        assert_return(index > 0, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
-        if (r < 0)
-                return r;
-
-        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-        (*ret)->hdr->nlmsg_type = nlmsg_type;
-
-        ifa = NLMSG_DATA((*ret)->hdr);
-
-        ifa->ifa_family = family;
-        ifa->ifa_prefixlen = prefixlen;
-        ifa->ifa_flags = flags;
-        ifa->ifa_scope = scope;
-        ifa->ifa_index = index;
-
-        UPDATE_RTA(*ret, IFA_RTA(ifa));
-
-        return 0;
-}
-
-sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
-        if (m)
-                assert_se(REFCNT_INC(m->n_ref) >= 2);
-
-        return m;
-}
-
-sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
-        if (m && REFCNT_DEC(m->n_ref) <= 0) {
-                free(m->hdr);
-                free(m);
-        }
-
-        return NULL;
-}
-
-int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
-        assert_return(m, -EINVAL);
-        assert_return(type, -EINVAL);
-
-        *type = m->hdr->nlmsg_type;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(ifindex, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *ifindex = ifi->ifi_index;
-
-        return 0;
-}
-
-int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
-        struct ifinfomsg *ifi;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-        assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-        assert_return(flags, -EINVAL);
-
-        ifi = NLMSG_DATA(m->hdr);
-
-        *flags = ifi->ifi_flags;
-
-        return 0;
-}
-
-/* If successful the updated message will be correctly aligned, if
-   unsuccessful the old message is untouched. */
-static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
-        uint32_t rta_length, message_length;
-        struct nlmsghdr *new_hdr;
-        struct rtattr *rta;
-        char *padding;
-
-        assert(m);
-        assert(m->hdr);
-        assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
-        assert(!data || data_length > 0);
-
-        /* get the size of the new rta attribute (with padding at the end) */
-        rta_length = RTA_LENGTH(data_length);
-
-        /* get the new message size (with padding at the end) */
-        message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
-
-        /* realloc to fit the new attribute */
-        new_hdr = realloc(m->hdr, message_length);
-        if (!new_hdr)
-                return -ENOMEM;
-        m->hdr = new_hdr;
-
-        /* get pointer to the attribute we are about to add */
-        rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
-
-        /* if we are inside a container, extend it */
-        if (CURRENT_CONTAINER(m))
-                CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
-
-        /* fill in the attribute */
-        rta->rta_type = type;
-        rta->rta_len = rta_length;
-        if (!data) {
-                /* this is the start of a new container */
-                m->container_offset = m->hdr->nlmsg_len;
-        } else {
-                /* we don't deal with the case where the user lies about the type
-                 * and gives us too little data (so don't do that)
-                */
-                padding = mempcpy(RTA_DATA(rta), data, data_length);
-                /* make sure also the padding at the end of the message is initialized */
-                memzero(padding,
-                        (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
-        }
-
-        /* update message size */
-        m->hdr->nlmsg_len = message_length;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
-        uint16_t rtm_type;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(data, -EINVAL);
-
-        r = sd_rtnl_message_get_type(m, &rtm_type);
-        if (r < 0)
-                return r;
-
-        /* check that the type is correct */
-        switch (rtm_type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
-                case RTM_DELLINK:
-                        if (CURRENT_CONTAINER(m)) {
-                                if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
-                                    type != IFLA_INFO_KIND)
-                                        return -ENOTSUP;
-                        } else {
-                                switch (type) {
-                                        case IFLA_IFNAME:
-                                        case IFLA_IFALIAS:
-                                        case IFLA_QDISC:
-                                                break;
-                                        default:
-                                                return -ENOTSUP;
-                                }
-                        }
-                        break;
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        if (type != IFA_LABEL)
-                                return -ENOTSUP;
-                        break;
-                default:
-                        return -ENOTSUP;
-        }
-
-        r = add_rtattr(m, type, data, strlen(data) + 1);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
-        uint16_t rtm_type;
-        int r;
-
-        assert_return(m, -EINVAL);
-
-        r = sd_rtnl_message_get_type(m, &rtm_type);
-        if (r < 0)
-                return r;
-
-        /* check that the type is correct */
-        switch (rtm_type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
-                case RTM_DELLINK:
-                        switch (type) {
-                                case IFLA_MASTER:
-                                case IFLA_MTU:
-                                case IFLA_LINK:
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                        break;
-                case RTM_NEWROUTE:
-                case RTM_GETROUTE:
-                case RTM_DELROUTE:
-                        switch (type) {
-                                case RTA_TABLE:
-                                case RTA_PRIORITY:
-                                case RTA_IIF:
-                                case RTA_OIF:
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                        break;
-                default:
-                        return -ENOTSUP;
-        }
-
-        r = add_rtattr(m, type, &data, sizeof(uint32_t));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
-        struct ifaddrmsg *ifa;
-        struct rtmsg *rtm;
-        uint16_t rtm_type;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(data, -EINVAL);
-
-        r = sd_rtnl_message_get_type(m, &rtm_type);
-        if (r < 0)
-                return r;
-
-        /* check that the type is correct */
-        switch (rtm_type) {
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        switch (type) {
-                                case IFA_ADDRESS:
-                                case IFA_LOCAL:
-                                case IFA_BROADCAST:
-                                case IFA_ANYCAST:
-                                        ifa = NLMSG_DATA(m->hdr);
-
-                                        if (ifa->ifa_family != AF_INET)
-                                                return -EINVAL;
-
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                        break;
-                case RTM_NEWROUTE:
-                case RTM_GETROUTE:
-                case RTM_DELROUTE:
-                        switch (type) {
-                                case RTA_DST:
-                                case RTA_SRC:
-                                case RTA_GATEWAY:
-                                        rtm = NLMSG_DATA(m->hdr);
-
-                                        if (rtm->rtm_family != AF_INET)
-                                                return -EINVAL;
-
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                        break;
-                default:
-                        return -ENOTSUP;
-        }
-
-        r = add_rtattr(m, type, data, sizeof(struct in_addr));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
-        struct ifaddrmsg *ifa;
-        struct rtmsg *rtm;
-        uint16_t rtm_type;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(data, -EINVAL);
-
-        r = sd_rtnl_message_get_type(m, &rtm_type);
-        if (r < 0)
-                return r;
-
-        /* check that the type is correct */
-        switch (rtm_type) {
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        switch (type) {
-                                case IFA_ADDRESS:
-                                case IFA_LOCAL:
-                                case IFA_BROADCAST:
-                                case IFA_ANYCAST:
-                                        ifa = NLMSG_DATA(m->hdr);
-
-                                        if (ifa->ifa_family != AF_INET6)
-                                                return -EINVAL;
-
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                        break;
-                case RTM_NEWROUTE:
-                case RTM_GETROUTE:
-                case RTM_DELROUTE:
-                        switch (type) {
-                                case RTA_DST:
-                                case RTA_SRC:
-                                case RTA_GATEWAY:
-                                        rtm = NLMSG_DATA(m->hdr);
-
-                                        if (rtm->rtm_family != AF_INET6)
-                                                return -EINVAL;
-
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                default:
-                        return -ENOTSUP;
-        }
-
-        r = add_rtattr(m, type, data, sizeof(struct in6_addr));
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
-        uint16_t rtm_type;
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(data, -EINVAL);
-
-        sd_rtnl_message_get_type(m, &rtm_type);
-
-        switch (rtm_type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_DELLINK:
-                case RTM_GETLINK:
-                        switch (type) {
-                                case IFLA_ADDRESS:
-                                case IFLA_BROADCAST:
-                                        break;
-                                default:
-                                        return -ENOTSUP;
-                        }
-                        break;
-                default:
-                        return -ENOTSUP;
-        }
-
-        r = add_rtattr(m, type, data, ETH_ALEN);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
-        uint16_t rtm_type;
-
-        assert_return(m, -EINVAL);
-        assert_return(!CURRENT_CONTAINER(m), -EINVAL);
-
-        sd_rtnl_message_get_type(m, &rtm_type);
-
-        if (message_type_is_link(rtm_type)) {
-                if (type == IFLA_LINKINFO)
-                        return add_rtattr(m, type, NULL, 0);
-                else
-                        return -ENOTSUP;
-        } else
-                return -ENOTSUP;
-
-        return 0;
-}
-
-int sd_rtnl_message_close_container(sd_rtnl_message *m) {
-        assert_return(m, -EINVAL);
-        assert_return(CURRENT_CONTAINER(m), -EINVAL);
-
-        m->container_offset = 0;
-
-        return 0;
-}
-
-int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
-        size_t remaining_size;
-        uint16_t rtm_type;
-        int r;
-
-        assert(m);
-        assert(m->next_rta_offset);
-        assert(type);
-        assert(data);
-
-        remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
-
-        if (!RTA_OK(NEXT_RTA(m), remaining_size))
-                return 0;
-
-        /* make sure we don't try to read a container
-         * TODO: add support for entering containers for reading */
-        r = sd_rtnl_message_get_type(m, &rtm_type);
-        if (r < 0)
-                return r;
-
-        if (message_type_is_link(rtm_type) &&
-            NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
-               return -EINVAL;
-
-        *data = RTA_DATA(NEXT_RTA(m));
-        *type = NEXT_RTA(m)->rta_type;
-
-        UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
-
-        return 1;
-}
-
-uint32_t message_get_serial(sd_rtnl_message *m) {
-        assert(m);
-        assert(m->hdr);
-
-        return m->hdr->nlmsg_seq;
-}
-
-int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
-        struct nlmsgerr *err;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-
-        if (m->hdr->nlmsg_type != NLMSG_ERROR)
-                return 0;
-
-        err = NLMSG_DATA(m->hdr);
-
-        return err->error;
-}
-
-int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
-        assert(nl);
-        assert(m);
-        assert(m->hdr);
-
-        if (m->sealed)
-                return -EPERM;
-
-        m->hdr->nlmsg_seq = nl->serial++;
-        m->sealed = true;
-
-        return 0;
-}
-
-static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
-        assert(rtnl);
-        assert(need);
-
-        /* ioctl(rtnl->fd, FIONREAD, &need)
-           Does not appear to work on netlink sockets. libnl uses
-           MSG_PEEK instead. I don't know if that is worth the
-           extra roundtrip.
-
-           For now we simply use the maximum message size the kernel
-           may use (NLMSG_GOODSIZE), and then realloc to the actual
-           size after reading the message (hence avoiding huge memory
-           usage in case many small messages are kept around) */
-        *need = page_size();
-        if (*need > 8192UL)
-                *need = 8192UL;
-
-        return 0;
-}
-
-/* returns the number of bytes sent, or a negative error code */
-int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } addr = {
-                .nl.nl_family = AF_NETLINK,
-        };
-        ssize_t k;
-
-        assert(nl);
-        assert(m);
-        assert(m->hdr);
-
-        k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
-                        0, &addr.sa, sizeof(addr));
-        if (k < 0)
-                return (errno == EAGAIN) ? 0 : -errno;
-
-        return k;
-}
-
-/* On success, the number of bytes received is returned and *ret points to the received message
- * which has a valid header and the correct size.
- * If nothing useful was received 0 is returned.
- * On failure, a negative error code is returned.
- */
-int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
-        sd_rtnl_message *m;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } addr;
-        socklen_t addr_len;
-        int r;
-        ssize_t k;
-        size_t need;
-
-        assert(nl);
-        assert(ret);
-
-        r = message_receive_need(nl, &need);
-        if (r < 0)
-                return r;
-
-        r = message_new(&m, need);
-        if (r < 0)
-                return r;
-
-        addr_len = sizeof(addr);
-
-        k = recvfrom(nl->fd, m->hdr, need,
-                        0, &addr.sa, &addr_len);
-        if (k < 0)
-                k = (errno == EAGAIN) ? 0 : -errno; /* no data */
-        else if (k == 0)
-                k = -ECONNRESET; /* connection was closed by the kernel */
-        else if (addr_len != sizeof(addr.nl) ||
-                        addr.nl.nl_family != AF_NETLINK)
-                k = -EIO; /* not a netlink message */
-        else if (addr.nl.nl_pid != 0)
-                k = 0; /* not from the kernel */
-        else if ((size_t) k < sizeof(struct nlmsghdr) ||
-                        (size_t) k < m->hdr->nlmsg_len)
-                k = -EIO; /* too small (we do accept too big though) */
-        else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
-                k = 0; /* not broadcast and not for us */
-
-        if (k > 0)
-                switch (m->hdr->nlmsg_type) {
-                        struct ifinfomsg *ifi;
-                        struct ifaddrmsg *ifa;
-                        struct rtmsg *rtm;
-
-                        /* check that the size matches the message type */
-                        case NLMSG_ERROR:
-                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
-                                        k = -EIO;
-                                break;
-                        case RTM_NEWLINK:
-                        case RTM_SETLINK:
-                        case RTM_DELLINK:
-                        case RTM_GETLINK:
-                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
-                                        k = -EIO;
-                                else {
-                                        ifi = NLMSG_DATA(m->hdr);
-                                        UPDATE_RTA(m, IFLA_RTA(ifi));
-                                }
-                                break;
-                        case RTM_NEWADDR:
-                        case RTM_DELADDR:
-                        case RTM_GETADDR:
-                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
-                                        k = -EIO;
-                                else {
-                                        ifa = NLMSG_DATA(m->hdr);
-                                        UPDATE_RTA(m, IFA_RTA(ifa));
-                                }
-                                break;
-                        case RTM_NEWROUTE:
-                        case RTM_DELROUTE:
-                        case RTM_GETROUTE:
-                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
-                                        k = -EIO;
-                                else {
-                                        rtm = NLMSG_DATA(m->hdr);
-                                        UPDATE_RTA(m, RTM_RTA(rtm));
-                                }
-                                break;
-                        case NLMSG_NOOP:
-                                k = 0;
-                                break;
-                        default:
-                                k = 0; /* ignoring message of unknown type */
-                }
-
-        if (k <= 0)
-                sd_rtnl_message_unref(m);
-        else {
-                /* we probably allocated way too much memory, give it back */
-                m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
-                *ret = m;
-        }
-
-        return k;
-}
-
-int sd_rtnl_message_rewind(sd_rtnl_message *m) {
-        struct ifinfomsg *ifi;
-        struct ifaddrmsg *ifa;
-        struct rtmsg *rtm;
-
-        assert_return(m, -EINVAL);
-        assert_return(m->hdr, -EINVAL);
-
-        switch(m->hdr->nlmsg_type) {
-                case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
-                case RTM_DELLINK:
-                        ifi = NLMSG_DATA(m->hdr);
-                        UPDATE_RTA(m, IFLA_RTA(ifi));
-
-                        break;
-                case RTM_NEWADDR:
-                case RTM_GETADDR:
-                case RTM_DELADDR:
-                        ifa = NLMSG_DATA(m->hdr);
-                        UPDATE_RTA(m, IFA_RTA(ifa));
-
-                        break;
-                case RTM_NEWROUTE:
-                case RTM_GETROUTE:
-                case RTM_DELROUTE:
-                        rtm = NLMSG_DATA(m->hdr);
-                        UPDATE_RTA(m, RTM_RTA(rtm));
-
-                        break;
-                default:
-                        return -ENOTSUP;
-        }
-
-        return 0;
-}
diff --git a/src/libsystemd/rtnl-util.c b/src/libsystemd/rtnl-util.c
deleted file mode 100644
index dfc0050..0000000
--- a/src/libsystemd/rtnl-util.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
-
-  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 <linux/rtnetlink.h>
-#include <netinet/ether.h>
-
-#include "sd-rtnl.h"
-
-#include "rtnl-util.h"
-
-int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message = NULL;
-        int r;
-
-        assert(rtnl);
-        assert(ifindex > 0);
-        assert(name);
-
-        r = sd_rtnl_message_link_new(RTM_SETLINK, ifindex, &message);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_message_append_string(message, IFLA_IFNAME, name);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_call(rtnl, message, 0, NULL);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias,
-                             const struct ether_addr *mac, unsigned mtu) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message = NULL;
-        bool need_update = false;
-        int r;
-
-        assert(rtnl);
-        assert(ifindex > 0);
-
-        if (!alias && !mac && mtu == 0)
-                return 0;
-
-        r = sd_rtnl_message_link_new(RTM_SETLINK, ifindex, &message);
-        if (r < 0)
-                return r;
-
-        if (alias) {
-                r = sd_rtnl_message_append_string(message, IFLA_IFALIAS, alias);
-                if (r < 0)
-                        return r;
-
-                need_update = true;
-
-        }
-
-        if (mac) {
-                r = sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, mac);
-                if (r < 0)
-                        return r;
-
-                need_update = true;
-        }
-
-        if (mtu > 0) {
-                r = sd_rtnl_message_append_u32(message, IFLA_MTU, mtu);
-                if (r < 0)
-                        return r;
-
-                need_update = true;
-        }
-
-        if  (need_update) {
-                r = sd_rtnl_call(rtnl, message, 0, NULL);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
diff --git a/src/libsystemd/rtnl-util.h b/src/libsystemd/rtnl-util.h
deleted file mode 100644
index 013002d..0000000
--- a/src/libsystemd/rtnl-util.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
-
-  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 <netinet/ether.h>
-
-#include "util.h"
-#include "sd-rtnl.h"
-
-int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name);
-int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl*, sd_rtnl_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl_message*, sd_rtnl_message_unref);
-
-#define _cleanup_sd_rtnl_unref_ _cleanup_(sd_rtnl_unrefp)
-#define _cleanup_sd_rtnl_message_unref_ _cleanup_(sd_rtnl_message_unrefp)
diff --git a/src/libsystemd/sd-bus.c b/src/libsystemd/sd-bus.c
deleted file mode 100644
index 95d80db..0000000
--- a/src/libsystemd/sd-bus.c
+++ /dev/null
@@ -1,3032 +0,0 @@
-/*-*- 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 <endian.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <sys/poll.h>
-#include <byteswap.h>
-#include <sys/mman.h>
-#include <pthread.h>
-
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-#include "set.h"
-#include "missing.h"
-#include "def.h"
-
-#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-type.h"
-#include "bus-socket.h"
-#include "bus-kernel.h"
-#include "bus-control.h"
-#include "bus-introspect.h"
-#include "bus-signature.h"
-#include "bus-objects.h"
-#include "bus-util.h"
-#include "bus-container.h"
-#include "bus-protocol.h"
-
-static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
-static int attach_io_events(sd_bus *b);
-static void detach_io_events(sd_bus *b);
-
-static void bus_close_fds(sd_bus *b) {
-        assert(b);
-
-        detach_io_events(b);
-
-        if (b->input_fd >= 0)
-                close_nointr_nofail(b->input_fd);
-
-        if (b->output_fd >= 0 && b->output_fd != b->input_fd)
-                close_nointr_nofail(b->output_fd);
-
-        b->input_fd = b->output_fd = -1;
-}
-
-static void bus_node_destroy(sd_bus *b, struct node *n) {
-        struct node_callback *c;
-        struct node_vtable *v;
-        struct node_enumerator *e;
-
-        assert(b);
-
-        if (!n)
-                return;
-
-        while (n->child)
-                bus_node_destroy(b, n->child);
-
-        while ((c = n->callbacks)) {
-                LIST_REMOVE(callbacks, n->callbacks, c);
-                free(c);
-        }
-
-        while ((v = n->vtables)) {
-                LIST_REMOVE(vtables, n->vtables, v);
-                free(v->interface);
-                free(v);
-        }
-
-        while ((e = n->enumerators)) {
-                LIST_REMOVE(enumerators, n->enumerators, e);
-                free(e);
-        }
-
-        if (n->parent)
-                LIST_REMOVE(siblings, n->parent->child, n);
-
-        assert_se(hashmap_remove(b->nodes, n->path) == n);
-        free(n->path);
-        free(n);
-}
-
-static void bus_reset_queues(sd_bus *b) {
-        unsigned i;
-
-        assert(b);
-
-        for (i = 0; i < b->rqueue_size; i++)
-                sd_bus_message_unref(b->rqueue[i]);
-        free(b->rqueue);
-
-        for (i = 0; i < b->wqueue_size; i++)
-                sd_bus_message_unref(b->wqueue[i]);
-        free(b->wqueue);
-
-        b->rqueue = b->wqueue = NULL;
-        b->rqueue_allocated = b->wqueue_allocated = 0;
-        b->rqueue_size = b->wqueue_size = 0;
-}
-
-static void bus_free(sd_bus *b) {
-        struct filter_callback *f;
-        struct node *n;
-
-        assert(b);
-
-        sd_bus_detach_event(b);
-
-        bus_close_fds(b);
-
-        if (b->kdbus_buffer)
-                munmap(b->kdbus_buffer, KDBUS_POOL_SIZE);
-
-        free(b->rbuffer);
-        free(b->unique_name);
-        free(b->auth_buffer);
-        free(b->address);
-        free(b->kernel);
-        free(b->machine);
-        free(b->fake_label);
-        free(b->cgroup_root);
-
-        free(b->exec_path);
-        strv_free(b->exec_argv);
-
-        close_many(b->fds, b->n_fds);
-        free(b->fds);
-
-        bus_reset_queues(b);
-
-        hashmap_free_free(b->reply_callbacks);
-        prioq_free(b->reply_callbacks_prioq);
-
-        while ((f = b->filter_callbacks)) {
-                LIST_REMOVE(callbacks, b->filter_callbacks, f);
-                free(f);
-        }
-
-        bus_match_free(&b->match_callbacks);
-
-        hashmap_free_free(b->vtable_methods);
-        hashmap_free_free(b->vtable_properties);
-
-        while ((n = hashmap_first(b->nodes)))
-                bus_node_destroy(b, n);
-
-        hashmap_free(b->nodes);
-
-        bus_kernel_flush_memfd(b);
-
-        assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0);
-
-        free(b);
-}
-
-_public_ int sd_bus_new(sd_bus **ret) {
-        sd_bus *r;
-
-        assert_return(ret, -EINVAL);
-
-        r = new0(sd_bus, 1);
-        if (!r)
-                return -ENOMEM;
-
-        r->n_ref = REFCNT_INIT;
-        r->input_fd = r->output_fd = -1;
-        r->message_version = 1;
-        r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
-        r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
-        r->attach_flags |= KDBUS_ATTACH_NAMES;
-        r->original_pid = getpid();
-
-        assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0);
-
-        /* We guarantee that wqueue always has space for at least one
-         * entry */
-        if (!GREEDY_REALLOC(r->wqueue, r->wqueue_allocated, 1)) {
-                free(r);
-                return -ENOMEM;
-        }
-
-        *ret = r;
-        return 0;
-}
-
-_public_ int sd_bus_set_address(sd_bus *bus, const char *address) {
-        char *a;
-
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(address, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        a = strdup(address);
-        if (!a)
-                return -ENOMEM;
-
-        free(bus->address);
-        bus->address = a;
-
-        return 0;
-}
-
-_public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(input_fd >= 0, -EINVAL);
-        assert_return(output_fd >= 0, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        bus->input_fd = input_fd;
-        bus->output_fd = output_fd;
-        return 0;
-}
-
-_public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
-        char *p, **a;
-
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(path, -EINVAL);
-        assert_return(!strv_isempty(argv), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        p = strdup(path);
-        if (!p)
-                return -ENOMEM;
-
-        a = strv_copy(argv);
-        if (!a) {
-                free(p);
-                return -ENOMEM;
-        }
-
-        free(bus->exec_path);
-        strv_free(bus->exec_argv);
-
-        bus->exec_path = p;
-        bus->exec_argv = a;
-
-        return 0;
-}
-
-_public_ int sd_bus_set_bus_client(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        bus->bus_client = !!b;
-        return 0;
-}
-
-_public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b);
-        return 0;
-}
-
-_public_ int sd_bus_negotiate_attach_timestamp(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        SET_FLAG(bus->attach_flags, KDBUS_ATTACH_TIMESTAMP, b);
-        return 0;
-}
-
-_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t mask) {
-        assert_return(bus, -EINVAL);
-        assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        /* The well knowns we need unconditionally, so that matches can work */
-        bus->creds_mask = mask | SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
-
-        return kdbus_translate_attach_flags(bus->creds_mask, &bus->creds_mask);
-}
-
-_public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
-        assert_return(bus, -EINVAL);
-        assert_return(b || sd_id128_equal(server_id, SD_ID128_NULL), -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        bus->is_server = !!b;
-        bus->server_id = server_id;
-        return 0;
-}
-
-_public_ int sd_bus_set_anonymous(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        bus->anonymous_auth = !!b;
-        return 0;
-}
-
-_public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        bus->trusted = !!b;
-        return 0;
-}
-
-static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
-        const char *s;
-        int r;
-
-        assert(bus);
-        assert(bus->state == BUS_HELLO || bus->state == BUS_CLOSING);
-        assert(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)
-                return r;
-
-        if (!service_name_is_valid(s) || s[0] != ':')
-                return -EBADMSG;
-
-        bus->unique_name = strdup(s);
-        if (!bus->unique_name)
-                return -ENOMEM;
-
-        if (bus->state == BUS_HELLO)
-                bus->state = BUS_RUNNING;
-
-        return 1;
-}
-
-static int bus_send_hello(sd_bus *bus) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert(bus);
-
-        if (!bus->bus_client || bus->is_kernel)
-                return 0;
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "Hello",
-                        &m);
-        if (r < 0)
-                return r;
-
-        return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_cookie);
-}
-
-int bus_start_running(sd_bus *bus) {
-        assert(bus);
-
-        if (bus->bus_client && !bus->is_kernel) {
-                bus->state = BUS_HELLO;
-                return 1;
-        }
-
-        bus->state = BUS_RUNNING;
-        return 1;
-}
-
-static int parse_address_key(const char **p, const char *key, char **value) {
-        size_t l, n = 0, allocated = 0;
-        const char *a;
-        char *r = NULL;
-
-        assert(p);
-        assert(*p);
-        assert(value);
-
-        if (key) {
-                l = strlen(key);
-                if (strncmp(*p, key, l) != 0)
-                        return 0;
-
-                if ((*p)[l] != '=')
-                        return 0;
-
-                if (*value)
-                        return -EINVAL;
-
-                a = *p + l + 1;
-        } else
-                a = *p;
-
-        while (*a != ';' && *a != ',' && *a != 0) {
-                char c;
-
-                if (*a == '%') {
-                        int x, y;
-
-                        x = unhexchar(a[1]);
-                        if (x < 0) {
-                                free(r);
-                                return x;
-                        }
-
-                        y = unhexchar(a[2]);
-                        if (y < 0) {
-                                free(r);
-                                return y;
-                        }
-
-                        c = (char) ((x << 4) | y);
-                        a += 3;
-                } else {
-                        c = *a;
-                        a++;
-                }
-
-                if (!GREEDY_REALLOC(r, allocated, n + 2))
-                        return -ENOMEM;
-
-                r[n++] = c;
-        }
-
-        if (!r) {
-                r = strdup("");
-                if (!r)
-                        return -ENOMEM;
-        } else
-                r[n] = 0;
-
-        if (*a == ',')
-                a++;
-
-        *p = a;
-
-        free(*value);
-        *value = r;
-
-        return 1;
-}
-
-static void skip_address_key(const char **p) {
-        assert(p);
-        assert(*p);
-
-        *p += strcspn(*p, ",");
-
-        if (**p == ',')
-                (*p) ++;
-}
-
-static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
-        _cleanup_free_ char *path = NULL, *abstract = NULL;
-        size_t l;
-        int r;
-
-        assert(b);
-        assert(p);
-        assert(*p);
-        assert(guid);
-
-        while (**p != 0 && **p != ';') {
-                r = parse_address_key(p, "guid", guid);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "path", &path);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "abstract", &abstract);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                skip_address_key(p);
-        }
-
-        if (!path && !abstract)
-                return -EINVAL;
-
-        if (path && abstract)
-                return -EINVAL;
-
-        if (path) {
-                l = strlen(path);
-                if (l > sizeof(b->sockaddr.un.sun_path))
-                        return -E2BIG;
-
-                b->sockaddr.un.sun_family = AF_UNIX;
-                strncpy(b->sockaddr.un.sun_path, path, sizeof(b->sockaddr.un.sun_path));
-                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l;
-        } else if (abstract) {
-                l = strlen(abstract);
-                if (l > sizeof(b->sockaddr.un.sun_path) - 1)
-                        return -E2BIG;
-
-                b->sockaddr.un.sun_family = AF_UNIX;
-                b->sockaddr.un.sun_path[0] = 0;
-                strncpy(b->sockaddr.un.sun_path+1, abstract, sizeof(b->sockaddr.un.sun_path)-1);
-                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
-        }
-
-        return 0;
-}
-
-static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
-        _cleanup_free_ char *host = NULL, *port = NULL, *family = NULL;
-        int r;
-        struct addrinfo *result, hints = {
-                .ai_socktype = SOCK_STREAM,
-                .ai_flags = AI_ADDRCONFIG,
-        };
-
-        assert(b);
-        assert(p);
-        assert(*p);
-        assert(guid);
-
-        while (**p != 0 && **p != ';') {
-                r = parse_address_key(p, "guid", guid);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "host", &host);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "port", &port);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "family", &family);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                skip_address_key(p);
-        }
-
-        if (!host || !port)
-                return -EINVAL;
-
-        if (family) {
-                if (streq(family, "ipv4"))
-                        hints.ai_family = AF_INET;
-                else if (streq(family, "ipv6"))
-                        hints.ai_family = AF_INET6;
-                else
-                        return -EINVAL;
-        }
-
-        r = getaddrinfo(host, port, &hints, &result);
-        if (r == EAI_SYSTEM)
-                return -errno;
-        else if (r != 0)
-                return -EADDRNOTAVAIL;
-
-        memcpy(&b->sockaddr, result->ai_addr, result->ai_addrlen);
-        b->sockaddr_size = result->ai_addrlen;
-
-        freeaddrinfo(result);
-
-        return 0;
-}
-
-static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
-        char *path = NULL;
-        unsigned n_argv = 0, j;
-        char **argv = NULL;
-        size_t allocated = 0;
-        int r;
-
-        assert(b);
-        assert(p);
-        assert(*p);
-        assert(guid);
-
-        while (**p != 0 && **p != ';') {
-                r = parse_address_key(p, "guid", guid);
-                if (r < 0)
-                        goto fail;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "path", &path);
-                if (r < 0)
-                        goto fail;
-                else if (r > 0)
-                        continue;
-
-                if (startswith(*p, "argv")) {
-                        unsigned ul;
-
-                        errno = 0;
-                        ul = strtoul(*p + 4, (char**) p, 10);
-                        if (errno > 0 || **p != '=' || ul > 256) {
-                                r = -EINVAL;
-                                goto fail;
-                        }
-
-                        (*p) ++;
-
-                        if (ul >= n_argv) {
-                                if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                n_argv = ul + 1;
-                        }
-
-                        r = parse_address_key(p, NULL, argv + ul);
-                        if (r < 0)
-                                goto fail;
-
-                        continue;
-                }
-
-                skip_address_key(p);
-        }
-
-        if (!path) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        /* Make sure there are no holes in the array, with the
-         * exception of argv[0] */
-        for (j = 1; j < n_argv; j++)
-                if (!argv[j]) {
-                        r = -EINVAL;
-                        goto fail;
-                }
-
-        if (argv && argv[0] == NULL) {
-                argv[0] = strdup(path);
-                if (!argv[0]) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        b->exec_path = path;
-        b->exec_argv = argv;
-        return 0;
-
-fail:
-        for (j = 0; j < n_argv; j++)
-                free(argv[j]);
-
-        free(argv);
-        free(path);
-        return r;
-}
-
-static int parse_kernel_address(sd_bus *b, const char **p, char **guid) {
-        _cleanup_free_ char *path = NULL;
-        int r;
-
-        assert(b);
-        assert(p);
-        assert(*p);
-        assert(guid);
-
-        while (**p != 0 && **p != ';') {
-                r = parse_address_key(p, "guid", guid);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "path", &path);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                skip_address_key(p);
-        }
-
-        if (!path)
-                return -EINVAL;
-
-        free(b->kernel);
-        b->kernel = path;
-        path = NULL;
-
-        return 0;
-}
-
-static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) {
-        _cleanup_free_ char *machine = NULL;
-        int r;
-
-        assert(b);
-        assert(p);
-        assert(*p);
-        assert(guid);
-
-        while (**p != 0 && **p != ';') {
-                r = parse_address_key(p, "guid", guid);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "machine", &machine);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                skip_address_key(p);
-        }
-
-        if (!machine)
-                return -EINVAL;
-
-        if (!filename_is_safe(machine))
-                return -EINVAL;
-
-        free(b->machine);
-        b->machine = machine;
-        machine = NULL;
-
-        b->sockaddr.un.sun_family = AF_UNIX;
-        strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
-        b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/var/run/dbus/system_bus_socket") - 1;
-
-        return 0;
-}
-
-static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) {
-        _cleanup_free_ char *machine = NULL;
-        int r;
-
-        assert(b);
-        assert(p);
-        assert(*p);
-        assert(guid);
-
-        while (**p != 0 && **p != ';') {
-                r = parse_address_key(p, "guid", guid);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                r = parse_address_key(p, "machine", &machine);
-                if (r < 0)
-                        return r;
-                else if (r > 0)
-                        continue;
-
-                skip_address_key(p);
-        }
-
-        if (!machine)
-                return -EINVAL;
-
-        if (!filename_is_safe(machine))
-                return -EINVAL;
-
-        free(b->machine);
-        b->machine = machine;
-        machine = NULL;
-
-        free(b->kernel);
-        b->kernel = strdup("/dev/kdbus/0-system/bus");
-        if (!b->kernel)
-                return -ENOMEM;
-
-        return 0;
-}
-
-static void bus_reset_parsed_address(sd_bus *b) {
-        assert(b);
-
-        zero(b->sockaddr);
-        b->sockaddr_size = 0;
-        strv_free(b->exec_argv);
-        free(b->exec_path);
-        b->exec_path = NULL;
-        b->exec_argv = NULL;
-        b->server_id = SD_ID128_NULL;
-        free(b->kernel);
-        b->kernel = NULL;
-        free(b->machine);
-        b->machine = NULL;
-}
-
-static int bus_parse_next_address(sd_bus *b) {
-        _cleanup_free_ char *guid = NULL;
-        const char *a;
-        int r;
-
-        assert(b);
-
-        if (!b->address)
-                return 0;
-        if (b->address[b->address_index] == 0)
-                return 0;
-
-        bus_reset_parsed_address(b);
-
-        a = b->address + b->address_index;
-
-        while (*a != 0) {
-
-                if (*a == ';') {
-                        a++;
-                        continue;
-                }
-
-                if (startswith(a, "unix:")) {
-                        a += 5;
-
-                        r = parse_unix_address(b, &a, &guid);
-                        if (r < 0)
-                                return r;
-                        break;
-
-                } else if (startswith(a, "tcp:")) {
-
-                        a += 4;
-                        r = parse_tcp_address(b, &a, &guid);
-                        if (r < 0)
-                                return r;
-
-                        break;
-
-                } else if (startswith(a, "unixexec:")) {
-
-                        a += 9;
-                        r = parse_exec_address(b, &a, &guid);
-                        if (r < 0)
-                                return r;
-
-                        break;
-
-                } else if (startswith(a, "kernel:")) {
-
-                        a += 7;
-                        r = parse_kernel_address(b, &a, &guid);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                } else if (startswith(a, "x-container-unix:")) {
-
-                        a += 17;
-                        r = parse_container_unix_address(b, &a, &guid);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                } else if (startswith(a, "x-container-kernel:")) {
-
-                        a += 19;
-                        r = parse_container_kernel_address(b, &a, &guid);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                }
-
-                a = strchr(a, ';');
-                if (!a)
-                        return 0;
-        }
-
-        if (guid) {
-                r = sd_id128_from_string(guid, &b->server_id);
-                if (r < 0)
-                        return r;
-        }
-
-        b->address_index = a - b->address;
-        return 1;
-}
-
-static int bus_start_address(sd_bus *b) {
-        int r;
-
-        assert(b);
-
-        for (;;) {
-                bool skipped = false;
-
-                bus_close_fds(b);
-
-                if (b->exec_path)
-                        r = bus_socket_exec(b);
-                else if (b->machine && b->kernel)
-                        r = bus_container_connect_kernel(b);
-                else if (b->machine && b->sockaddr.sa.sa_family != AF_UNSPEC)
-                        r = bus_container_connect_socket(b);
-                else if (b->kernel)
-                        r = bus_kernel_connect(b);
-                else if (b->sockaddr.sa.sa_family != AF_UNSPEC)
-                        r = bus_socket_connect(b);
-                else
-                        skipped = true;
-
-                if (!skipped) {
-                        if (r >= 0) {
-                                r = attach_io_events(b);
-                                if (r >= 0)
-                                        return r;
-                        }
-
-                        b->last_connect_error = -r;
-                }
-
-                r = bus_parse_next_address(b);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED;
-        }
-}
-
-int bus_next_address(sd_bus *b) {
-        assert(b);
-
-        bus_reset_parsed_address(b);
-        return bus_start_address(b);
-}
-
-static int bus_start_fd(sd_bus *b) {
-        struct stat st;
-        int r;
-
-        assert(b);
-        assert(b->input_fd >= 0);
-        assert(b->output_fd >= 0);
-
-        r = fd_nonblock(b->input_fd, true);
-        if (r < 0)
-                return r;
-
-        r = fd_cloexec(b->input_fd, true);
-        if (r < 0)
-                return r;
-
-        if (b->input_fd != b->output_fd) {
-                r = fd_nonblock(b->output_fd, true);
-                if (r < 0)
-                        return r;
-
-                r = fd_cloexec(b->output_fd, true);
-                if (r < 0)
-                        return r;
-        }
-
-        if (fstat(b->input_fd, &st) < 0)
-                return -errno;
-
-        if (S_ISCHR(b->input_fd))
-                return bus_kernel_take_fd(b);
-        else
-                return bus_socket_take_fd(b);
-}
-
-_public_ int sd_bus_start(sd_bus *bus) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state == BUS_UNSET, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        bus->state = BUS_OPENING;
-
-        if (bus->is_server && bus->bus_client)
-                return -EINVAL;
-
-        if (bus->input_fd >= 0)
-                r = bus_start_fd(bus);
-        else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel || bus->machine)
-                r = bus_start_address(bus);
-        else
-                return -EINVAL;
-
-        if (r < 0)
-                return r;
-
-        return bus_send_hello(bus);
-}
-
-_public_ int sd_bus_open_system(sd_bus **ret) {
-        const char *e;
-        sd_bus *b;
-        int r;
-
-        assert_return(ret, -EINVAL);
-
-        r = sd_bus_new(&b);
-        if (r < 0)
-                return r;
-
-        e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
-        if (e)
-                r = sd_bus_set_address(b, e);
-        else
-                r = sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_PATH);
-        if (r < 0)
-                goto fail;
-
-        b->bus_client = true;
-
-        /* Let's do per-method access control on the system bus. We
-         * need the caller's UID and capability set for that. */
-        b->trusted = false;
-        b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
-
-        r = sd_bus_start(b);
-        if (r < 0)
-                goto fail;
-
-        *ret = b;
-        return 0;
-
-fail:
-        bus_free(b);
-        return r;
-}
-
-_public_ int sd_bus_open_user(sd_bus **ret) {
-        const char *e;
-        sd_bus *b;
-        int r;
-
-        assert_return(ret, -EINVAL);
-
-        r = sd_bus_new(&b);
-        if (r < 0)
-                return r;
-
-        e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
-        if (e) {
-                r = sd_bus_set_address(b, e);
-                if (r < 0)
-                        goto fail;
-        } else {
-                e = secure_getenv("XDG_RUNTIME_DIR");
-                if (e) {
-                        _cleanup_free_ char *ee = NULL;
-
-                        ee = bus_address_escape(e);
-                        if (!ee) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-#ifdef ENABLE_KDBUS
-                        asprintf(&b->address, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, (unsigned long) getuid(), ee);
-#else
-                        asprintf(&b->address, UNIX_USER_BUS_FMT, ee);
-#endif
-                } else {
-#ifdef ENABLE_KDBUS
-                        asprintf(&b->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid());
-#else
-                        return -ECONNREFUSED;
-#endif
-                }
-
-                if (!b->address) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        b->bus_client = true;
-
-        /* We don't do any per-method access control on the user
-         * bus. */
-        b->trusted = true;
-
-        r = sd_bus_start(b);
-        if (r < 0)
-                goto fail;
-
-        *ret = b;
-        return 0;
-
-fail:
-        bus_free(b);
-        return r;
-}
-
-_public_ int sd_bus_open_system_remote(const char *host, sd_bus **ret) {
-        _cleanup_free_ char *e = NULL;
-        char *p = NULL;
-        sd_bus *bus;
-        int r;
-
-        assert_return(host, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        e = bus_address_escape(host);
-        if (!e)
-                return -ENOMEM;
-
-        p = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL);
-        if (!p)
-                return -ENOMEM;
-
-        r = sd_bus_new(&bus);
-        if (r < 0) {
-                free(p);
-                return r;
-        }
-
-        bus->address = p;
-        bus->bus_client = true;
-
-        r = sd_bus_start(bus);
-        if (r < 0) {
-                bus_free(bus);
-                return r;
-        }
-
-        *ret = bus;
-        return 0;
-}
-
-_public_ int sd_bus_open_system_container(const char *machine, sd_bus **ret) {
-        _cleanup_free_ char *e = NULL;
-        sd_bus *bus;
-        char *p;
-        int r;
-
-        assert_return(machine, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(filename_is_safe(machine), -EINVAL);
-
-        e = bus_address_escape(machine);
-        if (!e)
-                return -ENOMEM;
-
-#ifdef ENABLE_KDBUS
-        p = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
-#else
-        p = strjoin("x-container-unix:machine=", e, NULL);
-#endif
-        if (!p)
-                return -ENOMEM;
-
-        r = sd_bus_new(&bus);
-        if (r < 0) {
-                free(p);
-                return r;
-        }
-
-        bus->address = p;
-        bus->bus_client = true;
-
-        r = sd_bus_start(bus);
-        if (r < 0) {
-                bus_free(bus);
-                return r;
-        }
-
-        *ret = bus;
-        return 0;
-}
-
-_public_ void sd_bus_close(sd_bus *bus) {
-
-        if (!bus)
-                return;
-        if (bus->state == BUS_CLOSED)
-                return;
-        if (bus_pid_changed(bus))
-                return;
-
-        bus->state = BUS_CLOSED;
-
-        sd_bus_detach_event(bus);
-
-        /* Drop all queued messages so that they drop references to
-         * the bus object and the bus may be freed */
-        bus_reset_queues(bus);
-
-        if (!bus->is_kernel)
-                bus_close_fds(bus);
-
-        /* We'll leave the fd open in case this is a kernel bus, since
-         * there might still be memblocks around that reference this
-         * bus, and they might need to invoke the KDBUS_CMD_FREE
-         * ioctl on the fd when they are freed. */
-}
-
-static void bus_enter_closing(sd_bus *bus) {
-        assert(bus);
-
-        if (bus->state != BUS_OPENING &&
-            bus->state != BUS_AUTHENTICATING &&
-            bus->state != BUS_HELLO &&
-            bus->state != BUS_RUNNING)
-                return;
-
-        bus->state = BUS_CLOSING;
-}
-
-_public_ sd_bus *sd_bus_ref(sd_bus *bus) {
-        assert_return(bus, NULL);
-
-        assert_se(REFCNT_INC(bus->n_ref) >= 2);
-
-        return bus;
-}
-
-_public_ sd_bus *sd_bus_unref(sd_bus *bus) {
-        unsigned i;
-
-        if (!bus)
-                return NULL;
-
-        i = REFCNT_DEC(bus->n_ref);
-        if (i != bus->rqueue_size + bus->wqueue_size)
-                return NULL;
-
-        for (i = 0; i < bus->rqueue_size; i++)
-                if (bus->rqueue[i]->n_ref > 1)
-                        return NULL;
-
-        for (i = 0; i < bus->wqueue_size; i++)
-                if (bus->wqueue[i]->n_ref > 1)
-                        return NULL;
-
-        /* we are the only holders on the messages */
-        bus_free(bus);
-
-        return NULL;
-}
-
-_public_ int sd_bus_is_open(sd_bus *bus) {
-
-        assert_return(bus, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        return BUS_IS_OPEN(bus->state);
-}
-
-_public_ int sd_bus_can_send(sd_bus *bus, char type) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(bus->state != BUS_UNSET, -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (type == SD_BUS_TYPE_UNIX_FD) {
-                if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD))
-                        return 0;
-
-                r = bus_ensure_running(bus);
-                if (r < 0)
-                        return r;
-
-                return bus->can_fds;
-        }
-
-        return bus_type_is_valid(type);
-}
-
-_public_ int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(server_id, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = bus_ensure_running(bus);
-        if (r < 0)
-                return r;
-
-        *server_id = bus->server_id;
-        return 0;
-}
-
-static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
-        assert(b);
-        assert(m);
-
-        if (m->sealed) {
-                /* If we copy the same message to multiple
-                 * destinations, avoid using the same cookie
-                 * numbers. */
-                b->cookie = MAX(b->cookie, BUS_MESSAGE_COOKIE(m));
-                return 0;
-        }
-
-        if (timeout == 0)
-                timeout = BUS_DEFAULT_TIMEOUT;
-
-        return bus_message_seal(m, ++b->cookie, timeout);
-}
-
-static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
-        assert(b);
-
-        /* Do packet version and endianess already match? */
-        if ((b->message_version == 0 || b->message_version == (*m)->header->version) &&
-            (b->message_endian == 0 || b->message_endian == (*m)->header->endian))
-                return 0;
-
-        /* No? Then remarshal! */
-        return bus_message_remarshal(b, m);
-}
-
-int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
-        assert(b);
-        assert(m);
-
-        /* The bus specification says the serial number cannot be 0,
-         * hence let's fill something in for synthetic messages. Since
-         * synthetic messages might have a fake sender and we don't
-         * want to interfere with the real sender's serial numbers we
-         * pick a fixed, artifical one. We use (uint32_t) -1 rather
-         * than (uint64_t) -1 since dbus1 only had 32bit identifiers,
-         * even though kdbus can do 64bit. */
-
-        return bus_message_seal(m, 0xFFFFFFFFULL, 0);
-}
-
-static int bus_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
-        int r;
-
-        assert(bus);
-        assert(m);
-
-        if (bus->is_kernel)
-                r = bus_kernel_write_message(bus, m);
-        else
-                r = bus_socket_write_message(bus, m, idx);
-
-        if (r <= 0)
-                return r;
-
-        if (bus->is_kernel || *idx >= BUS_MESSAGE_SIZE(m))
-                log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s",
-                          bus_message_type_to_string(m->header->type),
-                          strna(sd_bus_message_get_sender(m)),
-                          strna(sd_bus_message_get_destination(m)),
-                          strna(sd_bus_message_get_path(m)),
-                          strna(sd_bus_message_get_interface(m)),
-                          strna(sd_bus_message_get_member(m)),
-                          (unsigned long) BUS_MESSAGE_COOKIE(m),
-                          (unsigned long) m->reply_cookie,
-                          strna(m->error.message));
-
-        return r;
-}
-
-static int dispatch_wqueue(sd_bus *bus) {
-        int r, ret = 0;
-
-        assert(bus);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        while (bus->wqueue_size > 0) {
-
-                r = bus_write_message(bus, bus->wqueue[0], &bus->windex);
-                if (r < 0)
-                        return r;
-                else if (r == 0)
-                        /* Didn't do anything this time */
-                        return ret;
-                else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
-                        /* Fully written. Let's drop the entry from
-                         * the queue.
-                         *
-                         * This isn't particularly optimized, but
-                         * well, this is supposed to be our worst-case
-                         * buffer only, and the socket buffer is
-                         * supposed to be our primary buffer, and if
-                         * it got full, then all bets are off
-                         * anyway. */
-
-                        bus->wqueue_size --;
-                        sd_bus_message_unref(bus->wqueue[0]);
-                        memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
-                        bus->windex = 0;
-
-                        ret = 1;
-                }
-        }
-
-        return ret;
-}
-
-static int bus_read_message(sd_bus *bus) {
-        assert(bus);
-
-        if (bus->is_kernel)
-                return bus_kernel_read_message(bus);
-        else
-                return bus_socket_read_message(bus);
-}
-
-int bus_rqueue_make_room(sd_bus *bus) {
-        assert(bus);
-
-        if (bus->rqueue_size >= BUS_RQUEUE_MAX)
-                return -ENOBUFS;
-
-        if (!GREEDY_REALLOC(bus->rqueue, bus->rqueue_allocated, bus->rqueue_size + 1))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
-        int r, ret = 0;
-
-        assert(bus);
-        assert(m);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        for (;;) {
-                if (bus->rqueue_size > 0) {
-                        /* Dispatch a queued message */
-
-                        *m = bus->rqueue[0];
-                        bus->rqueue_size --;
-                        memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
-                        return 1;
-                }
-
-                /* Try to read a new message */
-                r = bus_read_message(bus);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return ret;
-
-                ret = 1;
-        }
-}
-
-_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(m, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (m->n_fds > 0) {
-                r = sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return -ENOTSUP;
-        }
-
-        /* If the cookie number isn't kept, then we know that no reply
-         * is expected */
-        if (!cookie && !m->sealed)
-                m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
-
-        r = bus_seal_message(bus, m, 0);
-        if (r < 0)
-                return r;
-
-        /* Remarshall if we have to. This will possibly unref the
-         * message and place a replacement in m */
-        r = bus_remarshal_message(bus, &m);
-        if (r < 0)
-                return r;
-
-        /* If this is a reply and no reply was requested, then let's
-         * suppress this, if we can */
-        if (m->dont_send && !cookie)
-                return 1;
-
-        if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
-                size_t idx = 0;
-
-                r = bus_write_message(bus, m, &idx);
-                if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                                bus_enter_closing(bus);
-                                return -ECONNRESET;
-                        }
-
-                        return r;
-                } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m))  {
-                        /* Wasn't fully written. So let's remember how
-                         * much was written. Note that the first entry
-                         * of the wqueue array is always allocated so
-                         * that we always can remember how much was
-                         * written. */
-                        bus->wqueue[0] = sd_bus_message_ref(m);
-                        bus->wqueue_size = 1;
-                        bus->windex = idx;
-                }
-        } else {
-                /* Just append it to the queue. */
-
-                if (bus->wqueue_size >= BUS_WQUEUE_MAX)
-                        return -ENOBUFS;
-
-                if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
-                        return -ENOMEM;
-
-                bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m);
-        }
-
-        if (cookie)
-                *cookie = BUS_MESSAGE_COOKIE(m);
-
-        return 1;
-}
-
-_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(m, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (!streq_ptr(m->destination, destination)) {
-
-                if (!destination)
-                        return -EEXIST;
-
-                r = sd_bus_message_set_destination(m, destination);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_send(bus, m, cookie);
-}
-
-static usec_t calc_elapse(uint64_t usec) {
-        if (usec == (uint64_t) -1)
-                return 0;
-
-        return now(CLOCK_MONOTONIC) + usec;
-}
-
-static int timeout_compare(const void *a, const void *b) {
-        const struct reply_callback *x = a, *y = b;
-
-        if (x->timeout != 0 && y->timeout == 0)
-                return -1;
-
-        if (x->timeout == 0 && y->timeout != 0)
-                return 1;
-
-        if (x->timeout < y->timeout)
-                return -1;
-
-        if (x->timeout > y->timeout)
-                return 1;
-
-        return 0;
-}
-
-_public_ int sd_bus_call_async(
-                sd_bus *bus,
-                sd_bus_message *_m,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t usec,
-                uint64_t *cookie) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
-        struct reply_callback *c;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(m, -EINVAL);
-        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func);
-        if (r < 0)
-                return r;
-
-        r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare);
-        if (r < 0)
-                return r;
-
-        r = bus_seal_message(bus, m, usec);
-        if (r < 0)
-                return r;
-
-        r = bus_remarshal_message(bus, &m);
-        if (r < 0)
-                return r;
-
-        c = new0(struct reply_callback, 1);
-        if (!c)
-                return -ENOMEM;
-
-        c->callback = callback;
-        c->userdata = userdata;
-        c->cookie = BUS_MESSAGE_COOKIE(m);
-        c->timeout = calc_elapse(m->timeout);
-
-        r = hashmap_put(bus->reply_callbacks, &c->cookie, c);
-        if (r < 0) {
-                free(c);
-                return r;
-        }
-
-        if (c->timeout != 0) {
-                r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-                if (r < 0) {
-                        c->timeout = 0;
-                        sd_bus_call_async_cancel(bus, c->cookie);
-                        return r;
-                }
-        }
-
-        r = sd_bus_send(bus, m, cookie);
-        if (r < 0) {
-                sd_bus_call_async_cancel(bus, c->cookie);
-                return r;
-        }
-
-        return r;
-}
-
-_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie) {
-        struct reply_callback *c;
-
-        assert_return(bus, -EINVAL);
-        assert_return(cookie != 0, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        c = hashmap_remove(bus->reply_callbacks, &cookie);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-
-        free(c);
-        return 1;
-}
-
-int bus_ensure_running(sd_bus *bus) {
-        int r;
-
-        assert(bus);
-
-        if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING)
-                return -ENOTCONN;
-        if (bus->state == BUS_RUNNING)
-                return 1;
-
-        for (;;) {
-                r = sd_bus_process(bus, NULL);
-                if (r < 0)
-                        return r;
-                if (bus->state == BUS_RUNNING)
-                        return 1;
-                if (r > 0)
-                        continue;
-
-                r = sd_bus_wait(bus, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-_public_ int sd_bus_call(
-                sd_bus *bus,
-                sd_bus_message *_m,
-                uint64_t usec,
-                sd_bus_error *error,
-                sd_bus_message **reply) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
-        usec_t timeout;
-        uint64_t cookie;
-        unsigned i;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(m, -EINVAL);
-        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
-        assert_return(!bus_error_is_dirty(error), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = bus_ensure_running(bus);
-        if (r < 0)
-                return r;
-
-        i = bus->rqueue_size;
-
-        r = bus_seal_message(bus, m, usec);
-        if (r < 0)
-                return r;
-
-        r = bus_remarshal_message(bus, &m);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_send(bus, m, &cookie);
-        if (r < 0)
-                return r;
-
-        timeout = calc_elapse(m->timeout);
-
-        for (;;) {
-                usec_t left;
-
-                while (i < bus->rqueue_size) {
-                        sd_bus_message *incoming = NULL;
-
-                        incoming = bus->rqueue[i];
-
-                        if (incoming->reply_cookie == cookie) {
-                                /* Found a match! */
-
-                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
-                                bus->rqueue_size--;
-
-                                if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
-
-                                        if (reply)
-                                                *reply = incoming;
-                                        else
-                                                sd_bus_message_unref(incoming);
-
-                                        return 1;
-                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
-                                        r = sd_bus_error_copy(error, &incoming->error);
-                                else
-                                        r = -EIO;
-
-                                sd_bus_message_unref(incoming);
-                                return r;
-
-                        } else if (BUS_MESSAGE_COOKIE(incoming) == cookie &&
-                                   bus->unique_name &&
-                                   incoming->sender &&
-                                   streq(bus->unique_name, incoming->sender)) {
-
-                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
-                                bus->rqueue_size--;
-
-                                /* Our own message? Somebody is trying
-                                 * to send its own client a message,
-                                 * let's not dead-lock, let's fail
-                                 * immediately. */
-
-                                sd_bus_message_unref(incoming);
-                                return -ELOOP;
-                        }
-
-                        /* Try to read more, right-away */
-                        i++;
-                }
-
-                r = bus_read_message(bus);
-                if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                                bus_enter_closing(bus);
-                                return -ECONNRESET;
-                        }
-
-                        return r;
-                }
-                if (r > 0)
-                        continue;
-
-                if (timeout > 0) {
-                        usec_t n;
-
-                        n = now(CLOCK_MONOTONIC);
-                        if (n >= timeout)
-                                return -ETIMEDOUT;
-
-                        left = timeout - n;
-                } else
-                        left = (uint64_t) -1;
-
-                r = bus_poll(bus, true, left);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return -ETIMEDOUT;
-
-                r = dispatch_wqueue(bus);
-                if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                                bus_enter_closing(bus);
-                                return -ECONNRESET;
-                        }
-
-                        return r;
-                }
-        }
-}
-
-_public_ int sd_bus_get_fd(sd_bus *bus) {
-
-        assert_return(bus, -EINVAL);
-        assert_return(bus->input_fd == bus->output_fd, -EPERM);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        return bus->input_fd;
-}
-
-_public_ int sd_bus_get_events(sd_bus *bus) {
-        int flags = 0;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (bus->state == BUS_OPENING)
-                flags |= POLLOUT;
-        else if (bus->state == BUS_AUTHENTICATING) {
-
-                if (bus_socket_auth_needs_write(bus))
-                        flags |= POLLOUT;
-
-                flags |= POLLIN;
-
-        } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) {
-                if (bus->rqueue_size <= 0)
-                        flags |= POLLIN;
-                if (bus->wqueue_size > 0)
-                        flags |= POLLOUT;
-        }
-
-        return flags;
-}
-
-_public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
-        struct reply_callback *c;
-
-        assert_return(bus, -EINVAL);
-        assert_return(timeout_usec, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (bus->state == BUS_CLOSING) {
-                *timeout_usec = 0;
-                return 1;
-        }
-
-        if (bus->state == BUS_AUTHENTICATING) {
-                *timeout_usec = bus->auth_timeout;
-                return 1;
-        }
-
-        if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) {
-                *timeout_usec = (uint64_t) -1;
-                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;
-                return 0;
-        }
-
-        *timeout_usec = c->timeout;
-        return 1;
-}
-
-static int process_timeout(sd_bus *bus) {
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message* m = NULL;
-        struct reply_callback *c;
-        usec_t n;
-        int r;
-
-        assert(bus);
-
-        c = prioq_peek(bus->reply_callbacks_prioq);
-        if (!c)
-                return 0;
-
-        n = now(CLOCK_MONOTONIC);
-        if (c->timeout > n)
-                return 0;
-
-        r = bus_message_new_synthetic_error(
-                        bus,
-                        c->cookie,
-                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out"),
-                        &m);
-        if (r < 0)
-                return r;
-
-        m->sender = "org.freedesktop.DBus";
-
-        r = bus_seal_synthetic_message(bus, m);
-        if (r < 0)
-                return r;
-
-        assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
-        hashmap_remove(bus->reply_callbacks, &c->cookie);
-
-        bus->current = m;
-        bus->iteration_counter ++;
-
-        r = c->callback(bus, m, c->userdata, &error_buffer);
-        r = bus_maybe_reply_error(m, r, &error_buffer);
-        free(c);
-
-        bus->current = NULL;
-
-        return r;
-}
-
-static int process_hello(sd_bus *bus, sd_bus_message *m) {
-        assert(bus);
-        assert(m);
-
-        if (bus->state != BUS_HELLO)
-                return 0;
-
-        /* Let's make sure the first message on the bus is the HELLO
-         * reply. But note that we don't actually parse the message
-         * 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_METHOD_RETURN &&
-            m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
-                return -EIO;
-
-        if (m->reply_cookie != bus->hello_cookie)
-                return -EIO;
-
-        return 0;
-}
-
-static int process_reply(sd_bus *bus, sd_bus_message *m) {
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        struct reply_callback *c;
-        int r;
-
-        assert(bus);
-        assert(m);
-
-        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_cookie);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-
-        r = sd_bus_message_rewind(m, true);
-        if (r < 0)
-                return r;
-
-        r = c->callback(bus, m, c->userdata, &error_buffer);
-        r = bus_maybe_reply_error(m, r, &error_buffer);
-        free(c);
-
-        return r;
-}
-
-static int process_filter(sd_bus *bus, sd_bus_message *m) {
-        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        struct filter_callback *l;
-        int r;
-
-        assert(bus);
-        assert(m);
-
-        do {
-                bus->filter_callbacks_modified = false;
-
-                LIST_FOREACH(callbacks, l, bus->filter_callbacks) {
-
-                        if (bus->filter_callbacks_modified)
-                                break;
-
-                        /* Don't run this more than once per iteration */
-                        if (l->last_iteration == bus->iteration_counter)
-                                continue;
-
-                        l->last_iteration = bus->iteration_counter;
-
-                        r = sd_bus_message_rewind(m, true);
-                        if (r < 0)
-                                return r;
-
-                        r = l->callback(bus, m, l->userdata, &error_buffer);
-                        r = bus_maybe_reply_error(m, r, &error_buffer);
-                        if (r != 0)
-                                return r;
-
-                }
-
-        } while (bus->filter_callbacks_modified);
-
-        return 0;
-}
-
-static int process_match(sd_bus *bus, sd_bus_message *m) {
-        int r;
-
-        assert(bus);
-        assert(m);
-
-        do {
-                bus->match_callbacks_modified = false;
-
-                r = bus_match_run(bus, &bus->match_callbacks, m);
-                if (r != 0)
-                        return r;
-
-        } while (bus->match_callbacks_modified);
-
-        return 0;
-}
-
-static int process_builtin(sd_bus *bus, sd_bus_message *m) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        int r;
-
-        assert(bus);
-        assert(m);
-
-        if (bus->manual_peer_interface)
-                return 0;
-
-        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
-                return 0;
-
-        if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
-                return 0;
-
-        if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
-                return 1;
-
-        if (streq_ptr(m->member, "Ping"))
-                r = sd_bus_message_new_method_return(m, &reply);
-        else if (streq_ptr(m->member, "GetMachineId")) {
-                sd_id128_t id;
-                char sid[33];
-
-                r = sd_id128_get_machine(&id);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_new_method_return(m, &reply);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_message_append(reply, "s", sd_id128_to_string(id, sid));
-        } else {
-                r = sd_bus_message_new_method_errorf(
-                                m, &reply,
-                                SD_BUS_ERROR_UNKNOWN_METHOD,
-                                 "Unknown method '%s' on interface '%s'.", m->member, m->interface);
-        }
-
-        if (r < 0)
-                return r;
-
-        r = sd_bus_send(bus, reply, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int process_message(sd_bus *bus, sd_bus_message *m) {
-        int r;
-
-        assert(bus);
-        assert(m);
-
-        bus->current = m;
-        bus->iteration_counter++;
-
-        log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s",
-                  bus_message_type_to_string(m->header->type),
-                  strna(sd_bus_message_get_sender(m)),
-                  strna(sd_bus_message_get_destination(m)),
-                  strna(sd_bus_message_get_path(m)),
-                  strna(sd_bus_message_get_interface(m)),
-                  strna(sd_bus_message_get_member(m)),
-                  (unsigned long) BUS_MESSAGE_COOKIE(m),
-                  (unsigned long) m->reply_cookie,
-                  strna(m->error.message));
-
-        r = process_hello(bus, m);
-        if (r != 0)
-                goto finish;
-
-        r = process_reply(bus, m);
-        if (r != 0)
-                goto finish;
-
-        r = process_filter(bus, m);
-        if (r != 0)
-                goto finish;
-
-        r = process_match(bus, m);
-        if (r != 0)
-                goto finish;
-
-        r = process_builtin(bus, m);
-        if (r != 0)
-                goto finish;
-
-        r = bus_process_object(bus, m);
-
-finish:
-        bus->current = NULL;
-        return r;
-}
-
-static int process_running(sd_bus *bus, sd_bus_message **ret) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        assert(bus);
-        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
-
-        r = process_timeout(bus);
-        if (r != 0)
-                goto null_message;
-
-        r = dispatch_wqueue(bus);
-        if (r != 0)
-                goto null_message;
-
-        r = dispatch_rqueue(bus, &m);
-        if (r < 0)
-                return r;
-        if (!m)
-                goto null_message;
-
-        r = process_message(bus, m);
-        if (r != 0)
-                goto null_message;
-
-        if (ret) {
-                r = sd_bus_message_rewind(m, true);
-                if (r < 0)
-                        return r;
-
-                *ret = m;
-                m = NULL;
-                return 1;
-        }
-
-        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) {
-
-                log_debug("Unprocessed message call 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 = sd_bus_reply_method_errorf(
-                                m,
-                                SD_BUS_ERROR_UNKNOWN_OBJECT,
-                                "Unknown object '%s'.", m->path);
-                if (r < 0)
-                        return r;
-        }
-
-        return 1;
-
-null_message:
-        if (r >= 0 && ret)
-                *ret = NULL;
-
-        return r;
-}
-
-static int process_closing(sd_bus *bus, sd_bus_message **ret) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        struct reply_callback *c;
-        int r;
-
-        assert(bus);
-        assert(bus->state == BUS_CLOSING);
-
-        c = hashmap_first(bus->reply_callbacks);
-        if (c) {
-                _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-
-                /* First, fail all outstanding method calls */
-                r = bus_message_new_synthetic_error(
-                                bus,
-                                c->cookie,
-                                &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
-                                &m);
-                if (r < 0)
-                        return r;
-
-                r = bus_seal_synthetic_message(bus, m);
-                if (r < 0)
-                        return r;
-
-                if (c->timeout != 0)
-                        prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-
-                hashmap_remove(bus->reply_callbacks, &c->cookie);
-
-                bus->current = m;
-                bus->iteration_counter++;
-
-                r = c->callback(bus, m, c->userdata, &error_buffer);
-                r = bus_maybe_reply_error(m, r, &error_buffer);
-                free(c);
-
-                goto finish;
-        }
-
-        /* Then, synthesize a Disconnected message */
-        r = sd_bus_message_new_signal(
-                        bus,
-                        "/org/freedesktop/DBus/Local",
-                        "org.freedesktop.DBus.Local",
-                        "Disconnected",
-                        &m);
-        if (r < 0)
-                return r;
-
-        m->sender = "org.freedesktop.DBus.Local";
-
-        r = bus_seal_synthetic_message(bus, m);
-        if (r < 0)
-                return r;
-
-        sd_bus_close(bus);
-
-        bus->current = m;
-        bus->iteration_counter++;
-
-        r = process_filter(bus, m);
-        if (r != 0)
-                goto finish;
-
-        r = process_match(bus, m);
-        if (r != 0)
-                goto finish;
-
-        if (ret) {
-                *ret = m;
-                m = NULL;
-        }
-
-        r = 1;
-
-finish:
-        bus->current = NULL;
-        return r;
-}
-
-_public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
-        BUS_DONT_DESTROY(bus);
-        int r;
-
-        /* Returns 0 when we didn't do anything. This should cause the
-         * caller to invoke sd_bus_wait() before returning the next
-         * time. Returns > 0 when we did something, which possibly
-         * means *ret is filled in with an unprocessed message. */
-
-        assert_return(bus, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        /* We don't allow recursively invoking sd_bus_process(). */
-        assert_return(!bus->current, -EBUSY);
-
-        switch (bus->state) {
-
-        case BUS_UNSET:
-                return -ENOTCONN;
-
-        case BUS_CLOSED:
-                return -ECONNRESET;
-
-        case BUS_OPENING:
-                r = bus_socket_process_opening(bus);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                        bus_enter_closing(bus);
-                        r = 1;
-                } else if (r < 0)
-                        return r;
-                if (ret)
-                        *ret = NULL;
-                return r;
-
-        case BUS_AUTHENTICATING:
-                r = bus_socket_process_authenticating(bus);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                        bus_enter_closing(bus);
-                        r = 1;
-                } else if (r < 0)
-                        return r;
-
-                if (ret)
-                        *ret = NULL;
-
-                return r;
-
-        case BUS_RUNNING:
-        case BUS_HELLO:
-                r = process_running(bus, ret);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                        bus_enter_closing(bus);
-                        r = 1;
-
-                        if (ret)
-                                *ret = NULL;
-                }
-
-                return r;
-
-        case BUS_CLOSING:
-                return process_closing(bus, ret);
-        }
-
-        assert_not_reached("Unknown state");
-}
-
-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 m = (usec_t) -1;
-
-        assert(bus);
-
-        if (bus->state == BUS_CLOSING)
-                return 1;
-
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-
-        e = sd_bus_get_events(bus);
-        if (e < 0)
-                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;
-        else {
-                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))
-                m = timeout_usec;
-
-        p[0].fd = bus->input_fd;
-        if (bus->output_fd == bus->input_fd) {
-                p[0].events = e;
-                n = 1;
-        } else {
-                p[0].events = e & POLLIN;
-                p[1].fd = bus->output_fd;
-                p[1].events = e & POLLOUT;
-                n = 2;
-        }
-
-        r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
-        if (r < 0)
-                return -errno;
-
-        return r > 0 ? 1 : 0;
-}
-
-_public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
-
-        assert_return(bus, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (bus->state == BUS_CLOSING)
-                return 0;
-
-        assert_return(BUS_IS_OPEN(bus->state) , -ENOTCONN);
-
-        if (bus->rqueue_size > 0)
-                return 0;
-
-        return bus_poll(bus, false, timeout_usec);
-}
-
-_public_ int sd_bus_flush(sd_bus *bus) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        if (bus->state == BUS_CLOSING)
-                return 0;
-
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-
-        r = bus_ensure_running(bus);
-        if (r < 0)
-                return r;
-
-        if (bus->wqueue_size <= 0)
-                return 0;
-
-        for (;;) {
-                r = dispatch_wqueue(bus);
-                if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
-                                bus_enter_closing(bus);
-                                return -ECONNRESET;
-                        }
-
-                        return r;
-                }
-
-                if (bus->wqueue_size <= 0)
-                        return 0;
-
-                r = bus_poll(bus, false, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-_public_ int sd_bus_add_filter(sd_bus *bus,
-                               sd_bus_message_handler_t callback,
-                               void *userdata) {
-
-        struct filter_callback *f;
-
-        assert_return(bus, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        f = new0(struct filter_callback, 1);
-        if (!f)
-                return -ENOMEM;
-        f->callback = callback;
-        f->userdata = userdata;
-
-        bus->filter_callbacks_modified = true;
-        LIST_PREPEND(callbacks, bus->filter_callbacks, f);
-        return 0;
-}
-
-_public_ int sd_bus_remove_filter(sd_bus *bus,
-                                  sd_bus_message_handler_t callback,
-                                  void *userdata) {
-
-        struct filter_callback *f;
-
-        assert_return(bus, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        LIST_FOREACH(callbacks, f, bus->filter_callbacks) {
-                if (f->callback == callback && f->userdata == userdata) {
-                        bus->filter_callbacks_modified = true;
-                        LIST_REMOVE(callbacks, bus->filter_callbacks, f);
-                        free(f);
-                        return 1;
-                }
-        }
-
-        return 0;
-}
-
-_public_ int sd_bus_add_match(sd_bus *bus,
-                              const char *match,
-                              sd_bus_message_handler_t callback,
-                              void *userdata) {
-
-        struct bus_match_component *components = NULL;
-        unsigned n_components = 0;
-        uint64_t cookie = 0;
-        int r = 0;
-
-        assert_return(bus, -EINVAL);
-        assert_return(match, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = bus_match_parse(match, &components, &n_components);
-        if (r < 0)
-                goto finish;
-
-        if (bus->bus_client) {
-                cookie = ++bus->match_cookie;
-
-                r = bus_add_match_internal(bus, match, components, n_components, cookie);
-                if (r < 0)
-                        goto finish;
-        }
-
-        bus->match_callbacks_modified = true;
-        r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL);
-        if (r < 0) {
-                if (bus->bus_client)
-                        bus_remove_match_internal(bus, match, cookie);
-        }
-
-finish:
-        bus_match_parse_free(components, n_components);
-        return r;
-}
-
-_public_ int sd_bus_remove_match(sd_bus *bus,
-                                 const char *match,
-                                 sd_bus_message_handler_t callback,
-                                 void *userdata) {
-
-        struct bus_match_component *components = NULL;
-        unsigned n_components = 0;
-        int r = 0, q = 0;
-        uint64_t cookie = 0;
-
-        assert_return(bus, -EINVAL);
-        assert_return(match, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        r = bus_match_parse(match, &components, &n_components);
-        if (r < 0)
-                return r;
-
-        bus->match_callbacks_modified = true;
-        r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie);
-
-        if (bus->bus_client)
-                q = bus_remove_match_internal(bus, match, cookie);
-
-        bus_match_parse_free(components, n_components);
-
-        return r < 0 ? r : q;
-}
-
-bool bus_pid_changed(sd_bus *bus) {
-        assert(bus);
-
-        /* We don't support people creating a bus connection and
-         * keeping it around over a fork(). Let's complain. */
-
-        return bus->original_pid != getpid();
-}
-
-static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_bus *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) {
-        sd_bus *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;
-}
-
-static int quit_callback(sd_event_source *event, void *userdata) {
-        sd_bus *bus = userdata;
-
-        assert(event);
-
-        sd_bus_flush(bus);
-
-        return 1;
-}
-
-static int attach_io_events(sd_bus *bus) {
-        int r;
-
-        assert(bus);
-
-        if (bus->input_fd < 0)
-                return 0;
-
-        if (!bus->event)
-                return 0;
-
-        if (!bus->input_io_event_source) {
-                r = sd_event_add_io(bus->event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
-                if (r < 0)
-                        return r;
-
-                r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
-                if (r < 0)
-                        return r;
-
-                r = sd_event_source_set_priority(bus->input_io_event_source, bus->event_priority);
-        } else
-                r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd);
-
-        if (r < 0)
-                return r;
-
-        if (bus->output_fd != bus->input_fd) {
-                assert(bus->output_fd >= 0);
-
-                if (!bus->output_io_event_source) {
-                        r = sd_event_add_io(bus->event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
-                        if (r < 0)
-                                return r;
-
-                        r = sd_event_source_set_priority(bus->output_io_event_source, bus->event_priority);
-                } else
-                        r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static void detach_io_events(sd_bus *bus) {
-        assert(bus);
-
-        if (bus->input_io_event_source) {
-                sd_event_source_set_enabled(bus->input_io_event_source, SD_EVENT_OFF);
-                bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
-        }
-
-        if (bus->output_io_event_source) {
-                sd_event_source_set_enabled(bus->output_io_event_source, SD_EVENT_OFF);
-                bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
-        }
-}
-
-_public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(!bus->event, -EBUSY);
-
-        assert(!bus->input_io_event_source);
-        assert(!bus->output_io_event_source);
-        assert(!bus->time_event_source);
-
-        if (event)
-                bus->event = sd_event_ref(event);
-        else  {
-                r = sd_event_default(&bus->event);
-                if (r < 0)
-                        return r;
-        }
-
-        bus->event_priority = priority;
-
-        r = sd_event_add_monotonic(bus->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;
-
-        r = sd_event_add_exit(bus->event, quit_callback, bus, &bus->quit_event_source);
-        if (r < 0)
-                goto fail;
-
-        r = attach_io_events(bus);
-        if (r < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        sd_bus_detach_event(bus);
-        return r;
-}
-
-_public_ int sd_bus_detach_event(sd_bus *bus) {
-        assert_return(bus, -EINVAL);
-
-        if (!bus->event)
-                return 0;
-
-        detach_io_events(bus);
-
-        if (bus->time_event_source) {
-                sd_event_source_set_enabled(bus->time_event_source, SD_EVENT_OFF);
-                bus->time_event_source = sd_event_source_unref(bus->time_event_source);
-        }
-
-        if (bus->quit_event_source) {
-                sd_event_source_set_enabled(bus->quit_event_source, SD_EVENT_OFF);
-                bus->quit_event_source = sd_event_source_unref(bus->quit_event_source);
-        }
-
-        if (bus->event)
-                bus->event = sd_event_unref(bus->event);
-
-        return 1;
-}
-
-_public_ sd_event* sd_bus_get_event(sd_bus *bus) {
-        assert_return(bus, NULL);
-
-        return bus->event;
-}
-
-_public_ sd_bus_message* sd_bus_get_current(sd_bus *bus) {
-        assert_return(bus, NULL);
-
-        return bus->current;
-}
-
-static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus **ret) {
-        sd_bus *b = NULL;
-        int r;
-
-        assert(bus_open);
-        assert(default_bus);
-
-        if (!ret)
-                return !!*default_bus;
-
-        if (*default_bus) {
-                *ret = sd_bus_ref(*default_bus);
-                return 0;
-        }
-
-        r = bus_open(&b);
-        if (r < 0)
-                return r;
-
-        b->default_bus_ptr = default_bus;
-        b->tid = gettid();
-        *default_bus = b;
-
-        *ret = b;
-        return 1;
-}
-
-_public_ int sd_bus_default_system(sd_bus **ret) {
-        static thread_local sd_bus *default_system_bus = NULL;
-
-        return bus_default(sd_bus_open_system, &default_system_bus, ret);
-}
-
-_public_ int sd_bus_default_user(sd_bus **ret) {
-        static thread_local sd_bus *default_user_bus = NULL;
-
-        return bus_default(sd_bus_open_user, &default_user_bus, ret);
-}
-
-_public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) {
-        assert_return(b, -EINVAL);
-        assert_return(tid, -EINVAL);
-        assert_return(!bus_pid_changed(b), -ECHILD);
-
-        if (b->tid != 0) {
-                *tid = b->tid;
-                return 0;
-        }
-
-        if (b->event)
-                return sd_event_get_tid(b->event, tid);
-
-        return -ENXIO;
-}
-
-_public_ char *sd_bus_label_escape(const char *s) {
-        char *r, *t;
-        const char *f;
-
-        assert_return(s, NULL);
-
-        /* Escapes all chars that D-Bus' object path cannot deal
-         * with. Can be reversed with bus_path_unescape(). We special
-         * case the empty string. */
-
-        if (*s == 0)
-                return strdup("_");
-
-        r = new(char, strlen(s)*3 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; *f; f++) {
-
-                /* Escape everything that is not a-zA-Z0-9. We also
-                 * escape 0-9 if it's the first character */
-
-                if (!(*f >= 'A' && *f <= 'Z') &&
-                    !(*f >= 'a' && *f <= 'z') &&
-                    !(f > s && *f >= '0' && *f <= '9')) {
-                        *(t++) = '_';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-_public_ char *sd_bus_label_unescape(const char *f) {
-        char *r, *t;
-
-        assert_return(f, NULL);
-
-        /* Special case for the empty string */
-        if (streq(f, "_"))
-                return strdup("");
-
-        r = new(char, strlen(f) + 1);
-        if (!r)
-                return NULL;
-
-        for (t = r; *f; f++) {
-
-                if (*f == '_') {
-                        int a, b;
-
-                        if ((a = unhexchar(f[1])) < 0 ||
-                            (b = unhexchar(f[2])) < 0) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '_';
-                        } else {
-                                *(t++) = (char) ((a << 4) | b);
-                                f += 2;
-                        }
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-_public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
-        sd_bus_creds *c;
-        pid_t pid = 0;
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
-        assert_return(ret, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(!bus->is_kernel, -ENOTSUP);
-
-        if (!bus->ucred_valid && !isempty(bus->label))
-                return -ENODATA;
-
-        c = bus_creds_new();
-        if (!c)
-                return -ENOMEM;
-
-        if (bus->ucred_valid) {
-                pid = c->pid = bus->ucred.pid;
-                c->uid = bus->ucred.uid;
-                c->gid = bus->ucred.gid;
-
-                c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
-        }
-
-        if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
-                c->label = strdup(bus->label);
-                if (!c->label) {
-                        sd_bus_creds_unref(c);
-                        return -ENOMEM;
-                }
-
-                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
-        }
-
-        r = bus_creds_add_more(c, mask, pid, 0);
-        if (r < 0)
-                return r;
-
-        *ret = c;
-        return 0;
-}
-
-_public_ int sd_bus_try_close(sd_bus *bus) {
-        int r;
-
-        assert_return(bus, -EINVAL);
-        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-        assert_return(bus->is_kernel, -ENOTSUP);
-
-        if (bus->rqueue_size > 0)
-                return -EBUSY;
-
-        if (bus->wqueue_size > 0)
-                return -EBUSY;
-
-        r = bus_kernel_try_close(bus);
-        if (r < 0)
-                return r;
-
-        sd_bus_close(bus);
-        return 0;
-}
diff --git a/src/libsystemd/sd-bus/.gitignore b/src/libsystemd/sd-bus/.gitignore
new file mode 100644
index 0000000..d32542e
--- /dev/null
+++ b/src/libsystemd/sd-bus/.gitignore
@@ -0,0 +1 @@
+/bus-error-mapping.c
diff --git a/src/libsystemd/sd-bus/DIFFERENCES b/src/libsystemd/sd-bus/DIFFERENCES
new file mode 100644
index 0000000..fd7506b
--- /dev/null
+++ b/src/libsystemd/sd-bus/DIFFERENCES
@@ -0,0 +1,28 @@
+Known differences between dbus1 and kdbus:
+
+- NameAcquired/NameLost is gone entirely on kdbus backends if
+  libsystemd is used. It is still added in by systemd-bus-proxyd
+  for old dbus1 clients, and it is available if libsystemd is used
+  against the classic dbus1 daemon. If you want to write compatible
+  code with libsystem-bus you need to explicitly subscribe to
+  NameOwnerChanged signals and just ignore NameAcquired/NameLost
+
+- Applications have to deal with spurious signals they didn't expect,
+  due to the probabilistic bloom filters. They need to handle this
+  anyway, given that any client can send anything to arbitrary clients
+  anyway, even in dbus1, so not much changes.
+
+- clients of the system bus when kdbus is used must roll their own
+  security. Only legacy dbus1 clients get the old XML policy enforced,
+  which is implemented by systemd-bus-proxyd.
+
+- Serial numbers of synthesized messages are always (uint32_t) -1.
+
+- The org.freedesktop.DBus "driver" service is not special on
+  kdbus. It is a bus activated service like any other with its own
+  unique name.
+
+- NameOwnerChanged is a synthetic message, generated locally and not
+  by the driver.
+
+- There's no standard per-session bus anymore. Only a per-user bus.
diff --git a/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION b/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION
new file mode 100644
index 0000000..5dffc25
--- /dev/null
+++ b/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION
@@ -0,0 +1,63 @@
+How we use GVariant for serializing D-Bus messages
+--------------------------------------------------
+
+We stay as close to the original dbus1 framing as possible. dbus1 has
+the following framing:
+
+    1. A fixed header of "yyyyuu"
+    2. Additional header fields of "a(yv)"
+    3. Padding with NUL bytes to pad up to next 8byte boundary
+    4. The body
+
+Note that the body is not padded at the end, the complete message
+hence might have a non-aligned size. Reading multiple messages at once
+will hence result in possibly unaligned messages in memory.
+
+The header consists of the following:
+
+    y  Endianness, 'l' or 'B'
+    y  Message Type
+    y  Flags
+    y  Protocol version, '1'
+    u  Length of the body, i.e. the length of part 4 above
+    u  Serial number
+
+    = 12 bytes
+
+When using GVariant we keep the basic structure in place, only
+slightly extend the header, and define protocol version '2'. The new
+header:
+
+    y  Endianness, 'l' or 'B'
+    y  Message Type
+    y  Flags
+    y  Protocol version, '2'
+    u  Length of the body, i.e. the length of part 4 above
+    u  Serial number
+    u  Length of the additional header fields array
+
+    = 16 bytes
+
+This has the nice benefit that the beginning of the additional header
+fields array is aligned to an 8 byte boundary. Also, in dbus1
+marshalling arrays start with a length value of 32bit, which means in
+both dbus1 and gvariant marshallings the size of the header fields
+array will be at the same location between bytes 12 and 16. To
+visualize that:
+
+              0               4               8               12              16
+      Common: | E | T | F | V | Body Length   | Serial        | Fields Length |
+
+       dbus1: |                            ... (as above) ... | Fields array ...
+
+    gvariant: |                            ... (as above) ... | Fields Length | Fields array ...
+
+And that's already it.
+
+Note: on kdbus only native endian messages marshalled in gvariant may
+      be sent. If a client receives a message in non-native endianness
+      or in dbus1 marshalling it shall ignore the message.
+
+Note: The GVariant "MAYBE" type is not supported, so that messages can
+      be fully converted forth and back between dbus1 and gvariant
+      representations.
diff --git a/src/libsystemd/sd-bus/Makefile b/src/libsystemd/sd-bus/Makefile
new file mode 120000
index 0000000..94aaae2
--- /dev/null
+++ b/src/libsystemd/sd-bus/Makefile
@@ -0,0 +1 @@
+../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-bus/PORTING-DBUS1 b/src/libsystemd/sd-bus/PORTING-DBUS1
new file mode 100644
index 0000000..67af277
--- /dev/null
+++ b/src/libsystemd/sd-bus/PORTING-DBUS1
@@ -0,0 +1,550 @@
+A few hints on supporting kdbus as backend in your favorite D-Bus library.
+
+~~~
+
+Before you read this, have a look at the DIFFERENCES and
+GVARIANT_SERIALIZATION texts you find in the same directory where you
+found this.
+
+We invite you to port your favorite D-Bus protocol implementation
+over to kdbus. However, there are a couple of complexities
+involved. On kdbus we only speak GVariant marshaling, kdbus clients
+ignore traffic in dbus1 marshaling. Thus, you need to add a second,
+GVariant compatible marshaler to your library first.
+
+After you have done that: here's the basic principle how kdbus works:
+
+You connect to a bus by opening its bus node in /dev/kdbus/. All
+buses have a device node there, it starts with a numeric UID of the
+owner of the bus, followed by a dash and a string identifying the
+bus. The system bus is thus called /dev/kdbus/0-system, and for user
+buses the device node is /dev/kdbus/1000-user (if 1000 is your user
+id).
+
+(Before we proceed, please always keep a copy of libsystemd next
+to you, ultimately that's where the details are, this document simply
+is a rough overview to help you grok things.)
+
+CONNECTING
+
+To connect to a bus, simply open() its device node and issue the
+KDBUS_CMD_HELLO call. That's it. Now you are connected. Do not send
+Hello messages or so (as you would on dbus1), that does not exist for
+kdbus.
+
+The structure you pass to the ioctl will contain a couple of
+parameters that you need to know, to operate on the bus.
+
+There are two flags fields, one indicating features of the kdbus
+kernel side ("conn_flags"), the other one ("bus_flags") indicating
+features of the bus owner (i.e. systemd). Both flags fields are 64bit
+in width.
+
+When calling into the ioctl, you need to place your own supported
+feature bits into these fields. This tells the kernel about the
+features you support. When the ioctl returns, it will contain the
+features the kernel supports.
+
+If any of the higher 32bit are set on the two flags fields and your
+client does not know what they mean, it must disconnect. The upper
+32bit are used to indicate "incompatible" feature additions on the bus
+system, the lower 32bit indicate "compatible" feature additions. A
+client that does not support a "compatible" feature addition can go on
+communicating with the bus, however a client that does not support an
+"incompatible" feature must not proceed with the connection.
+
+The hello structure also contains another flags field "attach_flags"
+which indicates metadata that is optionally attached to all incoming
+messages. You probably want to set KDBUS_ATTACH_NAMES unconditionally
+in it. This has the effect that all well-known names of a sender are
+attached to all incoming messages. You need this information to
+implement matches that match on a message sender name correctly. Of
+course, you should only request the attachment of as little metadata
+fields as you need.
+
+The kernel will return in the "id" field your unique id. This is a
+simple numeric value. For compatibility with classic dbus1 simply
+format this as string and prefix ":0.".
+
+The kernel will also return the bloom filter size used for the signal
+broadcast bloom filter (see below).
+
+The kernel will also return the bus ID of the bus in a 128bit field.
+
+The pool size field specifies the size of the memory mapped buffer.
+After the calling the hello ioctl, you should memory map the kdbus
+fd. In this memory mapped region, the kernel will place all your incoming
+messages.
+
+SENDING MESSAGES
+
+Use the MSG_SEND ioctl to send a message to another peer. The ioctl
+takes a structure that contains a variety of fields:
+
+The flags field corresponds closely to the old dbus1 message header
+flags field, though the DONT_EXPECT_REPLY field got inverted into
+EXPECT_REPLY.
+
+The dst_id/src_id field contains the unique id of the destination and
+the sender. The sender field is overridden by the kernel usually, hence
+you shouldn't fill it in. The destination field can also take the
+special value KDBUS_DST_ID_BROADCAST for broadcast messages. For
+messages intended to a well-known name set the field to
+KDBUS_DST_ID_NAME, and attach the name in a special "items" entry to
+the message (see below).
+
+The payload field indicates the payload. For all dbus traffic it
+should carry the value 0x4442757344427573ULL. (Which encodes
+'DBusDBus').
+
+The cookie field corresponds with the "serial" field of classic
+dbus1. We simply renamed it here (and extended it to 64bit) since we
+didn't want to imply the monotonicity of the assignment the way the
+word "serial" indicates it.
+
+When sending a message that expects a reply, you need to set the
+EXPECT_REPLY flag in the message flag field. In this case you should
+also fill out the "timeout_ns" value which indicates the timeout in
+nsec for this call. If the peer does not respond in this time you will
+get a notification of a timeout. Note that this is also used for
+security purposes: a single reply messages is only allowed through the
+bus as long as the timeout has not ended. With this timeout value you
+hence "open a time window" in which the peer might respond to your
+request and the policy allows the response to go through.
+
+When sending a message that is a reply, you need to fill in the
+cookie_reply field, which is similar to the reply_serial field of
+dbus1. Note that a message cannot have EXPECT_REPLY and a reply_serial
+at the same time!
+
+This pretty much explains the ioctl header. The actual payload of the
+data is now referenced in additional items that are attached to this
+ioctl header structure at the end. When sending a message, you attach
+items of the type PAYLOAD_VEC, PAYLOAD_MEMFD, FDS, BLOOM, DST_NAME to
+it:
+
+   KDBUS_ITEM_PAYLOAD_VEC: contains a pointer + length pair for
+   referencing arbitrary user memory. This is how you reference most
+   of your data. It's a lot like the good old iovec structure of glibc.
+
+   KDBUS_ITEM_PAYLOAD_MEMFD: for large data blocks it is preferable
+   to send prepared "memfds" (see below) over. This item contains an
+   fd for a memfd plus a size.
+
+   KDBUS_ITEM_PAYLOAD_FDS: for sending over fds attach an item of this
+   type with an array of fds.
+
+   KDBUS_ITEM_BLOOM: the calculated bloom filter of this message, only
+   for undirected (broadcast) message.
+
+   KDBUS_DST_NAME: for messages that are directed to a well-known name
+   (instead of a unique name), this item contains the well-known name
+   field.
+
+A single message may consists of no, one or more payload items of type
+PAYLOAD_VEC or PAYLOAD_MEMFD. D-Bus protocol implementations should
+treat them as a single block that just happens to be split up into
+multiple items. Some restrictions apply however:
+
+   The message header in its entirety must be contained in a single
+   PAYLOAD_VEC item.
+
+   You may only split your message up right in front of each GVariant
+   contained in the payload, as well is immediately before framing of a
+   Gvariant, as well after as any padding bytes if there are any. The
+   padding bytes must be wholly contained in the preceding
+   PAYLOAD_VEC/PAYLOAD_MEMFD item. You may not split up simple types
+   nor arrays of trivial types. The latter is necessary to allow APIs
+   to return direct pointers to linear chunks of fixed size trivial
+   arrays. Examples: The simple types "u", "s", "t" have to be in the
+   same payload item. The array of simple types "ay", "ai" have to be
+   fully in contained in the same payload item. For an array "as" or
+   "a(si)" the only restriction however is to keep each string
+   individually in an uninterrupted item, to keep the framing of each
+   element and the array in a single uninterrupted item, however the
+   various strings might end up in different items.
+
+Note again, that splitting up messages into separate items is up to the
+implementation. Also note that the kdbus kernel side might merge
+separate items if it deems this to be useful. However, the order in
+which items are contained in the message is left untouched.
+
+PAYLOAD_MEMFD items allow zero-copy data transfer (see below regarding
+the memfd concept). Note however that the overhead of mapping these
+makes them relatively expensive, and only worth the trouble for memory
+blocks > 128K (this value appears to be quite universal across
+architectures, as we tested). Thus we recommend sending PAYLOAD_VEC
+items over for small messages and restore to PAYLOAD_MEMFD items for
+messages > 128K. Since while building up the message you might not
+know yet whether it will grow beyond this boundary a good approach is
+to simply build the message unconditionally in a memfd
+object. However, when the message is sealed to be sent away check for
+the size limit. If the size of the message is < 128K, then simply send
+the data as PAYLOAD_VEC and reuse the memfd. If it is >= 128K, seal
+the memfd and send it as PAYLOAD_MEMFD, and allocate a new memfd for
+the next message.
+
+RECEIVING MESSAGES
+
+Use the MSG_RECV ioctl to read a message from kdbus. This will return
+an offset into the pool memory map, relative to its beginning.
+
+The received message structure more or less follows the structure of
+the message originally sent. However, certain changes have been
+made. In the header the src_id field will be filled in.
+
+The payload items might have gotten merged and PAYLOAD_VEC items are
+not used. Instead, you will only find PAYLOAD_OFF and PAYLOAD_MEMFD
+items. The former contain an offset and size into your memory mapped
+pool where you find the payload.
+
+If during the HELLO ioctl you asked for getting metadata attached to
+your message, you will find additional KDBUS_ITEM_CREDS,
+KDBUS_ITEM_PID_COMM, KDBUS_ITEM_TID_COMM, KDBUS_ITEM_TIMESTAMP,
+KDBUS_ITEM_EXE, KDBUS_ITEM_CMDLINE, KDBUS_ITEM_CGROUP,
+KDBUS_ITEM_CAPS, KDBUS_ITEM_SECLABEL, KDBUS_ITEM_AUDIT items that
+contain this metadata. This metadata will be gathered from the sender
+at the point in time it sends the message. This information is
+uncached, and since it is appended by the kernel, trustable. The
+KDBUS_ITEM_SECLABEL item usually contains the SELinux security label,
+if it is used.
+
+After processing the message you need to call the KDBUS_CMD_FREE
+ioctl, which releases the message from the pool, and allows the kernel
+to store another message there. Note that the memory used by the pool
+is ordinary anonymous, swappable memory that is backed by tmpfs. Hence
+there is no need to copy the message out of it quickly, instead you
+can just leave it there as long as you need it and release it via the
+FREE ioctl only after that's done.
+
+BLOOM FILTERS
+
+The kernel does not understand dbus marshaling, it will not look into
+the message payload. To allow clients to subscribe to specific subsets
+of the broadcast matches we employ bloom filters.
+
+When broadcasting messages, a bloom filter needs to be attached to the
+message in a KDBUS_ITEM_BLOOM item (and only for broadcasting
+messages!). If you don't know what bloom filters are, read up now on
+Wikipedia. In short: they are a very efficient way how to
+probabilistically check whether a certain word is contained in a
+vocabulary. It knows no false negatives, but it does know false
+positives.
+
+The bloom filter that needs to be included has the parameters m=512
+(bits in the filter), k=8 (nr of hash functions). The underlying hash
+function is SipHash-2-4. We calculate two hash values for an input
+strings, one with the hash key b9660bf0467047c18875c49c54b9bd15 (this
+is supposed to be read as a series of 16 hexadecimal formatted
+bytes), and one with the hash key
+aaa154a2e0714b39bfe1dd2e9fc54a3b. This results in two 64bit hash
+values, A and B. The 8 hash functions for the bloom filter require a 9
+bit output each (since m=512=2^9), to generate these we XOR combine
+the first 8 bit of A shifted to the left by 1, with the first 8 bit of
+B. Then, for the next hash function we use the second 8 bit pair, and
+so on.
+
+For each message to send across the bus we populate the bloom filter
+with all possible matchable strings. If a client then wants to
+subscribe to messages of this type, it simply tells the kernel to test
+its own calculated bit mask against the bloom filter of each message.
+
+More specifically, the following strings are added to the bloom filter
+of each message that is broadcasted:
+
+  The string "interface:" suffixed by the interface name
+
+  The string "member:" suffixed by the member name
+
+  The string "path:" suffixed by the path name
+
+  The string "path-slash-prefix:" suffixed with the path name, and
+  also all prefixes of the path name (cut off at "/"), also prefixed
+  with "path-slash-prefix".
+
+  The string "message-type:" suffixed with the strings "signal",
+  "method_call", "error" or "method_return" for the respective message
+  type of the message.
+
+  If the first argument of the message is a string, "arg0:" suffixed
+  with the first argument.
+
+  If the first argument of the message is a string, "arg0-dot-prefix"
+  suffixed with the first argument, and also all prefixes of the
+  argument (cut off at "."), also prefixed with "arg0-dot-prefix".
+
+  If the first argument of the message is a string,
+  "arg0-slash-prefix" suffixed with the first argument, and also all
+  prefixes of the argument (cut off at "/"), also prefixed with
+  "arg0-slash-prefix".
+
+  Similar for all further arguments that are strings up to 63, for the
+  arguments and their "dot" and "slash" prefixes. On the first
+  argument that is not a string, addition to the bloom filter should be
+  stopped however.
+
+(Note that the bloom filter does not contain sender nor receiver
+names!)
+
+When a client wants to subscribe to messages matching a certain
+expression, it should calculate the bloom mask following the same
+algorithm. The kernel will then simply test the mask against the
+attached bloom filters.
+
+Note that bloom filters are probabilistic, which means that clients
+might get messages they did not expect. Your bus protocol
+implementation must be capable of dealing with these unexpected
+messages (which it needs to anyway, given that transfers are
+relatively unrestricted on kdbus and people can send you all kinds of
+non-sense).
+
+INSTALLING MATCHES
+
+To install matches for broadcast messages, use the KDBUS_CMD_ADD_MATCH
+ioctl. It takes a structure that contains an encoded match expression,
+and that is followed by one or more items, which are combined in an
+AND way. (Meaning: a message is matched exactly when all items
+attached to the original ioctl struct match).
+
+To match against other user messages add a KDBUS_ITEM_BLOOM item in
+the match (see above). Note that the bloom filter does not include
+matches to the sender names. To additionally check against sender
+names, use the KDBUS_ITEM_ID (for unique id matches) and
+KDBUS_ITEM_NAME (for well-known name matches) item types.
+
+To match against kernel generated messages (see below) you should add
+items of the same type as the kernel messages include,
+i.e. KDBUS_ITEM_NAME_ADD, KDBUS_ITEM_NAME_REMOVE,
+KDBUS_ITEM_NAME_CHANGE, KDBUS_ITEM_ID_ADD, KDBUS_ITEM_ID_REMOVE and
+fill them out. Note however, that you have some wildcards in this
+case, for example the .id field of KDBUS_ITEM_ADD/KDBUS_ITEM_REMOVE
+structures may be set to 0 to match against any id addition/removal.
+
+Note that dbus match strings do no map 1:1 to these ioctl() calls. In
+many cases (where the match string is "underspecified") you might need
+to issue up to six different ioctl() calls for the same match. For
+example, the empty match (which matches against all messages), would
+translate into one KDBUS_ITEM_BLOOM ioctl, one KDBUS_ITEM_NAME_ADD,
+one KDBUS_ITEM_NAME_CHANGE, one KDBUS_ITEM_NAME_REMOVE, one
+KDBUS_ITEM_ID_ADD and one KDBUS_ITEM_ID_REMOVE.
+
+When creating a match, you may attach a "cookie" value to them, which
+is used for deleting this match again. The cookie can be selected freely
+by the client. When issuing KDBUS_CMD_REMOVE_MATCH, simply pass the
+same cookie as before and all matches matching the same "cookie" value
+will be removed. This is particularly handy for the case where multiple
+ioctl()s are added for a single match strings.
+
+MEMFDS
+
+The "memfd" concept is used for zero-copy data transfers (see
+above). memfds are file descriptors to memory chunks of arbitrary
+sizes. If you have a memfd you can mmap() it to get access to the data
+it contains or write to it. They are comparable to file descriptors to
+unlinked files on a tmpfs, or to anonymous memory that one may refer
+to with an fd. They have one particular property: they can be
+"sealed". A memfd that is "sealed" is protected from alteration. Only
+memfds that are currently not mapped and to which a single fd refers
+may be sealed (they may also be unsealed in that case).
+
+The concept of "sealing" makes memfds useful for using them as
+transport for kdbus messages: only when the receiver knows that the
+message it has received cannot change while looking at, it can safely
+parse it without having to copy it to a safe memory area. memfds can also
+be reused in multiple messages. A sender may send the same memfd to
+multiple peers, and since it is sealed, it can be sure that the receiver
+will not be able to modify it. "Sealing" hence provides both sides of
+a transaction with the guarantee that the data stays constant and is
+reusable.
+
+memfds are a generic concept that can be used outside of the immediate
+kdbus usecase. You can send them across AF_UNIX sockets too, sealed or
+unsealed. In kdbus themselves, they can be used to send zero-copy
+payloads, but may also be sent as normal fds.
+
+memfds are allocated with the KDBUS_CMD_MEMFD_NEW ioctl. After allocation,
+simply memory map them and write to them. To set their size, use
+KDBUS_CMD_MEMFD_SIZE_SET. Note that memfds will be increased in size
+automatically if you touch previously unallocated pages. However, the
+size will only be increased in multiples of the page size in that
+case. Thus, in almost all cases, an explicit KDBUS_CMD_MEMFD_SIZE_SET
+is necessary, since it allows setting memfd sizes in finer
+granularity. To seal a memfd use the KDBUS_CMD_MEMFD_SEAL_SET ioctl
+call. It will only succeed if the caller has the only fd reference to
+the memfd open, and if the memfd is currently unmapped.
+
+If memfds are shared, keep in mind that the file pointer used by
+write/read/seek is shared too, only pread/pwrite are safe to use
+in that case.
+
+memfds may be sent across kdbus via KDBUS_ITEM_PAYLOAD_MEMFD items
+attached to messages. If this is done, the data included in the memfd
+is considered part of the payload stream of a message, and are treated
+the same way as KDBUS_ITEM_PAYLOAD_VEC by the receiving side. It is
+possible to interleave KDBUS_ITEM_PAYLOAD_MEMFD and
+KDBUS_ITEM_PAYLOAD_VEC items freely, by the reader they will be
+considered a single stream of bytes in the order these items appear in
+the message, that just happens to be split up at various places
+(regarding rules how they may be split up, see above). The kernel will
+refuse taking KDBUS_ITEM_PAYLOAD_MEMFD items that refer to memfds that
+are not sealed.
+
+Note that sealed memfds may be unsealed again if they are not mapped
+you have the only fd reference to them.
+
+Alternatively to sending memfds as KDBUS_ITEM_PAYLOAD_MEMFD items
+(where they are just a part of the payload stream of a message) you can
+also simply attach any memfd to a message using
+KDBUS_ITEM_PAYLOAD_FDS. In this case, the memfd contents is not
+considered part of the payload stream of the message, but simply fds
+like any other, that happen to be attached to the message.
+
+MESSAGES FROM THE KERNEL
+
+A couple of messages previously generated by the dbus1 bus driver are
+now generated by the kernel. Since the kernel does not understand the
+payload marshaling, they are generated by the kernel  in a different
+format. This is indicated with the "payload type" field of the
+messages set to 0. Library implementations should take these messages
+and synthesize traditional driver messages for them on reception.
+
+More specifically:
+
+   Instead of the NameOwnerChanged, NameLost, NameAcquired signals
+   there are kernel messages containing KDBUS_ITEM_NAME_ADD,
+   KDBUS_ITEM_NAME_REMOVE, KDBUS_ITEM_NAME_CHANGE, KDBUS_ITEM_ID_ADD,
+   KDBUS_ITEM_ID_REMOVE items are generated (each message will contain
+   exactly one of these items). Note that in libsystemd we have
+   obsoleted NameLost/NameAcquired messages, since they are entirely
+   redundant to NameOwnerChanged. This library will hence only
+   synthesize NameOwnerChanged messages from these kernel messages,
+   and never generate NameLost/NameAcquired. If your library needs to
+   stay compatible to the old dbus1 userspace, you possibly might need
+   to synthesize both a NameOwnerChanged and NameLost/NameAcquired
+   message from the same kernel message.
+
+   When a method call times out, a KDBUS_ITEM_REPLY_TIMEOUT message is
+   generated. This should be synthesized into a method error reply
+   message to the original call.
+
+   When a method call fails because the peer terminated the connection
+   before responding, a KDBUS_ITEM_REPLY_DEAD message is
+   generated. Similarly, it should be synthesized into a method error
+   reply message.
+
+For synthesized messages we recommend setting the cookie field to
+(uint32_t) -1 (and not (uint64_t) -1!), so that the cookie is not 0
+(which the dbus1 spec does not allow), but clearly recognizable as
+synthetic.
+
+Note that the KDBUS_ITEM_NAME_XYZ messages will actually inform you
+about all kinds of names, including activatable ones. Classic dbus1
+NameOwnerChanged messages OTOH are only generated when a name is
+really acquired on the bus and not just simply activatable. This means
+you must explicitly check for the case where an activatable name
+becomes acquired or an acquired name is lost and returns to be
+activatable.
+
+NAME REGISTRY
+
+To acquire names on the bus, use the KDBUS_CMD_NAME_ACQUIRE ioctl(). It
+takes a flags field similar to dbus1's RequestName() bus driver call,
+however the NO_QUEUE flag got inverted into a QUEUE flag instead.
+
+To release a previously acquired name use the KDBUS_CMD_NAME_RELEASE
+ioctl().
+
+To list acquired names use the KDBUS_CMD_CONN_INFO ioctl. It may be
+used to list unique names, well known names as well as activatable
+names and clients currently queuing for ownership of a well-known
+name. The ioctl will return an offset into the memory pool. After
+reading all the data you need, you need to release this via the
+KDBUS_CMD_FREE ioctl(), similar how you release a received message.
+
+CREDENTIALS
+
+kdbus can optionally attach various kinds of metadata about the sender at
+the point of time of sending ("credentials") to messages, on request
+of the receiver. This is both supported on directed and undirected
+(broadcast) messages. The metadata to attach is selected at time of
+the HELLO ioctl of the receiver via a flags field (see above). Note
+that clients must be able to handle that messages contain more
+metadata than they asked for themselves, to simplify implementation of
+broadcasting in the kernel. The receiver should not rely on this data
+to be around though, even though it will be correct if it happens to
+be attached. In order to avoid programming errors in applications, we
+recommend though not passing this data on to clients that did not
+explicitly ask for it.
+
+Credentials may also be queried for a well-known or unique name. Use
+the KDBUS_CMD_CONN_INFO for this. It will return an offset to the pool
+area again, which will contain the same credential items as messages
+have attached. Note that when issuing the ioctl, you can select a
+different set of credentials to gather, than what was originally requested
+for being attached to incoming messages.
+
+Credentials are always specific to the sender namespace that was
+current at the time of sending, and of the process that opened the
+bus connection at the time of opening it. Note that this latter data
+is cached!
+
+POLICY
+
+The kernel enforces only very limited policy on names. It will not do
+access filtering by userspace payload, and thus not by interface or
+method name.
+
+This ultimately means that most fine-grained policy enforcement needs
+to be done by the receiving process. We recommend using PolicyKit for
+any more complex checks. However, libraries should make simple static
+policy decisions regarding privileged/unprivileged method calls
+easy. We recommend doing this by enabling KDBUS_ATTACH_CAPS and
+KDBUS_ATTACH_CREDS for incoming messages, and then discerning client
+access by some capability, or if sender and receiver UIDs match.
+
+BUS ADDRESSES
+
+When connecting to kdbus use the "kernel:" protocol prefix in DBus
+address strings. The device node path is encoded in its "path="
+parameter.
+
+Client libraries should use the following connection string when
+connecting to the system bus:
+
+   kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket
+
+This will ensure that kdbus is preferred over the legacy AF_UNIX
+socket, but compatibility is kept. For the user bus use:
+
+   kernel:path=/dev/kdbus/$UID-user/bus;unix:path=$XDG_RUNTIME_DIR/bus
+
+With $UID replaced by the callers numer user ID, and $XDG_RUNTIME_DIR
+following the XDG basedir spec.
+
+Of course the $DBUS_SYSTEM_BUS_ADDRESS and $DBUS_SESSION_BUS_ADDRESS
+variables should still take precedence.
+
+DBUS SERVICE FILES
+
+Activatable services for kdbus may not use classic dbus1 service
+activation files. Instead, programs should drop in native systemd
+.service and .busname unit files, so that they are treated uniformly
+with other types of units and activation of the system.
+
+Note that this results in a major difference to classic dbus1:
+activatable bus names can be established at any time in the boot process.
+This is unlike dbus1 where activatable names are unconditionally available
+as long as dbus-daemon is running. Being able to control when
+activatable names are established is essential to allow usage of kdbus
+during early boot and in initrds, without the risk of triggering
+services too early.
+
+DISCLAIMER
+
+This all is so far just the status quo. We are putting this together, because
+we are quite confident that further API changes will be smaller, but
+to make this very clear: this is all subject to change, still!
+
+We invite you to port over your favorite dbus library to this new
+scheme, but please be prepared to make minor changes when we still
+change these interfaces!
diff --git a/src/libsystemd/sd-bus/bus-bloom.c b/src/libsystemd/sd-bus/bus-bloom.c
new file mode 100644
index 0000000..9e51334
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-bloom.c
@@ -0,0 +1,99 @@
+/*-*- 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 "util.h"
+#include "siphash24.h"
+#include "bus-bloom.h"
+
+static inline void set_bit(uint64_t filter[], unsigned b) {
+        filter[b >> 6] |= 1ULL << (b & 63);
+}
+
+#define HASH_KEY1 SD_ID128_MAKE(b9,66,0b,f0,46,70,47,c1,88,75,c4,9c,54,b9,bd,15)
+#define HASH_KEY2 SD_ID128_MAKE(aa,a1,54,a2,e0,71,4b,39,bf,e1,dd,2e,9f,c5,4a,3b)
+
+static void bloom_add_data(uint64_t filter[BLOOM_SIZE/8], const void *data, size_t n) {
+        uint8_t a[8], b[8];
+        unsigned k = 0;
+
+        /*
+         * Our bloom filter has the following parameters:
+         *
+         * m=512   (bits in the filter)
+         * k=8     (hash functions)
+         *
+         * We calculate a two 64bit SipHash values (for two fixed but
+         * randomly generated hash keys) of which we use 8 parts of 9 bits
+         * as individual hash functions.
+         *
+         */
+
+        siphash24(a, data, n, HASH_KEY1.bytes);
+        siphash24(b, data, n, HASH_KEY2.bytes);
+
+        assert_cc(BLOOM_SIZE*8 == 512);
+
+        for (k = 0; k < 8; k++)
+                set_bit(filter, ((uint16_t) a[k] << 1) ^ (uint16_t) b[k]);
+
+        /* log_debug("bloom: adding <%.*s>", (int) n, (char*) data); */
+}
+
+void bloom_add_pair(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b) {
+        size_t n;
+        char *c;
+
+        assert(filter);
+        assert(a);
+        assert(b);
+
+        n = strlen(a) + 1 + strlen(b);
+        c = alloca(n + 1);
+        strcpy(stpcpy(stpcpy(c, a), ":"), b);
+
+        bloom_add_data(filter, c, n);
+}
+
+void bloom_add_prefixes(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b, char sep) {
+        size_t n;
+        char *c, *p;
+
+        assert(filter);
+        assert(a);
+        assert(b);
+
+        n = strlen(a) + 1 + strlen(b);
+        c = alloca(n + 1);
+
+        p = stpcpy(stpcpy(c, a), ":");
+        strcpy(p, b);
+
+        for (;;) {
+                char *e;
+
+                e = strrchr(p, sep);
+                if (!e || e == p)
+                        break;
+
+                *e = 0;
+                bloom_add_data(filter, c, e - c);
+        }
+}
diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h
new file mode 100644
index 0000000..422eb4e
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-bloom.h
@@ -0,0 +1,29 @@
+/*-*- 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 <sys/types.h>
+
+#define BLOOM_SIZE 64
+
+void bloom_add_pair(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b);
+void bloom_add_prefixes(uint64_t filter[BLOOM_SIZE/8], const char *a, const char *b, char sep);
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
new file mode 100644
index 0000000..d330363
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -0,0 +1,241 @@
+/*-*- 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 <unistd.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "fileio.h"
+#include "bus-internal.h"
+#include "bus-socket.h"
+#include "bus-container.h"
+
+int bus_container_connect_socket(sd_bus *b) {
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+        pid_t leader, child;
+        siginfo_t si;
+        int r;
+
+        assert(b);
+        assert(b->input_fd < 0);
+        assert(b->output_fd < 0);
+
+        r = container_get_leader(b->machine, &leader);
+        if (r < 0)
+                return r;
+
+        r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd);
+        if (r < 0)
+                return r;
+
+        b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (b->input_fd < 0)
+                return -errno;
+
+        b->output_fd = b->input_fd;
+
+        bus_socket_setup(b);
+
+        child = fork();
+        if (child < 0)
+                return -errno;
+
+        if (child == 0) {
+                pid_t grandchild;
+
+                r = namespace_enter(pidnsfd, mntnsfd, rootfd);
+                if (r < 0)
+                        _exit(255);
+
+                /* We just changed PID namespace, however it will only
+                 * take effect on the children we now fork. Hence,
+                 * let's fork another time, and connect from this
+                 * grandchild, so that SO_PEERCRED of our connection
+                 * comes from a process from within the container, and
+                 * not outside of it */
+
+                grandchild = fork();
+                if (grandchild < 0)
+                        _exit(255);
+
+                if (grandchild == 0) {
+
+                        r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
+                        if (r < 0) {
+                                if (errno == EINPROGRESS)
+                                        _exit(1);
+
+                                _exit(255);
+                        }
+
+                        _exit(EXIT_SUCCESS);
+                }
+
+                r = wait_for_terminate(grandchild, &si);
+                if (r < 0)
+                        _exit(255);
+
+                if (si.si_code != CLD_EXITED)
+                        _exit(255);
+
+                _exit(si.si_status);
+        }
+
+        r = wait_for_terminate(child, &si);
+        if (r < 0)
+                return r;
+
+        if (si.si_code != CLD_EXITED)
+                return -EIO;
+
+        if (si.si_status == 1)
+                return 1;
+
+        if (si.si_status != EXIT_SUCCESS)
+                return -EIO;
+
+        return bus_socket_start_auth(b);
+}
+
+int bus_container_connect_kernel(sd_bus *b) {
+        _cleanup_close_pipe_ int pair[2] = { -1, -1 };
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(int))];
+        } control = {};
+        struct msghdr mh = {
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
+        };
+        struct cmsghdr *cmsg;
+        pid_t leader, child;
+        siginfo_t si;
+        int r;
+        _cleanup_close_ int fd = -1;
+
+        assert(b);
+        assert(b->input_fd < 0);
+        assert(b->output_fd < 0);
+
+        r = container_get_leader(b->machine, &leader);
+        if (r < 0)
+                return r;
+
+        r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd);
+        if (r < 0)
+                return r;
+
+        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+                return -errno;
+
+        child = fork();
+        if (child < 0)
+                return -errno;
+
+        if (child == 0) {
+                pid_t grandchild;
+
+                close_nointr_nofail(pair[0]);
+                pair[0] = -1;
+
+                r = namespace_enter(pidnsfd, mntnsfd, rootfd);
+                if (r < 0)
+                        _exit(EXIT_FAILURE);
+
+                /* We just changed PID namespace, however it will only
+                 * take effect on the children we now fork. Hence,
+                 * let's fork another time, and connect from this
+                 * grandchild, so that kdbus only sees the credentials
+                 * of this process which comes from within the
+                 * container, and not outside of it */
+
+                grandchild = fork();
+                if (grandchild < 0)
+                        _exit(EXIT_FAILURE);
+
+                if (grandchild == 0) {
+
+                        fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
+                        if (fd < 0)
+                                _exit(EXIT_FAILURE);
+
+                        cmsg = CMSG_FIRSTHDR(&mh);
+                        cmsg->cmsg_level = SOL_SOCKET;
+                        cmsg->cmsg_type = SCM_RIGHTS;
+                        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+                        memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+                        mh.msg_controllen = cmsg->cmsg_len;
+
+                        if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
+                                _exit(EXIT_FAILURE);
+
+                        _exit(EXIT_SUCCESS);
+                }
+
+                r = wait_for_terminate(grandchild, &si);
+                if (r < 0)
+                        _exit(EXIT_FAILURE);
+
+                if (si.si_code != CLD_EXITED)
+                        _exit(EXIT_FAILURE);
+
+                _exit(si.si_status);
+        }
+
+        close_nointr_nofail(pair[1]);
+        pair[1] = -1;
+
+        r = wait_for_terminate(child, &si);
+        if (r < 0)
+                return r;
+
+        if (si.si_code != CLD_EXITED)
+                return -EIO;
+
+        if (si.si_status != EXIT_SUCCESS)
+                return -EIO;
+
+        if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
+                return -errno;
+
+        for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
+                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+                        int *fds;
+                        unsigned n_fds;
+
+                        fds = (int*) CMSG_DATA(cmsg);
+                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+                        if (n_fds != 1) {
+                                close_many(fds, n_fds);
+                                return -EIO;
+                        }
+
+                        fd = fds[0];
+                }
+
+        b->input_fd = b->output_fd = fd;
+        fd = -1;
+
+        return bus_kernel_take_fd(b);
+}
diff --git a/src/libsystemd/sd-bus/bus-container.h b/src/libsystemd/sd-bus/bus-container.h
new file mode 100644
index 0000000..c6f757a
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-container.h
@@ -0,0 +1,27 @@
+/*-*- 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-bus.h"
+
+int bus_container_connect_socket(sd_bus *b);
+int bus_container_connect_kernel(sd_bus *b);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
new file mode 100644
index 0000000..e7e9ba0
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -0,0 +1,1217 @@
+/*-*- 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/>.
+***/
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
+#include <stddef.h>
+#include <errno.h>
+
+#include "strv.h"
+#include "sd-bus.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-control.h"
+#include "bus-bloom.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+
+_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(unique, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = bus_ensure_running(bus);
+        if (r < 0)
+                return r;
+
+        *unique = bus->unique_name;
+        return 0;
+}
+
+static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
+        struct kdbus_cmd_name *n;
+        size_t size, l;
+        int r;
+
+        assert(bus);
+        assert(name);
+
+        l = strlen(name);
+        size = offsetof(struct kdbus_cmd_name, name) + l + 1;
+        n = alloca0(size);
+        n->size = size;
+        kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
+        memcpy(n->name, name, l+1);
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+        VALGRIND_MAKE_MEM_DEFINED(n, n->size);
+#endif
+
+        r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
+        if (r < 0)
+                return -errno;
+
+        if (n->flags & KDBUS_NAME_IN_QUEUE)
+                return 0;
+
+        return 1;
+}
+
+static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        uint32_t ret, param = 0;
+        int r;
+
+        assert(bus);
+        assert(name);
+
+        if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
+                param |= BUS_NAME_ALLOW_REPLACEMENT;
+        if (flags & SD_BUS_NAME_REPLACE_EXISTING)
+                param |= BUS_NAME_REPLACE_EXISTING;
+        if (!(flags & SD_BUS_NAME_QUEUE))
+                param |= BUS_NAME_DO_NOT_QUEUE;
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "RequestName",
+                        NULL,
+                        &reply,
+                        "su",
+                        name,
+                        param);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(reply, "u", &ret);
+        if (r < 0)
+                return r;
+
+        if (ret == BUS_NAME_ALREADY_OWNER)
+                return -EALREADY;
+        else if (ret == BUS_NAME_EXISTS)
+                return -EEXIST;
+        else if (ret == BUS_NAME_IN_QUEUE)
+                return 0;
+        else if (ret == BUS_NAME_PRIMARY_OWNER)
+                return 1;
+
+        return -EIO;
+}
+
+_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(bus->bus_client, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
+        assert_return(service_name_is_valid(name), -EINVAL);
+        assert_return(name[0] != ':', -EINVAL);
+
+        if (bus->is_kernel)
+                return bus_request_name_kernel(bus, name, flags);
+        else
+                return bus_request_name_dbus1(bus, name, flags);
+}
+
+static int bus_release_name_kernel(sd_bus *bus, const char *name) {
+        struct kdbus_cmd_name *n;
+        size_t l;
+        int r;
+
+        assert(bus);
+        assert(name);
+
+        l = strlen(name);
+        n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
+        n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
+        memcpy(n->name, name, l+1);
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+        VALGRIND_MAKE_MEM_DEFINED(n, n->size);
+#endif
+        r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
+        if (r < 0)
+                return -errno;
+
+        return n->flags;
+}
+
+static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        uint32_t ret;
+        int r;
+
+        assert(bus);
+        assert(name);
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "ReleaseName",
+                        NULL,
+                        &reply,
+                        "s",
+                        name);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(reply, "u", &ret);
+        if (r < 0)
+                return r;
+        if (ret == BUS_NAME_NON_EXISTENT)
+                return -ESRCH;
+        if (ret == BUS_NAME_NOT_OWNER)
+                return -EADDRINUSE;
+        if (ret == BUS_NAME_RELEASED)
+                return 0;
+
+        return -EINVAL;
+}
+
+_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(bus->bus_client, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(service_name_is_valid(name), -EINVAL);
+        assert_return(name[0] != ':', -EINVAL);
+
+        if (bus->is_kernel)
+                return bus_release_name_kernel(bus, name);
+        else
+                return bus_release_name_dbus1(bus, name);
+}
+
+static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
+        struct kdbus_cmd_name_list cmd = {};
+        struct kdbus_name_list *name_list;
+        struct kdbus_cmd_name *name;
+        uint64_t previous_id = 0;
+        int r;
+
+        /* Caller will free half-constructed list on failure... */
+
+        cmd.flags = flags;
+
+        r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
+        if (r < 0)
+                return -errno;
+
+        name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
+
+        KDBUS_ITEM_FOREACH(name, name_list, names) {
+
+                if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
+                        char *n;
+
+                        if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0)
+                                return -ENOMEM;
+
+                        r = strv_push(x, n);
+                        if (r < 0) {
+                                free(n);
+                                return -ENOMEM;
+                        }
+
+                        previous_id = name->owner_id;
+                }
+
+                if (name->size > sizeof(*name) && service_name_is_valid(name->name)) {
+                        r = strv_extend(x, name->name);
+                        if (r < 0)
+                                return -ENOMEM;
+                }
+        }
+
+        r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
+        _cleanup_strv_free_ char **x = NULL, **y = NULL;
+        int r;
+
+        if (acquired) {
+                r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
+                if (r < 0)
+                        return r;
+        }
+
+        if (activatable) {
+                r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
+                if (r < 0)
+                        return r;
+
+                *activatable = y;
+                y = NULL;
+        }
+
+        if (acquired) {
+                *acquired = x;
+                x = NULL;
+        }
+
+        return 0;
+}
+
+static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_strv_free_ char **x = NULL, **y = NULL;
+        int r;
+
+        if (acquired) {
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.DBus",
+                                "/org/freedesktop/DBus",
+                                "org.freedesktop.DBus",
+                                "ListNames",
+                                NULL,
+                                &reply,
+                                NULL);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read_strv(reply, &x);
+                if (r < 0)
+                        return r;
+
+                reply = sd_bus_message_unref(reply);
+        }
+
+        if (activatable) {
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.DBus",
+                                "/org/freedesktop/DBus",
+                                "org.freedesktop.DBus",
+                                "ListActivatableNames",
+                                NULL,
+                                &reply,
+                                NULL);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read_strv(reply, &y);
+                if (r < 0)
+                        return r;
+
+                *activatable = y;
+                y = NULL;
+        }
+
+        if (acquired) {
+                *acquired = x;
+                x = NULL;
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
+        assert_return(bus, -EINVAL);
+        assert_return(acquired || activatable, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (bus->is_kernel)
+                return bus_list_names_kernel(bus, acquired, activatable);
+        else
+                return bus_list_names_dbus1(bus, acquired, activatable);
+}
+
+static int bus_get_owner_kdbus(
+                sd_bus *bus,
+                const char *name,
+                uint64_t mask,
+                sd_bus_creds **creds) {
+
+        _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
+        struct kdbus_cmd_conn_info *cmd;
+        struct kdbus_conn_info *conn_info;
+        struct kdbus_item *item;
+        size_t size;
+        uint64_t m, id;
+        int r;
+
+        r = bus_kernel_parse_unique_name(name, &id);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                size = offsetof(struct kdbus_cmd_conn_info, name);
+                cmd = alloca0(size);
+                cmd->id = id;
+        } else {
+                size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
+                cmd = alloca0(size);
+                strcpy(cmd->name, name);
+        }
+        cmd->flags = KDBUS_ATTACH_NAMES;
+
+        cmd->size = size;
+        r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
+        if (r < 0)
+                return -errno;
+
+        conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
+
+        /* Non-activated names are considered not available */
+        if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
+                return name[0] == ':' ? -ENXIO : -ENOENT;
+
+        c = bus_creds_new();
+        if (!c)
+                return -ENOMEM;
+
+        if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
+                if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
+                        return -ENOMEM;
+
+                c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
+        }
+
+        KDBUS_ITEM_FOREACH(item, conn_info, items) {
+
+                switch (item->type) {
+
+                case KDBUS_ITEM_CREDS:
+                        m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask;
+
+                        if (m) {
+                                c->uid = (uid_t) item->creds.uid;
+                                c->pid = (pid_t) item->creds.pid;
+                                c->gid = (gid_t) item->creds.gid;
+                                c->mask |= m;
+                        }
+
+                        if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) {
+                                c->tid = (pid_t) item->creds.tid;
+                                c->mask |= SD_BUS_CREDS_TID;
+                        }
+
+                        if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) {
+                                c->pid_starttime = item->creds.starttime;
+                                c->mask |= SD_BUS_CREDS_PID_STARTTIME;
+                        }
+
+                        break;
+
+                case KDBUS_ITEM_PID_COMM:
+                        if (mask & SD_BUS_CREDS_COMM) {
+                                c->comm = strdup(item->str);
+                                if (!c->comm) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= SD_BUS_CREDS_COMM;
+                        }
+                        break;
+
+                case KDBUS_ITEM_TID_COMM:
+                        if (mask & SD_BUS_CREDS_TID_COMM) {
+                                c->tid_comm = strdup(item->str);
+                                if (!c->tid_comm) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= SD_BUS_CREDS_TID_COMM;
+                        }
+                        break;
+
+                case KDBUS_ITEM_EXE:
+                        if (mask & SD_BUS_CREDS_EXE) {
+                                c->exe = strdup(item->str);
+                                if (!c->exe) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= SD_BUS_CREDS_EXE;
+                        }
+                        break;
+
+                case KDBUS_ITEM_CMDLINE:
+                        if (mask & SD_BUS_CREDS_CMDLINE) {
+                                c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
+                                c->cmdline = memdup(item->data, c->cmdline_size);
+                                if (!c->cmdline) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= SD_BUS_CREDS_CMDLINE;
+                        }
+                        break;
+
+                case KDBUS_ITEM_CGROUP:
+                        m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
+                             SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
+                             SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
+
+                        if (m) {
+                                c->cgroup = strdup(item->str);
+                                if (!c->cgroup) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                if (!bus->cgroup_root) {
+                                        r = cg_get_root_path(&bus->cgroup_root);
+                                        if (r < 0)
+                                                goto fail;
+                                }
+
+                                c->cgroup_root = strdup(bus->cgroup_root);
+                                if (!c->cgroup_root) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= m;
+                        }
+                        break;
+
+                case KDBUS_ITEM_CAPS:
+                        m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
+                             SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
+
+                        if (m) {
+                                c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE;
+                                c->capability = memdup(item->data, c->capability_size);
+                                if (!c->capability) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= m;
+                        }
+                        break;
+
+                case KDBUS_ITEM_SECLABEL:
+                        if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+                                c->label = strdup(item->str);
+                                if (!c->label) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+                        }
+                        break;
+
+                case KDBUS_ITEM_AUDIT:
+                        m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
+
+                        if (m) {
+                                c->audit_session_id = item->audit.sessionid;
+                                c->audit_login_uid = item->audit.loginuid;
+                                c->mask |= m;
+                        }
+                        break;
+
+                case KDBUS_ITEM_NAME:
+                        if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
+                                r = strv_extend(&c->well_known_names, item->name.name);
+                                if (r < 0)
+                                        goto fail;
+
+                                c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
+                        }
+                        break;
+                }
+        }
+
+        if (creds) {
+                *creds = c;
+                c = NULL;
+        }
+
+        r = 0;
+
+fail:
+        ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
+        return r;
+}
+
+static int bus_get_owner_dbus1(
+                sd_bus *bus,
+                const char *name,
+                uint64_t mask,
+                sd_bus_creds **creds) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
+        _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
+        const char *unique = NULL;
+        pid_t pid = 0;
+        int r;
+
+        /* Only query the owner if the caller wants to know it or if
+         * the caller just wants to check whether a name exists */
+        if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.DBus",
+                                "/org/freedesktop/DBus",
+                                "org.freedesktop.DBus",
+                                "GetNameOwner",
+                                NULL,
+                                &reply_unique,
+                                "s",
+                                name);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(reply_unique, "s", &unique);
+                if (r < 0)
+                        return r;
+        }
+
+        if (mask != 0) {
+                c = bus_creds_new();
+                if (!c)
+                        return -ENOMEM;
+
+                if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
+                        c->unique_name = strdup(unique);
+                        if (!c->unique_name)
+                                return -ENOMEM;
+
+                        c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
+                }
+
+                if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
+                            SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+                            SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
+                            SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+                            SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
+                        uint32_t u;
+
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.DBus",
+                                        "/org/freedesktop/DBus",
+                                        "org.freedesktop.DBus",
+                                        "GetConnectionUnixProcessID",
+                                        NULL,
+                                        &reply,
+                                        "s",
+                                        unique ? unique : name);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_read(reply, "u", &u);
+                        if (r < 0)
+                                return r;
+
+                        pid = u;
+                        if (mask & SD_BUS_CREDS_PID) {
+                                c->pid = u;
+                                c->mask |= SD_BUS_CREDS_PID;
+                        }
+
+                        reply = sd_bus_message_unref(reply);
+                }
+
+                if (mask & SD_BUS_CREDS_UID) {
+                        uint32_t u;
+
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.DBus",
+                                        "/org/freedesktop/DBus",
+                                        "org.freedesktop.DBus",
+                                        "GetConnectionUnixUser",
+                                        NULL,
+                                        &reply,
+                                        "s",
+                                        unique ? unique : name);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_read(reply, "u", &u);
+                        if (r < 0)
+                                return r;
+
+                        c->uid = u;
+                        c->mask |= SD_BUS_CREDS_UID;
+
+                        reply = sd_bus_message_unref(reply);
+                }
+
+                if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+                        const void *p;
+                        size_t sz;
+
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.DBus",
+                                        "/org/freedesktop/DBus",
+                                        "org.freedesktop.DBus",
+                                        "GetConnectionSELinuxSecurityContext",
+                                        NULL,
+                                        &reply,
+                                        "s",
+                                        unique ? unique : name);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_read_array(reply, 'y', &p, &sz);
+                        if (r < 0)
+                                return r;
+
+                        c->label = strndup(p, sz);
+                        if (!c->label)
+                                return -ENOMEM;
+
+                        c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+                }
+
+                r = bus_creds_add_more(c, mask, pid, 0);
+                if (r < 0)
+                        return r;
+        }
+
+        if (creds) {
+                *creds = c;
+                c = NULL;
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_get_owner(
+                sd_bus *bus,
+                const char *name,
+                uint64_t mask,
+                sd_bus_creds **creds) {
+
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+        assert_return(mask == 0 || creds, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(service_name_is_valid(name), -EINVAL);
+        assert_return(bus->bus_client, -ENODATA);
+
+        if (bus->is_kernel)
+                return bus_get_owner_kdbus(bus, name, mask, creds);
+        else
+                return bus_get_owner_dbus1(bus, name, mask, creds);
+}
+
+static int add_name_change_match(sd_bus *bus,
+                                 uint64_t cookie,
+                                 const char *name,
+                                 const char *old_owner,
+                                 const char *new_owner) {
+
+        uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
+        int is_name_id = -1, r;
+        struct kdbus_item *item;
+
+        assert(bus);
+
+        /* If we encounter a match that could match against
+         * NameOwnerChanged messages, then we need to create
+         * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
+         * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
+         * multiple if the match is underspecified.
+         *
+         * The NameOwnerChanged signals take three parameters with
+         * unique or well-known names, but only some forms actually
+         * exist:
+         *
+         * WELLKNOWN, "", UNIQUE       → KDBUS_ITEM_NAME_ADD
+         * WELLKNOWN, UNIQUE, ""       → KDBUS_ITEM_NAME_REMOVE
+         * WELLKNOWN, UNIQUE, UNIQUE   → KDBUS_ITEM_NAME_CHANGE
+         * UNIQUE, "", UNIQUE          → KDBUS_ITEM_ID_ADD
+         * UNIQUE, UNIQUE, ""          → KDBUS_ITEM_ID_REMOVE
+         *
+         * For the latter two the two unique names must be identical.
+         *
+         * */
+
+        if (name) {
+                is_name_id = bus_kernel_parse_unique_name(name, &name_id);
+                if (is_name_id < 0)
+                        return 0;
+        }
+
+        if (!isempty(old_owner)) {
+                r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
+                if (r < 0)
+                        return 0;
+                if (r == 0)
+                        return 0;
+                if (is_name_id > 0 && old_owner_id != name_id)
+                        return 0;
+        } else
+                old_owner_id = KDBUS_MATCH_ID_ANY;
+
+        if (!isempty(new_owner)) {
+                r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return 0;
+                if (is_name_id > 0 && new_owner_id != name_id)
+                        return 0;
+        } else
+                new_owner_id = KDBUS_MATCH_ID_ANY;
+
+        if (is_name_id <= 0) {
+                struct kdbus_cmd_match *m;
+                size_t sz, l;
+
+                /* If the name argument is missing or is a well-known
+                 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
+                 * matches for it */
+
+                l = name ? strlen(name) + 1 : 0;
+
+                sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
+                            offsetof(struct kdbus_item, name_change) +
+                            offsetof(struct kdbus_notify_name_change, name) +
+                            l);
+
+                m = alloca0(sz);
+                m->size = sz;
+                m->cookie = cookie;
+
+                item = m->items;
+                item->size =
+                        offsetof(struct kdbus_item, name_change) +
+                        offsetof(struct kdbus_notify_name_change, name) +
+                        l;
+
+                item->name_change.old.id = old_owner_id;
+                item->name_change.new.id = new_owner_id;
+
+                if (name)
+                        memcpy(item->name_change.name, name, l);
+
+                /* If the old name is unset or empty, then
+                 * this can match against added names */
+                if (!old_owner || old_owner[0] == 0) {
+                        item->type = KDBUS_ITEM_NAME_ADD;
+
+                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+                        if (r < 0)
+                                return -errno;
+                }
+
+                /* If the new name is unset or empty, then
+                 * this can match against removed names */
+                if (!new_owner || new_owner[0] == 0) {
+                        item->type = KDBUS_ITEM_NAME_REMOVE;
+
+                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+                        if (r < 0)
+                                return -errno;
+                }
+
+                /* The CHANGE match we need in either case, because
+                 * what is reported as a name change by the kernel
+                 * might just be an owner change between starter and
+                 * normal clients. For userspace such a change should
+                 * be considered a removal/addition, hence let's
+                 * subscribe to this unconditionally. */
+                item->type = KDBUS_ITEM_NAME_CHANGE;
+                r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+                if (r < 0)
+                        return -errno;
+        }
+
+        if (is_name_id != 0) {
+                struct kdbus_cmd_match *m;
+                uint64_t sz;
+
+                /* If the name argument is missing or is a unique
+                 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
+                 * for it */
+
+                sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
+                            offsetof(struct kdbus_item, id_change) +
+                            sizeof(struct kdbus_notify_id_change));
+
+                m = alloca0(sz);
+                m->size = sz;
+                m->cookie = cookie;
+
+                item = m->items;
+                item->size =
+                        offsetof(struct kdbus_item, id_change) +
+                        sizeof(struct kdbus_notify_id_change);
+                item->id_change.id = name_id;
+
+                /* If the old name is unset or empty, then this can
+                 * match against added ids */
+                if (!old_owner || old_owner[0] == 0) {
+                        item->type = KDBUS_ITEM_ID_ADD;
+
+                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+                        if (r < 0)
+                                return -errno;
+                }
+
+                /* If thew new name is unset or empty, then this can
+                 * match against removed ids */
+                if (!new_owner || new_owner[0] == 0) {
+                        item->type = KDBUS_ITEM_ID_REMOVE;
+
+                        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+                        if (r < 0)
+                                return -errno;
+                }
+        }
+
+        return 0;
+}
+
+int bus_add_match_internal_kernel(
+                sd_bus *bus,
+                uint64_t id,
+                struct bus_match_component *components,
+                unsigned n_components,
+                uint64_t cookie) {
+
+        struct kdbus_cmd_match *m;
+        struct kdbus_item *item;
+        uint64_t bloom[BLOOM_SIZE/8];
+        size_t sz;
+        const char *sender = NULL;
+        size_t sender_length = 0;
+        uint64_t src_id = KDBUS_MATCH_ID_ANY;
+        bool using_bloom = false;
+        unsigned i;
+        bool matches_name_change = true;
+        const char *name_change_arg[3] = {};
+        int r;
+
+        assert(bus);
+
+        zero(bloom);
+
+        sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
+
+        for (i = 0; i < n_components; i++) {
+                struct bus_match_component *c = &components[i];
+
+                switch (c->type) {
+
+                case BUS_MATCH_SENDER:
+                        if (!streq(c->value_str, "org.freedesktop.DBus"))
+                                matches_name_change = false;
+
+                        r = bus_kernel_parse_unique_name(c->value_str, &src_id);
+                        if (r < 0)
+                                return r;
+                        else if (r > 0)
+                                sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
+                        else  {
+                                sender = c->value_str;
+                                sender_length = strlen(sender);
+                                sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
+                        }
+
+                        break;
+
+                case BUS_MATCH_MESSAGE_TYPE:
+                        if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
+                                matches_name_change = false;
+
+                        bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
+                        using_bloom = true;
+                        break;
+
+                case BUS_MATCH_INTERFACE:
+                        if (!streq(c->value_str, "org.freedesktop.DBus"))
+                                matches_name_change = false;
+
+                        bloom_add_pair(bloom, "interface", c->value_str);
+                        using_bloom = true;
+                        break;
+
+                case BUS_MATCH_MEMBER:
+                        if (!streq(c->value_str, "NameOwnerChanged"))
+                                matches_name_change = false;
+
+                        bloom_add_pair(bloom, "member", c->value_str);
+                        using_bloom = true;
+                        break;
+
+                case BUS_MATCH_PATH:
+                        if (!streq(c->value_str, "/org/freedesktop/DBus"))
+                                matches_name_change = false;
+
+                        bloom_add_pair(bloom, "path", c->value_str);
+                        using_bloom = true;
+                        break;
+
+                case BUS_MATCH_PATH_NAMESPACE:
+                        if (!streq(c->value_str, "/")) {
+                                bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
+                                using_bloom = true;
+                        }
+                        break;
+
+                case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
+                        char buf[sizeof("arg")-1 + 2 + 1];
+
+                        if (c->type - BUS_MATCH_ARG < 3)
+                                name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
+
+                        snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
+                        bloom_add_pair(bloom, buf, c->value_str);
+                        using_bloom = true;
+                        break;
+                }
+
+                case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
+                        char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+
+                        snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
+                        bloom_add_pair(bloom, buf, c->value_str);
+                        using_bloom = true;
+                        break;
+                }
+
+                case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
+                        char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
+
+                        snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
+                        bloom_add_pair(bloom, buf, c->value_str);
+                        using_bloom = true;
+                        break;
+                }
+
+                case BUS_MATCH_DESTINATION:
+                        /* The bloom filter does not include
+                           the destination, since it is only
+                           available for broadcast messages
+                           which do not carry a destination
+                           since they are undirected. */
+                        break;
+
+                case BUS_MATCH_ROOT:
+                case BUS_MATCH_VALUE:
+                case BUS_MATCH_LEAF:
+                case _BUS_MATCH_NODE_TYPE_MAX:
+                case _BUS_MATCH_NODE_TYPE_INVALID:
+                        assert_not_reached("Invalid match type?");
+                }
+        }
+
+        if (using_bloom)
+                sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
+
+        m = alloca0(sz);
+        m->size = sz;
+        m->cookie = cookie;
+        m->owner_id = id;
+
+        item = m->items;
+
+        if (src_id != KDBUS_MATCH_ID_ANY) {
+                item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
+                item->type = KDBUS_ITEM_ID;
+                item->id = src_id;
+                item = KDBUS_ITEM_NEXT(item);
+        }
+
+        if (using_bloom) {
+                item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
+                item->type = KDBUS_ITEM_BLOOM;
+                memcpy(item->data64, bloom, BLOOM_SIZE);
+                item = KDBUS_ITEM_NEXT(item);
+        }
+
+        if (sender) {
+                item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
+                item->type = KDBUS_ITEM_NAME;
+                memcpy(item->str, sender, sender_length + 1);
+        }
+
+        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
+        if (r < 0)
+                return -errno;
+
+        if (matches_name_change) {
+
+                /* If this match could theoretically match
+                 * NameOwnerChanged messages, we need to
+                 * install a second non-bloom filter explitly
+                 * for it */
+
+                r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int bus_add_match_internal_dbus1(
+                sd_bus *bus,
+                const char *match) {
+
+        assert(bus);
+        assert(match);
+
+        return sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "AddMatch",
+                        NULL,
+                        NULL,
+                        "s",
+                        match);
+}
+
+int bus_add_match_internal(
+                sd_bus *bus,
+                const char *match,
+                struct bus_match_component *components,
+                unsigned n_components,
+                uint64_t cookie) {
+
+        assert(bus);
+        assert(match);
+
+        if (bus->is_kernel)
+                return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
+        else
+                return bus_add_match_internal_dbus1(bus, match);
+}
+
+int bus_remove_match_internal_kernel(
+                sd_bus *bus,
+                uint64_t id,
+                uint64_t cookie) {
+
+        struct kdbus_cmd_match m;
+        int r;
+
+        assert(bus);
+
+        zero(m);
+        m.size = offsetof(struct kdbus_cmd_match, items);
+        m.cookie = cookie;
+        m.owner_id = id;
+
+        r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int bus_remove_match_internal_dbus1(
+                sd_bus *bus,
+                const char *match) {
+
+        assert(bus);
+        assert(match);
+
+        return sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "RemoveMatch",
+                        NULL,
+                        NULL,
+                        "s",
+                        match);
+}
+
+int bus_remove_match_internal(
+                sd_bus *bus,
+                const char *match,
+                uint64_t cookie) {
+
+        assert(bus);
+        assert(match);
+
+        if (bus->is_kernel)
+                return bus_remove_match_internal_kernel(bus, 0, cookie);
+        else
+                return bus_remove_match_internal_dbus1(bus, match);
+}
+
+_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
+        const char *mid;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(machine, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(service_name_is_valid(name), -EINVAL);
+
+        if (streq_ptr(name, bus->unique_name))
+                return sd_id128_get_machine(machine);
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        name,
+                        "/",
+                        "org.freedesktop.DBus.Peer",
+                        "GetMachineId", &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_set_no_auto_start(m, true);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_call(bus, m, 0, NULL, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(reply, "s", &mid);
+        if (r < 0)
+                return r;
+
+        return sd_id128_from_string(mid, machine);
+}
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
new file mode 100644
index 0000000..b610bef
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-control.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 "sd-bus.h"
+
+int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
+int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
+
+int bus_add_match_internal_kernel(sd_bus *bus, uint64_t id, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
+int bus_remove_match_internal_kernel(sd_bus *bus, uint64_t id, uint64_t cookie);
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
new file mode 100644
index 0000000..3964960
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -0,0 +1,442 @@
+/*-*- 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 "bus-internal.h"
+#include "bus-message.h"
+#include "bus-signature.h"
+#include "bus-util.h"
+#include "bus-type.h"
+
+_public_ int sd_bus_emit_signal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *member,
+                const char *types, ...) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_message_new_signal(bus, path, interface, member, &m);
+        if (r < 0)
+                return r;
+
+        if (!isempty(types)) {
+                va_list ap;
+
+                va_start(ap, types);
+                r = bus_message_append_ap(m, types, ap);
+                va_end(ap);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_send(bus, m, NULL);
+}
+
+_public_ int sd_bus_call_method(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_error *error,
+                sd_bus_message **reply,
+                const char *types, ...) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
+        if (r < 0)
+                return r;
+
+        if (!isempty(types)) {
+                va_list ap;
+
+                va_start(ap, types);
+                r = bus_message_append_ap(m, types, ap);
+                va_end(ap);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_call(bus, m, 0, error, reply);
+}
+
+_public_ int sd_bus_reply_method_return(
+                sd_bus_message *call,
+                const char *types, ...) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 0;
+
+        r = sd_bus_message_new_method_return(call, &m);
+        if (r < 0)
+                return r;
+
+        if (!isempty(types)) {
+                va_list ap;
+
+                va_start(ap, types);
+                r = bus_message_append_ap(m, types, ap);
+                va_end(ap);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_send(call->bus, m, NULL);
+}
+
+_public_ int sd_bus_reply_method_error(
+                sd_bus_message *call,
+                const sd_bus_error *e) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(sd_bus_error_is_set(e), -EINVAL);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 0;
+
+        r = sd_bus_message_new_method_error(call, e, &m);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(call->bus, m, NULL);
+}
+
+_public_ int sd_bus_reply_method_errorf(
+                sd_bus_message *call,
+                const char *name,
+                const char *format,
+                ...) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        va_list ap;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 0;
+
+        va_start(ap, format);
+        bus_error_setfv(&error, name, format, ap);
+        va_end(ap);
+
+        return sd_bus_reply_method_error(call, &error);
+}
+
+_public_ int sd_bus_reply_method_errno(
+                sd_bus_message *call,
+                int error,
+                const sd_bus_error *p) {
+
+        _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 0;
+
+        if (sd_bus_error_is_set(p))
+                return sd_bus_reply_method_error(call, p);
+
+        sd_bus_error_set_errno(&berror, error);
+
+        return sd_bus_reply_method_error(call, &berror);
+}
+
+_public_ int sd_bus_reply_method_errnof(
+                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(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        if (call->header->flags & 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(call, &berror);
+}
+
+_public_ int sd_bus_get_property(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_error *error,
+                sd_bus_message **reply,
+                const char *type) {
+
+        sd_bus_message *rep = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(reply, -EINVAL);
+        assert_return(signature_is_single(type, false), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(rep, 'v', type);
+        if (r < 0) {
+                sd_bus_message_unref(rep);
+                return r;
+        }
+
+        *reply = rep;
+        return 0;
+}
+
+_public_ int sd_bus_get_property_trivial(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_error *error,
+                char type, void *ptr) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(bus_type_is_trivial(type), -EINVAL);
+        assert_return(ptr, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_basic(reply, type, ptr);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+_public_ int sd_bus_get_property_string(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_error *error,
+                char **ret) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        const char *s;
+        char *n;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(reply, 'v', "s");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_basic(reply, 's', &s);
+        if (r < 0)
+                return r;
+
+        n = strdup(s);
+        if (!n)
+                return -ENOMEM;
+
+        *ret = n;
+        return 0;
+}
+
+_public_ int sd_bus_get_property_strv(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_error *error,
+                char ***ret) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(reply, 'v', NULL);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_strv(reply, ret);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+_public_ int sd_bus_set_property(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_error *error,
+                const char *type, ...) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        va_list ap;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(signature_is_single(type, false), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(m, "ss", strempty(interface), member);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(m, 'v', type);
+        if (r < 0)
+                return r;
+
+        va_start(ap, type);
+        r = bus_message_append_ap(m, type, ap);
+        va_end(ap);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        return sd_bus_call(bus, m, 0, error, NULL);
+}
+
+_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
+        sd_bus_creds *c;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+        c = sd_bus_message_get_creds(call);
+
+        /* All data we need? */
+        if (c && (mask & ~c->mask) == 0) {
+                *creds = sd_bus_creds_ref(c);
+                return 0;
+        }
+
+        /* No data passed? Or not enough data passed to retrieve the missing bits? */
+        if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
+                /* We couldn't read anything from the call, let's try
+                 * to get it from the sender or peer */
+
+                if (call->sender)
+                        return sd_bus_get_owner(call->bus, call->sender, mask, creds);
+                else
+                        return sd_bus_get_peer_creds(call->bus, mask, creds);
+        }
+
+        return bus_creds_extend_by_pid(c, mask, creds);
+}
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
new file mode 100644
index 0000000..52e55fc
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -0,0 +1,904 @@
+/*-*- 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 <stdlib.h>
+
+#include "util.h"
+#include "cgroup-util.h"
+#include "fileio.h"
+#include "audit.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "time-util.h"
+#include "strv.h"
+#include "bus-creds.h"
+
+enum {
+        CAP_OFFSET_INHERITABLE = 0,
+        CAP_OFFSET_PERMITTED = 1,
+        CAP_OFFSET_EFFECTIVE = 2,
+        CAP_OFFSET_BOUNDING = 3
+};
+
+void bus_creds_done(sd_bus_creds *c) {
+        assert(c);
+
+        /* For internal bus cred structures that are allocated by
+         * something else */
+
+        free(c->session);
+        free(c->unit);
+        free(c->user_unit);
+        free(c->slice);
+
+        strv_free(c->cmdline_array);
+        strv_free(c->well_known_names);
+}
+
+_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
+        assert_return(c, NULL);
+
+        if (c->allocated) {
+                assert(c->n_ref > 0);
+                c->n_ref++;
+        } else {
+                sd_bus_message *m;
+
+                /* If this is an embedded creds structure, then
+                 * forward ref counting to the message */
+                m = container_of(c, sd_bus_message, creds);
+                sd_bus_message_ref(m);
+        }
+
+        return c;
+}
+
+_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
+
+        if (!c)
+                return NULL;
+
+        if (c->allocated) {
+                assert(c->n_ref > 0);
+                c->n_ref--;
+
+                if (c->n_ref == 0) {
+                        bus_creds_done(c);
+
+                        free(c->comm);
+                        free(c->tid_comm);
+                        free(c->exe);
+                        free(c->cmdline);
+                        free(c->cgroup);
+                        free(c->capability);
+                        free(c->label);
+                        free(c->unique_name);
+                        free(c->cgroup_root);
+                        free(c);
+                }
+        } else {
+                sd_bus_message *m;
+
+                m = container_of(c, sd_bus_message, creds);
+                sd_bus_message_unref(m);
+        }
+
+
+        return NULL;
+}
+
+_public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
+        assert_return(c, 0);
+
+        return c->mask;
+}
+
+sd_bus_creds* bus_creds_new(void) {
+        sd_bus_creds *c;
+
+        c = new0(sd_bus_creds, 1);
+        if (!c)
+                return NULL;
+
+        c->allocated = true;
+        c->n_ref = 1;
+        return c;
+}
+
+_public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
+        sd_bus_creds *c;
+        int r;
+
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+        assert_return(ret, -EINVAL);
+
+        if (pid == 0)
+                pid = getpid();
+
+        c = bus_creds_new();
+        if (!c)
+                return -ENOMEM;
+
+        r = bus_creds_add_more(c, mask, pid, 0);
+        if (r < 0) {
+                sd_bus_creds_unref(c);
+                return r;
+        }
+
+        /* Check if the process existed at all, in case we haven't
+         * figured that out already */
+        if (kill(pid, 0) < 0 && errno == ESRCH) {
+                sd_bus_creds_unref(c);
+                return -ESRCH;
+        }
+
+        *ret = c;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
+        assert_return(c, -EINVAL);
+        assert_return(uid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_UID))
+                return -ENODATA;
+
+        *uid = c->uid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
+        assert_return(c, -EINVAL);
+        assert_return(gid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_UID))
+                return -ENODATA;
+
+        *gid = c->gid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
+        assert_return(c, -EINVAL);
+        assert_return(pid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_PID))
+                return -ENODATA;
+
+        assert(c->pid > 0);
+        *pid = c->pid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
+        assert_return(c, -EINVAL);
+        assert_return(tid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_TID))
+                return -ENODATA;
+
+        assert(c->tid > 0);
+        *tid = c->tid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
+        assert_return(c, -EINVAL);
+        assert_return(usec, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
+                return -ENODATA;
+
+        assert(c->pid_starttime > 0);
+        *usec = c->pid_starttime;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
+                return -ENODATA;
+
+        assert(c->label);
+        *ret = c->label;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_COMM))
+                return -ENODATA;
+
+        assert(c->comm);
+        *ret = c->comm;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_TID_COMM))
+                return -ENODATA;
+
+        assert(c->tid_comm);
+        *ret = c->tid_comm;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_EXE))
+                return -ENODATA;
+
+        assert(c->exe);
+        *ret = c->exe;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_CGROUP))
+                return -ENODATA;
+
+        assert(c->cgroup);
+        *ret = c->cgroup;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_UNIT))
+                return -ENODATA;
+
+        assert(c->cgroup);
+
+        if (!c->unit) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_unit(shifted, (char**) &c->unit);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->unit;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
+                return -ENODATA;
+
+        assert(c->cgroup);
+
+        if (!c->user_unit) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->user_unit;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_SLICE))
+                return -ENODATA;
+
+        assert(c->cgroup);
+
+        if (!c->slice) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_slice(shifted, (char**) &c->slice);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->slice;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_SESSION))
+                return -ENODATA;
+
+        assert(c->cgroup);
+
+        if (!c->session) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_session(shifted, (char**) &c->session);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->session;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
+        const char *shifted;
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(uid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
+                return -ENODATA;
+
+        assert(c->cgroup);
+
+        r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+        if (r < 0)
+                return r;
+
+        return cg_path_get_owner_uid(shifted, uid);
+}
+
+_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
+        assert_return(c, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_CMDLINE))
+                return -ENODATA;
+
+        assert_return(c->cmdline, -ESRCH);
+        assert(c->cmdline);
+
+        if (!c->cmdline_array) {
+                c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
+                if (!c->cmdline_array)
+                        return -ENOMEM;
+        }
+
+        *cmdline = c->cmdline_array;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
+        assert_return(c, -EINVAL);
+        assert_return(sessionid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
+                return -ENODATA;
+
+        *sessionid = c->audit_session_id;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
+        assert_return(c, -EINVAL);
+        assert_return(uid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
+                return -ENODATA;
+
+        *uid = c->audit_login_uid;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
+        assert_return(c, -EINVAL);
+        assert_return(unique_name, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
+                return -ENODATA;
+
+        *unique_name = c->unique_name;
+        return 0;
+}
+
+_public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
+        assert_return(c, -EINVAL);
+        assert_return(well_known_names, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
+                return -ENODATA;
+
+        *well_known_names = c->well_known_names;
+        return 0;
+}
+
+static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
+        size_t sz;
+
+        assert(c);
+        assert(c->capability);
+
+        sz = c->capability_size / 4;
+        if ((size_t) capability >= sz*8)
+                return 0;
+
+        return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
+}
+
+_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
+                return -ENODATA;
+
+        return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
+}
+
+_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
+                return -ENODATA;
+
+        return has_cap(c, CAP_OFFSET_PERMITTED, capability);
+}
+
+_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
+                return -ENODATA;
+
+        return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
+}
+
+_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
+        assert_return(c, -EINVAL);
+        assert_return(capability >= 0, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
+                return -ENODATA;
+
+        return has_cap(c, CAP_OFFSET_BOUNDING, capability);
+}
+
+static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
+        size_t sz;
+        unsigned i;
+
+        assert(c);
+        assert(p);
+
+        p += strspn(p, WHITESPACE);
+
+        sz = strlen(p);
+        if (sz % 2 != 0)
+                return -EINVAL;
+
+        sz /= 2;
+        if (!c->capability) {
+                c->capability = new0(uint8_t, sz * 4);
+                if (!c->capability)
+                        return -ENOMEM;
+
+                c->capability_size = sz * 4;
+        }
+
+        for (i = 0; i < sz; i ++) {
+                int x, y;
+
+                x = unhexchar(p[i*2]);
+                y = unhexchar(p[i*2+1]);
+
+                if (x < 0 || y < 0)
+                        return -EINVAL;
+
+                c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
+        }
+
+        return 0;
+}
+
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
+        uint64_t missing;
+        int r;
+
+        assert(c);
+        assert(c->allocated);
+
+        missing = mask & ~c->mask;
+        if (missing == 0)
+                return 0;
+
+        /* Try to retrieve PID from creds if it wasn't passed to us */
+        if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
+                pid = c->pid;
+
+        if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
+                tid = c->pid;
+
+        /* Without pid we cannot do much... */
+        if (pid <= 0)
+                return 0;
+
+        if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
+                       SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
+                       SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
+
+                _cleanup_fclose_ FILE *f = NULL;
+                char line[LINE_MAX];
+                const char *p;
+
+                p = procfs_file_alloca(pid, "status");
+
+                f = fopen(p, "re");
+                if (!f)
+                        return errno == ENOENT ? -ESRCH : -errno;
+
+                FOREACH_LINE(line, f, return -errno) {
+                        truncate_nl(line);
+
+                        if (missing & SD_BUS_CREDS_UID) {
+                                p = startswith(line, "Uid:");
+                                if (p) {
+                                        unsigned long uid;
+
+                                        p += strspn(p, WHITESPACE);
+                                        if (sscanf(p, "%lu", &uid) != 1)
+                                                return -EIO;
+
+                                        c->uid = (uid_t) uid;
+                                        c->mask |= SD_BUS_CREDS_UID;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_GID) {
+                                p = startswith(line, "Gid:");
+                                if (p) {
+                                        unsigned long gid;
+
+                                        p += strspn(p, WHITESPACE);
+                                        if (sscanf(p, "%lu", &gid) != 1)
+                                                return -EIO;
+
+                                        c->gid = (uid_t) gid;
+                                        c->mask |= SD_BUS_CREDS_GID;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
+                                p = startswith(line, "CapEff:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
+                                p = startswith(line, "CapPrm:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
+                                p = startswith(line, "CapInh:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
+                                        continue;
+                                }
+                        }
+
+                        if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
+                                p = startswith(line, "CapBnd:");
+                                if (p) {
+                                        r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
+                                        if (r < 0)
+                                                return r;
+
+                                        c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
+                                        continue;
+                                }
+                        }
+                }
+        }
+
+        if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
+                unsigned long long st;
+
+                r = get_starttime_of_pid(pid, &st);
+                if (r < 0)
+                        return r;
+
+                c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
+                c->mask |= SD_BUS_CREDS_PID_STARTTIME;
+        }
+
+        if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
+                const char *p;
+
+                p = procfs_file_alloca(pid, "attr/current");
+                r = read_one_line_file(p, &c->label);
+                if (r < 0 && r != -ENOENT && r != -EINVAL)
+                        return r;
+                else if (r >= 0)
+                        c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+        }
+
+        if (missing & SD_BUS_CREDS_COMM) {
+                r = get_process_comm(pid, &c->comm);
+                if (r < 0)
+                        return r;
+
+                c->mask |= SD_BUS_CREDS_COMM;
+        }
+
+        if (missing & SD_BUS_CREDS_EXE) {
+                r = get_process_exe(pid, &c->exe);
+                if (r < 0)
+                        return r;
+
+                c->mask |= SD_BUS_CREDS_EXE;
+        }
+
+        if (missing & SD_BUS_CREDS_CMDLINE) {
+                const char *p;
+
+                p = procfs_file_alloca(pid, "cmdline");
+                r = read_full_file(p, &c->cmdline, &c->cmdline_size);
+                if (r < 0)
+                        return r;
+
+                if (c->cmdline_size == 0) {
+                        free(c->cmdline);
+                        c->cmdline = NULL;
+                } else
+                        c->mask |= SD_BUS_CREDS_CMDLINE;
+        }
+
+        if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
+                _cleanup_free_ char *p = NULL;
+
+                if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
+                        return -ENOMEM;
+
+                r = read_one_line_file(p, &c->tid_comm);
+                if (r < 0)
+                        return r == -ENOENT ? -ESRCH : r;
+
+                c->mask |= SD_BUS_CREDS_TID_COMM;
+        }
+
+        if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
+
+                r = cg_pid_get_path(NULL, pid, &c->cgroup);
+                if (r < 0)
+                        return r;
+
+                r = cg_get_root_path(&c->cgroup_root);
+                if (r < 0)
+                        return r;
+
+                c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
+        }
+
+        if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
+                r = audit_session_from_pid(pid, &c->audit_session_id);
+                if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
+                        return r;
+                else if (r >= 0)
+                        c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+        }
+
+        if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
+                r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
+                if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
+                        return r;
+                else if (r >= 0)
+                        c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+        }
+
+        return 0;
+}
+
+int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
+        int r;
+
+        assert(c);
+        assert(ret);
+
+        if ((mask & ~c->mask) == 0) {
+                /* There's already all data we need. */
+
+                *ret = sd_bus_creds_ref(c);
+                return 0;
+        }
+
+        n = bus_creds_new();
+        if (!n)
+                return -ENOMEM;
+
+        /* Copy the original data over */
+
+        if (c->mask & mask & SD_BUS_CREDS_UID) {
+                n->uid = c->uid;
+                n->mask |= SD_BUS_CREDS_UID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_GID) {
+                n->gid = c->gid;
+                n->mask |= SD_BUS_CREDS_GID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_PID) {
+                n->pid = c->pid;
+                n->mask |= SD_BUS_CREDS_PID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_TID) {
+                n->tid = c->tid;
+                n->mask |= SD_BUS_CREDS_TID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
+                n->pid_starttime = c->pid_starttime;
+                n->mask |= SD_BUS_CREDS_PID_STARTTIME;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_COMM) {
+                n->comm = strdup(c->comm);
+                if (!n->comm)
+                        return -ENOMEM;
+
+                n->mask |= SD_BUS_CREDS_COMM;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
+                n->tid_comm = strdup(c->tid_comm);
+                if (!n->tid_comm)
+                        return -ENOMEM;
+
+                n->mask |= SD_BUS_CREDS_TID_COMM;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_EXE) {
+                n->exe = strdup(c->exe);
+                if (!n->exe)
+                        return -ENOMEM;
+
+                n->mask |= SD_BUS_CREDS_EXE;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
+                n->cmdline = memdup(c->cmdline, c->cmdline_size);
+                if (!n->cmdline)
+                        return -ENOMEM;
+
+                n->cmdline_size = c->cmdline_size;
+                n->mask |= SD_BUS_CREDS_CMDLINE;
+        }
+
+        if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) {
+                n->cgroup = strdup(c->cgroup);
+                if (!n->cgroup)
+                        return -ENOMEM;
+
+                n->cgroup_root = strdup(c->cgroup_root);
+                if (!n->cgroup_root)
+                        return -ENOMEM;
+
+                n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID);
+        }
+
+        if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
+                n->capability = memdup(c->capability, c->capability_size);
+                if (!n->capability)
+                        return -ENOMEM;
+
+                n->capability_size = c->capability_size;
+                n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
+                n->audit_session_id = c->audit_session_id;
+                n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
+                n->audit_login_uid = c->audit_login_uid;
+                n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
+                n->unique_name = strdup(c->unique_name);
+                if (!n->unique_name)
+                        return -ENOMEM;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
+                n->well_known_names = strv_copy(c->well_known_names);
+                if (!n->well_known_names)
+                        return -ENOMEM;
+        }
+
+        /* Get more data */
+
+        r = bus_creds_add_more(n, mask,
+                               c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
+                               c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
+        if (r < 0)
+                return r;
+
+        *ret = n;
+        n = NULL;
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
new file mode 100644
index 0000000..d8b4aca
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -0,0 +1,75 @@
+/*-*- 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 <stdbool.h>
+
+#include "sd-bus.h"
+#include "time-util.h"
+
+struct sd_bus_creds {
+        bool allocated;
+        unsigned n_ref;
+        uint64_t mask;
+
+        uid_t uid;
+        gid_t gid;
+        pid_t pid;
+        usec_t pid_starttime;
+        pid_t tid;
+
+        char *comm;
+        char *tid_comm;
+        char *exe;
+
+        char *cmdline;
+        size_t cmdline_size;
+        char **cmdline_array;
+
+        char *cgroup;
+        char *session;
+        char *unit;
+        char *user_unit;
+        char *slice;
+
+        uint8_t *capability;
+        size_t capability_size;
+
+        uint32_t audit_session_id;
+        uid_t audit_login_uid;
+
+        char *label;
+
+        char *unique_name;
+
+        char **well_known_names;
+
+        char *cgroup_root;
+};
+
+sd_bus_creds* bus_creds_new(void);
+
+void bus_creds_done(sd_bus_creds *c);
+
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid);
+
+int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret);
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
new file mode 100644
index 0000000..78e7597
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -0,0 +1,417 @@
+/*-*- 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 "util.h"
+#include "capability.h"
+#include "strv.h"
+#include "audit.h"
+
+#include "bus-message.h"
+#include "bus-internal.h"
+#include "bus-type.h"
+#include "bus-dump.h"
+
+static char *indent(unsigned level) {
+        char *p;
+
+        p = new(char, 2 + level + 1);
+        if (!p)
+                return NULL;
+
+        p[0] = p[1] = ' ';
+        memset(p + 2, '\t', level);
+        p[2 + level] = 0;
+
+        return p;
+}
+
+int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
+        unsigned level = 1;
+        int r;
+
+        assert(m);
+
+        if (!f)
+                f = stdout;
+
+        if (with_header) {
+                fprintf(f,
+                        "%s%s%sType=%s%s%s  Endian=%c  Flags=%u  Version=%u",
+                        m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
+                        m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
+                        m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
+                        ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
+                        m->header->endian,
+                        m->header->flags,
+                        m->header->version);
+
+                /* Display synthetic message serial number in a more readable
+                 * format than (uint32_t) -1 */
+                if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
+                        fprintf(f, " Cookie=-1");
+                else
+                        fprintf(f, " Cookie=%lu", (unsigned long) BUS_MESSAGE_COOKIE(m));
+
+                if (m->reply_cookie != 0)
+                        fprintf(f, "  ReplyCookie=%lu", (unsigned long) m->reply_cookie);
+
+                fputs("\n", f);
+
+                if (m->sender)
+                        fprintf(f, "  Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
+                if (m->destination)
+                        fprintf(f, "  Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
+                if (m->path)
+                        fprintf(f, "  Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
+                if (m->interface)
+                        fprintf(f, "  Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
+                if (m->member)
+                        fprintf(f, "  Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
+
+                if (m->sender || m->destination || m->path || m->interface || m->member)
+                        fputs("\n", f);
+
+                if (sd_bus_error_is_set(&m->error))
+                        fprintf(f,
+                                "  ErrorName=%s%s%s"
+                                "  ErrorMessage=%s\"%s\"%s\n",
+                                ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
+                                ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
+
+                if (m->monotonic != 0)
+                        fprintf(f, "  Monotonic=%llu", (unsigned long long) m->monotonic);
+                if (m->realtime != 0)
+                        fprintf(f, "  Realtime=%llu", (unsigned long long) m->realtime);
+
+                if (m->monotonic != 0 || m->realtime != 0)
+                        fputs("\n", f);
+
+                bus_creds_dump(&m->creds, f);
+        }
+
+        r = sd_bus_message_rewind(m, true);
+        if (r < 0) {
+                log_error("Failed to rewind: %s", strerror(-r));
+                return r;
+        }
+
+        fprintf(f, "  MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
+
+        for (;;) {
+                _cleanup_free_ char *prefix = NULL;
+                const char *contents = NULL;
+                char type;
+                union {
+                        uint8_t u8;
+                        uint16_t u16;
+                        int16_t s16;
+                        uint32_t u32;
+                        int32_t s32;
+                        uint64_t u64;
+                        int64_t s64;
+                        double d64;
+                        const char *string;
+                        int i;
+                } basic;
+
+                r = sd_bus_message_peek_type(m, &type, &contents);
+                if (r < 0) {
+                        log_error("Failed to peek type: %s", strerror(-r));
+                        return r;
+                }
+
+                if (r == 0) {
+                        if (level <= 1)
+                                break;
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0) {
+                                log_error("Failed to exit container: %s", strerror(-r));
+                                return r;
+                        }
+
+                        level--;
+
+                        prefix = indent(level);
+                        if (!prefix)
+                                return log_oom();
+
+                        fprintf(f, "%s};\n", prefix);
+                        continue;
+                }
+
+                prefix = indent(level);
+                if (!prefix)
+                        return log_oom();
+
+                if (bus_type_is_container(type) > 0) {
+                        r = sd_bus_message_enter_container(m, type, contents);
+                        if (r < 0) {
+                                log_error("Failed to enter container: %s", strerror(-r));
+                                return r;
+                        }
+
+                        if (type == SD_BUS_TYPE_ARRAY)
+                                fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
+                        else if (type == SD_BUS_TYPE_VARIANT)
+                                fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
+                        else if (type == SD_BUS_TYPE_STRUCT)
+                                fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
+                        else if (type == SD_BUS_TYPE_DICT_ENTRY)
+                                fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
+
+                        level ++;
+
+                        continue;
+                }
+
+                r = sd_bus_message_read_basic(m, type, &basic);
+                if (r < 0) {
+                        log_error("Failed to get basic: %s", strerror(-r));
+                        return r;
+                }
+
+                assert(r > 0);
+
+                switch (type) {
+
+                case SD_BUS_TYPE_BYTE:
+                        fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_BOOLEAN:
+                        fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_INT16:
+                        fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_UINT16:
+                        fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_INT32:
+                        fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_UINT32:
+                        fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_INT64:
+                        fprintf(f, "%sINT64 %s%lli%s;\n", prefix, ansi_highlight(), (long long) basic.s64, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_UINT64:
+                        fprintf(f, "%sUINT64 %s%llu%s;\n", prefix, ansi_highlight(), (unsigned long long) basic.u64, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_DOUBLE:
+                        fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_STRING:
+                        fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_OBJECT_PATH:
+                        fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_SIGNATURE:
+                        fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
+                        break;
+
+                case SD_BUS_TYPE_UNIX_FD:
+                        fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
+                        break;
+
+                default:
+                        assert_not_reached("Unknown basic type.");
+                }
+        }
+
+        fprintf(f, "  };\n\n");
+        return 0;
+}
+
+static void dump_capabilities(
+                sd_bus_creds *c,
+                FILE *f,
+                const char *name,
+                int (*has)(sd_bus_creds *c, int capability)) {
+
+        unsigned long i, last_cap;
+        unsigned n = 0;
+        int r;
+
+        assert(c);
+        assert(f);
+        assert(name);
+        assert(has);
+
+        i = 0;
+        r = has(c, i);
+        if (r < 0)
+                return;
+
+        fprintf(f, "  %s=", name);
+        last_cap = cap_last_cap();
+
+        for (;;) {
+                if (r > 0) {
+                        _cleanup_cap_free_charp_ char *t;
+
+                        if (n > 0)
+                                fputc(' ', f);
+                        if (n % 4 == 3)
+                                fputs("\n          ", f);
+
+                        t = cap_to_name(i);
+                        fprintf(f, "%s", t);
+                        n++;
+                }
+
+                i++;
+
+                if (i > last_cap)
+                        break;
+
+                r = has(c, i);
+        }
+
+        fputs("\n", f);
+}
+
+int bus_creds_dump(sd_bus_creds *c, FILE *f) {
+        bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
+        const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
+        uid_t owner, audit_loginuid;
+        uint32_t audit_sessionid;
+        char **cmdline = NULL, **well_known = NULL;
+        int r;
+
+        assert(c);
+
+        if (!f)
+                f = stdout;
+
+        if (c->mask & SD_BUS_CREDS_PID)
+                fprintf(f, "  PID=%lu", (unsigned long) c->pid);
+        if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
+                fprintf(f, "  PIDStartTime=%llu", (unsigned long long) c->pid_starttime);
+        if (c->mask & SD_BUS_CREDS_TID)
+                fprintf(f, "  TID=%lu", (unsigned long) c->tid);
+        if (c->mask & SD_BUS_CREDS_UID)
+                fprintf(f, "  UID=%lu", (unsigned long) c->uid);
+        r = sd_bus_creds_get_owner_uid(c, &owner);
+        if (r >= 0)
+                fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
+        if (c->mask & SD_BUS_CREDS_GID)
+                fprintf(f, "  GID=%lu", (unsigned long) c->gid);
+
+        if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0)
+                fputs("\n", f);
+
+        if (c->mask & SD_BUS_CREDS_EXE)
+                fprintf(f, "  Exe=%s", c->exe);
+        if (c->mask & SD_BUS_CREDS_COMM)
+                fprintf(f, "  Comm=%s", c->comm);
+        if (c->mask & SD_BUS_CREDS_TID_COMM)
+                fprintf(f, "  TIDComm=%s", c->tid_comm);
+        if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
+                fprintf(f, "  Label=%s", c->label);
+
+        if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_SELINUX_CONTEXT))
+                fputs("\n", f);
+
+        if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
+                char **i;
+
+                fputs("  CommandLine={", f);
+                STRV_FOREACH(i, cmdline) {
+                        if (i != cmdline)
+                                fputc(' ', f);
+
+                        fputs(*i, f);
+                }
+
+                fputs("}\n", f);
+        }
+
+        if (c->mask & SD_BUS_CREDS_CGROUP)
+                fprintf(f, "  CGroup=%s", c->cgroup);
+        sd_bus_creds_get_unit(c, &u);
+        if (u)
+                fprintf(f, "  Unit=%s", u);
+        sd_bus_creds_get_user_unit(c, &uu);
+        if (uu)
+                fprintf(f, "  UserUnit=%s", uu);
+        sd_bus_creds_get_slice(c, &sl);
+        if (sl)
+                fprintf(f, "  Slice=%s", sl);
+        sd_bus_creds_get_session(c, &s);
+        if (s)
+                fprintf(f, "  Session=%s", s);
+
+        if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
+                fputs("\n", f);
+
+        if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
+                audit_loginuid_is_set = true;
+                fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
+        }
+        if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
+                audit_sessionid_is_set = true;
+                fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
+        }
+
+        if (audit_loginuid_is_set || audit_sessionid_is_set)
+                fputs("\n", f);
+
+        if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
+                fprintf(f, "  UniqueName=%s", c->unique_name);
+
+        if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
+                char **i;
+
+                fputs("  WellKnownNames={", f);
+                STRV_FOREACH(i, well_known) {
+                        if (i != well_known)
+                                fputc(' ', f);
+
+                        fputs(*i, f);
+                }
+
+                fputc('}', f);
+        }
+
+        if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
+                fputc('\n', f);
+
+        dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
+        dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
+        dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
+        dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h
new file mode 100644
index 0000000..bb1d25d
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-dump.h
@@ -0,0 +1,31 @@
+/*-*- 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 <stdio.h>
+#include <stdbool.h>
+
+#include "sd-bus.h"
+
+int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header);
+
+int bus_creds_dump(sd_bus_creds *c, FILE *f);
diff --git a/src/libsystemd/sd-bus/bus-error-mapping.gperf b/src/libsystemd/sd-bus/bus-error-mapping.gperf
new file mode 100644
index 0000000..df2c4d4
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-error-mapping.gperf
@@ -0,0 +1,49 @@
+%{
+#include <errno.h>
+#include "bus-error.h"
+%}
+name_error_mapping;
+%null_strings
+%language=ANSI-C
+%define slot-name name
+%define hash-function-name bus_error_mapping_hash
+%define lookup-function-name bus_error_mapping_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+org.freedesktop.DBus.Error.Failed,                        EACCES
+org.freedesktop.DBus.Error.NoMemory,                      ENOMEM
+org.freedesktop.DBus.Error.ServiceUnknown,                EHOSTUNREACH
+org.freedesktop.DBus.Error.NameHasNoOwner,                ENXIO
+org.freedesktop.DBus.Error.NoReply,                       ETIMEDOUT
+org.freedesktop.DBus.Error.IOError,                       EIO
+org.freedesktop.DBus.Error.BadAddress,                    EADDRNOTAVAIL
+org.freedesktop.DBus.Error.NotSupported,                  ENOTSUP
+org.freedesktop.DBus.Error.LimitsExceeded,                ENOBUFS
+org.freedesktop.DBus.Error.AccessDenied,                  EACCES
+org.freedesktop.DBus.Error.AuthFailed,                    EACCES
+org.freedesktop.DBus.Error.NoServer,                      EHOSTDOWN
+org.freedesktop.DBus.Error.Timeout,                       ETIMEDOUT
+org.freedesktop.DBus.Error.NoNetwork,                     ENONET
+org.freedesktop.DBus.Error.AddressInUse,                  EADDRINUSE
+org.freedesktop.DBus.Error.Disconnected,                  ECONNRESET
+org.freedesktop.DBus.Error.InvalidArgs,                   EINVAL
+org.freedesktop.DBus.Error.FileNotFound,                  ENOENT
+org.freedesktop.DBus.Error.FileExists,                    EEXIST
+org.freedesktop.DBus.Error.UnknownMethod,                 EBADR
+org.freedesktop.DBus.Error.UnknownObject,                 EBADR
+org.freedesktop.DBus.Error.UnknownInterface,              EBADR
+org.freedesktop.DBus.Error.UnknownProperty,               EBADR
+org.freedesktop.DBus.Error.PropertyReadOnly,              EROFS
+org.freedesktop.DBus.Error.UnixProcessIdUnknown,          ESRCH
+org.freedesktop.DBus.Error.InvalidSignature,              EINVAL
+org.freedesktop.DBus.Error.InconsistentMessage,           EBADMSG
+#
+org.freedesktop.DBus.Error.TimedOut,                      ETIMEDOUT
+org.freedesktop.DBus.Error.MatchRuleInvalid,              EINVAL
+org.freedesktop.DBus.Error.InvalidFileContent,            EINVAL
+org.freedesktop.DBus.Error.MatchRuleNotFound,             ENOENT
+org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown, ESRCH
+org.freedesktop.DBus.Error.ObjectPathInUse,               EBUSY
diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
new file mode 100644
index 0000000..c2e41fb
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -0,0 +1,504 @@
+/*-*- 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 <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "errno-list.h"
+
+#include "sd-bus.h"
+#include "bus-error.h"
+
+#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
+#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
+
+static int bus_error_name_to_errno(const char *name) {
+        const char *p;
+        int r;
+        const name_error_mapping *m;
+
+        if (!name)
+                return EINVAL;
+
+        p = startswith(name, "System.Error.");
+        if (p) {
+                r = errno_from_name(p);
+                if (r <= 0)
+                        return EIO;
+
+                return r;
+        }
+
+        m = bus_error_mapping_lookup(name, strlen(name));
+        if (m)
+                return m->code;
+
+        return EIO;
+}
+
+static sd_bus_error errno_to_bus_error_const(int error) {
+
+        if (error < 0)
+                error = -error;
+
+        switch (error) {
+
+        case ENOMEM:
+                return BUS_ERROR_OOM;
+
+        case EPERM:
+        case EACCES:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
+
+        case EINVAL:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
+
+        case ESRCH:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
+
+        case ENOENT:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
+
+        case EEXIST:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
+
+        case ETIMEDOUT:
+        case ETIME:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
+
+        case EIO:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
+
+        case ENETRESET:
+        case ECONNABORTED:
+        case ECONNRESET:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
+
+        case ENOTSUP:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
+
+        case EADDRNOTAVAIL:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
+
+        case ENOBUFS:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
+
+        case EADDRINUSE:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
+
+        case EBADMSG:
+                return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
+        }
+
+        return SD_BUS_ERROR_NULL;
+}
+
+static int errno_to_bus_error_name_new(int error, char **ret) {
+        const char *name;
+        char *n;
+
+        if (error < 0)
+                error = -error;
+
+        name = errno_to_name(error);
+        if (!name)
+                return 0;
+
+        n = strappend("System.Error.", name);
+        if (!n)
+                return -ENOMEM;
+
+        *ret = n;
+        return 1;
+}
+
+bool bus_error_is_dirty(sd_bus_error *e) {
+        if (!e)
+                return false;
+
+        return e->name || e->message || e->_need_free != 0;
+}
+
+_public_ void sd_bus_error_free(sd_bus_error *e) {
+        if (!e)
+                return;
+
+        if (e->_need_free > 0) {
+                free((void*) e->name);
+                free((void*) e->message);
+        }
+
+        e->name = e->message = NULL;
+        e->_need_free = 0;
+}
+
+_public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
+
+        if (!name)
+                return 0;
+        if (!e)
+                goto finish;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        e->name = strdup(name);
+        if (!e->name) {
+                *e = BUS_ERROR_OOM;
+                return -ENOMEM;
+        }
+
+        if (message)
+                e->message = strdup(message);
+
+        e->_need_free = 1;
+
+finish:
+        return -bus_error_name_to_errno(name);
+}
+
+int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
+
+        if (!name)
+                return 0;
+        if (!e)
+                goto finish;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        e->name = strdup(name);
+        if (!e->name) {
+                *e = BUS_ERROR_OOM;
+                return -ENOMEM;
+        }
+
+        if (format)
+                vasprintf((char**) &e->message, format, ap);
+
+        e->_need_free = 1;
+
+finish:
+        return -bus_error_name_to_errno(name);
+}
+
+_public_ 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);
+}
+
+_public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
+
+        if (!sd_bus_error_is_set(e))
+                return 0;
+        if (!dest)
+                goto finish;
+
+        assert_return(!bus_error_is_dirty(dest), -EINVAL);
+
+        /*
+         * _need_free  < 0 indicates that the error is temporarily const, needs deep copying
+         * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
+         * _need_free  > 0 indicates that the error is fully dynamic, needs deep copying
+         */
+
+        if (e->_need_free == 0)
+                *dest = *e;
+        else {
+                dest->name = strdup(e->name);
+                if (!dest->name) {
+                        *dest = BUS_ERROR_OOM;
+                        return -ENOMEM;
+                }
+
+                if (e->message)
+                        dest->message = strdup(e->message);
+
+                dest->_need_free = 1;
+        }
+
+finish:
+        return -bus_error_name_to_errno(e->name);
+}
+
+_public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
+        if (!name)
+                return 0;
+        if (!e)
+                goto finish;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        *e = SD_BUS_ERROR_MAKE_CONST(name, message);
+
+finish:
+        return -bus_error_name_to_errno(name);
+}
+
+_public_ int sd_bus_error_is_set(const sd_bus_error *e) {
+        if (!e)
+                return 0;
+
+        return !!e->name;
+}
+
+_public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
+        if (!e)
+                return 0;
+
+        return streq_ptr(e->name, name);
+}
+
+_public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
+        if (!e)
+                return 0;
+
+        if (!e->name)
+                return 0;
+
+        return bus_error_name_to_errno(e->name);
+}
+
+static void bus_error_strerror(sd_bus_error *e, int error) {
+        size_t k = 64;
+        char *m;
+
+        assert(e);
+
+        for (;;) {
+                char *x;
+
+                m = new(char, k);
+                if (!m)
+                        return;
+
+                errno = 0;
+                x = strerror_r(error, m, k);
+                if (errno == ERANGE || strlen(x) >= k - 1) {
+                        free(m);
+                        k *= 2;
+                        continue;
+                }
+
+                if (!x || errno) {
+                        free(m);
+                        return;
+                }
+
+                if (x == m) {
+                        if (e->_need_free > 0) {
+                                /* Error is already dynamic, let's just update the message */
+                                free((char*) e->message);
+                                e->message = x;
+
+                        } else {
+                                char *t;
+                                /* Error was const so far, let's make it dynamic, if we can */
+
+                                t = strdup(e->name);
+                                if (!t) {
+                                        free(m);
+                                        return;
+                                }
+
+                                e->_need_free = 1;
+                                e->name = t;
+                                e->message = x;
+                        }
+                } else {
+                        free(m);
+
+                        if (e->_need_free > 0) {
+                                char *t;
+
+                                /* Error is dynamic, let's hence make the message also dynamic */
+                                t = strdup(x);
+                                if (!t)
+                                        return;
+
+                                free((char*) e->message);
+                                e->message = t;
+                        } else {
+                                /* Error is const, hence we can just override */
+                                e->message = x;
+                        }
+                }
+
+                return;
+        }
+}
+
+_public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
+
+        if (error < 0)
+                error = -error;
+
+        if (!e)
+                return -error;
+        if (error == 0)
+                return -error;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        /* First, try a const translation */
+        *e = errno_to_bus_error_const(error);
+
+        if (!sd_bus_error_is_set(e)) {
+                int k;
+
+                /* If that didn't work, try a dynamic one. */
+
+                k = errno_to_bus_error_name_new(error, (char**) &e->name);
+                if (k > 0)
+                        e->_need_free = 1;
+                else if (k < 0) {
+                        *e = BUS_ERROR_OOM;
+                        return -error;
+                } else
+                        *e = BUS_ERROR_FAILED;
+        }
+
+        /* Now, fill in the message from strerror() if we can */
+        bus_error_strerror(e, error);
+        return -error;
+}
+
+int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
+        int r;
+
+        if (error < 0)
+                error = -error;
+
+        if (!e)
+                return -error;
+        if (error == 0)
+                return 0;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        /* First, try a const translation */
+        *e = errno_to_bus_error_const(error);
+
+        if (!sd_bus_error_is_set(e)) {
+                int k;
+
+                /* If that didn't work, try a dynamic one */
+
+                k = errno_to_bus_error_name_new(error, (char**) &e->name);
+                if (k > 0)
+                        e->_need_free = 1;
+                else if (k < 0) {
+                        *e = BUS_ERROR_OOM;
+                        return -ENOMEM;
+                } else
+                        *e = BUS_ERROR_FAILED;
+        }
+
+        if (format) {
+                char *m;
+
+                /* First, let's try to fill in the supplied message */
+
+                r = vasprintf(&m, format, ap);
+                if (r >= 0) {
+
+                        if (e->_need_free <= 0) {
+                                char *t;
+
+                                t = strdup(e->name);
+                                if (t) {
+                                        e->_need_free = 1;
+                                        e->name = t;
+                                        e->message = m;
+                                        return -error;
+                                }
+
+                                free(m);
+                        } else {
+                                free((char*) e->message);
+                                e->message = m;
+                                return -error;
+                        }
+                }
+        }
+
+        /* If that didn't work, use strerror() for the message */
+        bus_error_strerror(e, error);
+        return -error;
+}
+
+_public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
+        int r;
+
+        if (error < 0)
+                error = -error;
+
+        if (!e)
+                return -error;
+        if (error == 0)
+                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 (e) {
+                /* Sometimes the D-Bus server is a little bit too verbose with
+                 * its error messages, so let's override them here */
+                if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
+                        return "Access denied";
+
+                if (e->message)
+                        return e->message;
+        }
+
+        if (error < 0)
+                error = -error;
+
+        return strerror(error);
+}
diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h
new file mode 100644
index 0000000..cf0ad9d
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-error.h
@@ -0,0 +1,42 @@
+/*-*- 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 <stdbool.h>
+
+#include "sd-bus.h"
+#include "macro.h"
+
+struct name_error_mapping {
+        const char* name;
+        int code;
+};
+typedef struct name_error_mapping name_error_mapping;
+
+const name_error_mapping* bus_error_mapping_lookup(const char *str, unsigned int len);
+
+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) _printf_(3,0);
+int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) _printf_(3,0);
diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c
new file mode 100644
index 0000000..dc40009
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-gvariant.c
@@ -0,0 +1,249 @@
+/*-*- 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 "util.h"
+#include "bus-type.h"
+#include "bus-gvariant.h"
+#include "bus-signature.h"
+
+int bus_gvariant_get_size(const char *signature) {
+        const char *p;
+        int sum = 0, r;
+
+        /* For fixed size structs. Fails for variable size structs. */
+
+        p = signature;
+        while (*p != 0) {
+                size_t n;
+
+                r = signature_element_length(p, &n);
+                if (r < 0)
+                        return r;
+                else {
+                        char t[n+1];
+
+                        memcpy(t, p, n);
+                        t[n] = 0;
+
+                        r = bus_gvariant_get_alignment(t);
+                        if (r < 0)
+                                return r;
+
+                        sum = ALIGN_TO(sum, r);
+                }
+
+                switch (*p) {
+
+                case SD_BUS_TYPE_BOOLEAN:
+                case SD_BUS_TYPE_BYTE:
+                        sum += 1;
+                        break;
+
+                case SD_BUS_TYPE_INT16:
+                case SD_BUS_TYPE_UINT16:
+                        sum += 2;
+                        break;
+
+                case SD_BUS_TYPE_INT32:
+                case SD_BUS_TYPE_UINT32:
+                case SD_BUS_TYPE_UNIX_FD:
+                        sum += 4;
+                        break;
+
+                case SD_BUS_TYPE_INT64:
+                case SD_BUS_TYPE_UINT64:
+                case SD_BUS_TYPE_DOUBLE:
+                        sum += 8;
+                        break;
+
+                case SD_BUS_TYPE_STRUCT_BEGIN:
+                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                        char t[n-1];
+
+                        memcpy(t, p + 1, n - 2);
+                        t[n - 2] = 0;
+
+                        r = bus_gvariant_get_size(t);
+                        if (r < 0)
+                                return r;
+
+                        sum += r;
+                        break;
+                }
+
+                case SD_BUS_TYPE_STRING:
+                case SD_BUS_TYPE_OBJECT_PATH:
+                case SD_BUS_TYPE_SIGNATURE:
+                case SD_BUS_TYPE_ARRAY:
+                case SD_BUS_TYPE_VARIANT:
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unknown signature type");
+                }
+
+                p += n;
+        }
+
+        r = bus_gvariant_get_alignment(signature);
+        if (r < 0)
+                return r;
+
+        return ALIGN_TO(sum, r);
+}
+
+int bus_gvariant_get_alignment(const char *signature) {
+        size_t alignment = 1;
+        const char *p;
+        int r;
+
+        p = signature;
+        while (*p != 0 && alignment < 8) {
+                size_t n;
+                int a;
+
+                r = signature_element_length(p, &n);
+                if (r < 0)
+                        return r;
+
+                switch (*p) {
+
+                case SD_BUS_TYPE_BYTE:
+                case SD_BUS_TYPE_BOOLEAN:
+                case SD_BUS_TYPE_STRING:
+                case SD_BUS_TYPE_OBJECT_PATH:
+                case SD_BUS_TYPE_SIGNATURE:
+                        a = 1;
+                        break;
+
+                case SD_BUS_TYPE_INT16:
+                case SD_BUS_TYPE_UINT16:
+                        a = 2;
+                        break;
+
+                case SD_BUS_TYPE_INT32:
+                case SD_BUS_TYPE_UINT32:
+                case SD_BUS_TYPE_UNIX_FD:
+                        a = 4;
+                        break;
+
+                case SD_BUS_TYPE_INT64:
+                case SD_BUS_TYPE_UINT64:
+                case SD_BUS_TYPE_DOUBLE:
+                case SD_BUS_TYPE_VARIANT:
+                        a = 8;
+                        break;
+
+                case SD_BUS_TYPE_ARRAY: {
+                        char t[n];
+
+                        memcpy(t, p + 1, n - 1);
+                        t[n - 1] = 0;
+
+                        a = bus_gvariant_get_alignment(t);
+                        break;
+                }
+
+                case SD_BUS_TYPE_STRUCT_BEGIN:
+                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                        char t[n-1];
+
+                        memcpy(t, p + 1, n - 2);
+                        t[n - 2] = 0;
+
+                        a = bus_gvariant_get_alignment(t);
+                        break;
+                }
+
+                default:
+                        assert_not_reached("Unknown signature type");
+                }
+
+                if (a < 0)
+                        return a;
+
+                assert(a > 0 && a <= 8);
+                if ((size_t) a > alignment)
+                        alignment = (size_t) a;
+
+                p += n;
+        }
+
+        return alignment;
+}
+
+int bus_gvariant_is_fixed_size(const char *signature) {
+        const char *p;
+        int r;
+
+        assert(signature);
+
+        p = signature;
+        while (*p != 0) {
+                size_t n;
+
+                r = signature_element_length(p, &n);
+                if (r < 0)
+                        return r;
+
+                switch (*p) {
+
+                case SD_BUS_TYPE_STRING:
+                case SD_BUS_TYPE_OBJECT_PATH:
+                case SD_BUS_TYPE_SIGNATURE:
+                case SD_BUS_TYPE_ARRAY:
+                case SD_BUS_TYPE_VARIANT:
+                        return 0;
+
+                case SD_BUS_TYPE_BYTE:
+                case SD_BUS_TYPE_BOOLEAN:
+                case SD_BUS_TYPE_INT16:
+                case SD_BUS_TYPE_UINT16:
+                case SD_BUS_TYPE_INT32:
+                case SD_BUS_TYPE_UINT32:
+                case SD_BUS_TYPE_UNIX_FD:
+                case SD_BUS_TYPE_INT64:
+                case SD_BUS_TYPE_UINT64:
+                case SD_BUS_TYPE_DOUBLE:
+                        break;
+
+                case SD_BUS_TYPE_STRUCT_BEGIN:
+                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                        char t[n-1];
+
+                        memcpy(t, p + 1, n - 2);
+                        t[n - 2] = 0;
+
+                        r = bus_gvariant_is_fixed_size(t);
+                        if (r <= 0)
+                                return r;
+                        break;
+                }
+
+                default:
+                        assert_not_reached("Unknown signature type");
+                }
+
+                p += n;
+        }
+
+        return true;
+}
diff --git a/src/libsystemd/sd-bus/bus-gvariant.h b/src/libsystemd/sd-bus/bus-gvariant.h
new file mode 100644
index 0000000..b4bd2a5
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-gvariant.h
@@ -0,0 +1,26 @@
+/*-*- 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/>.
+***/
+
+int bus_gvariant_get_size(const char *signature) _pure_;
+int bus_gvariant_get_alignment(const char *signature) _pure_;
+int bus_gvariant_is_fixed_size(const char *signature) _pure_;
diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c
new file mode 100644
index 0000000..0bea8ca
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-internal.c
@@ -0,0 +1,305 @@
+/*-*- 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 "bus-internal.h"
+
+bool object_path_is_valid(const char *p) {
+        const char *q;
+        bool slash;
+
+        if (!p)
+                return false;
+
+        if (p[0] != '/')
+                return false;
+
+        if (p[1] == 0)
+                return true;
+
+        for (slash = true, q = p+1; *q; q++)
+                if (*q == '/') {
+                        if (slash)
+                                return false;
+
+                        slash = true;
+                } else {
+                        bool good;
+
+                        good =
+                                (*q >= 'a' && *q <= 'z') ||
+                                (*q >= 'A' && *q <= 'Z') ||
+                                (*q >= '0' && *q <= '9') ||
+                                *q == '_';
+
+                        if (!good)
+                                return false;
+
+                        slash = false;
+                }
+
+        if (slash)
+                return false;
+
+        return true;
+}
+
+char* object_path_startswith(const char *a, const char *b) {
+        const char *p;
+
+        if (!object_path_is_valid(a) ||
+            !object_path_is_valid(b))
+                return NULL;
+
+        if (streq(b, "/"))
+                return (char*) a + 1;
+
+        p = startswith(a, b);
+        if (!p)
+                return NULL;
+
+        if (*p == 0)
+                return (char*) p;
+
+        if (*p == '/')
+                return (char*) p + 1;
+
+        return NULL;
+}
+
+bool interface_name_is_valid(const char *p) {
+        const char *q;
+        bool dot, found_dot = false;
+
+        if (isempty(p))
+                return false;
+
+        for (dot = true, q = p; *q; q++)
+                if (*q == '.') {
+                        if (dot)
+                                return false;
+
+                        found_dot = dot = true;
+                } else {
+                        bool good;
+
+                        good =
+                                (*q >= 'a' && *q <= 'z') ||
+                                (*q >= 'A' && *q <= 'Z') ||
+                                (!dot && *q >= '0' && *q <= '9') ||
+                                *q == '_';
+
+                        if (!good)
+                                return false;
+
+                        dot = false;
+                }
+
+        if (q - p > 255)
+                return false;
+
+        if (dot)
+                return false;
+
+        if (!found_dot)
+                return false;
+
+        return true;
+}
+
+bool service_name_is_valid(const char *p) {
+        const char *q;
+        bool dot, found_dot = false, unique;
+
+        if (isempty(p))
+                return false;
+
+        unique = p[0] == ':';
+
+        for (dot = true, q = unique ? p+1 : p; *q; q++)
+                if (*q == '.') {
+                        if (dot)
+                                return false;
+
+                        found_dot = dot = true;
+                } else {
+                        bool good;
+
+                        good =
+                                (*q >= 'a' && *q <= 'z') ||
+                                (*q >= 'A' && *q <= 'Z') ||
+                                ((!dot || unique) && *q >= '0' && *q <= '9') ||
+                                *q == '_' || *q == '-';
+
+                        if (!good)
+                                return false;
+
+                        dot = false;
+                }
+
+        if (q - p > 255)
+                return false;
+
+        if (dot)
+                return false;
+
+        if (!found_dot)
+                return false;
+
+        return true;
+}
+
+bool member_name_is_valid(const char *p) {
+        const char *q;
+
+        if (isempty(p))
+                return false;
+
+        for (q = p; *q; q++) {
+                bool good;
+
+                good =
+                        (*q >= 'a' && *q <= 'z') ||
+                        (*q >= 'A' && *q <= 'Z') ||
+                        (*q >= '0' && *q <= '9') ||
+                        *q == '_';
+
+                if (!good)
+                        return false;
+        }
+
+        if (q - p > 255)
+                return false;
+
+        return true;
+}
+
+static bool complex_pattern_check(char c, const char *a, const char *b) {
+        bool separator = false;
+
+        if (!a && !b)
+                return true;
+
+        if (!a || !b)
+                return false;
+
+        for (;;) {
+                if (*a != *b)
+                        return (separator && (*a == 0 || *b == 0)) ||
+                                (*a == 0 && *b == c && b[1] == 0) ||
+                                (*b == 0 && *a == c && a[1] == 0);
+
+                if (*a == 0)
+                        return true;
+
+                separator = *a == c;
+
+                a++, b++;
+        }
+}
+
+bool namespace_complex_pattern(const char *pattern, const char *value) {
+        return complex_pattern_check('.', pattern, value);
+}
+
+bool path_complex_pattern(const char *pattern, const char *value) {
+        return complex_pattern_check('/', pattern, value);
+}
+
+static bool simple_pattern_check(char c, const char *a, const char *b) {
+
+        if (!a && !b)
+                return true;
+
+        if (!a || !b)
+                return false;
+
+        for (;;) {
+                if (*a != *b)
+                        return *a == 0 && *b == c;
+
+                if (*a == 0)
+                        return true;
+
+                a++, b++;
+        }
+}
+
+bool namespace_simple_pattern(const char *pattern, const char *value) {
+        return simple_pattern_check('.', pattern, value);
+}
+
+bool path_simple_pattern(const char *pattern, const char *value) {
+        return simple_pattern_check('/', pattern, value);
+}
+
+int bus_message_type_from_string(const char *s, uint8_t *u) {
+        if (streq(s, "signal"))
+                *u = SD_BUS_MESSAGE_SIGNAL;
+        else if (streq(s, "method_call"))
+                *u = SD_BUS_MESSAGE_METHOD_CALL;
+        else if (streq(s, "error"))
+                *u = SD_BUS_MESSAGE_METHOD_ERROR;
+        else if (streq(s, "method_return"))
+                *u = SD_BUS_MESSAGE_METHOD_RETURN;
+        else
+                return -EINVAL;
+
+        return 0;
+}
+
+const char *bus_message_type_to_string(uint8_t u) {
+        if (u == SD_BUS_MESSAGE_SIGNAL)
+                return "signal";
+        else if (u == SD_BUS_MESSAGE_METHOD_CALL)
+                return "method_call";
+        else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
+                return "error";
+        else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
+                 return "method_return";
+        else
+                return NULL;
+}
+
+char *bus_address_escape(const char *v) {
+        const char *a;
+        char *r, *b;
+
+        r = new(char, strlen(v)*3+1);
+        if (!r)
+                return NULL;
+
+        for (a = v, b = r; *a; a++) {
+
+                if ((*a >= '0' && *a <= '9') ||
+                    (*a >= 'a' && *a <= 'z') ||
+                    (*a >= 'A' && *a <= 'Z') ||
+                    strchr("_-/.", *a))
+                        *(b++) = *a;
+                else {
+                        *(b++) = '%';
+                        *(b++) = hexchar(*a >> 4);
+                        *(b++) = hexchar(*a & 0xF);
+                }
+        }
+
+        *b = 0;
+        return r;
+}
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
new file mode 100644
index 0000000..7c92293
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -0,0 +1,328 @@
+/*-*- 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 <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+
+#include "hashmap.h"
+#include "prioq.h"
+#include "list.h"
+#include "util.h"
+#include "refcnt.h"
+
+#include "sd-bus.h"
+#include "bus-error.h"
+#include "bus-match.h"
+#include "bus-kernel.h"
+#include "kdbus.h"
+
+struct reply_callback {
+        sd_bus_message_handler_t callback;
+        void *userdata;
+        usec_t timeout;
+        uint64_t cookie;
+        unsigned prioq_idx;
+};
+
+struct filter_callback {
+        sd_bus_message_handler_t callback;
+        void *userdata;
+
+        unsigned last_iteration;
+
+        LIST_FIELDS(struct filter_callback, callbacks);
+};
+
+struct node {
+        char *path;
+        struct node *parent;
+        LIST_HEAD(struct node, child);
+        LIST_FIELDS(struct node, siblings);
+
+        LIST_HEAD(struct node_callback, callbacks);
+        LIST_HEAD(struct node_vtable, vtables);
+        LIST_HEAD(struct node_enumerator, enumerators);
+
+        bool object_manager;
+};
+
+struct node_callback {
+        struct node *node;
+
+        bool is_fallback;
+        sd_bus_message_handler_t callback;
+        void *userdata;
+
+        unsigned last_iteration;
+
+        LIST_FIELDS(struct node_callback, callbacks);
+};
+
+struct node_enumerator {
+        struct node *node;
+
+        sd_bus_node_enumerator_t callback;
+        void *userdata;
+
+        unsigned last_iteration;
+
+        LIST_FIELDS(struct node_enumerator, enumerators);
+};
+
+struct node_vtable {
+        struct node *node;
+
+        char *interface;
+        bool is_fallback;
+        const sd_bus_vtable *vtable;
+        void *userdata;
+        sd_bus_object_find_t find;
+
+        unsigned last_iteration;
+
+        LIST_FIELDS(struct node_vtable, vtables);
+};
+
+struct vtable_member {
+        const char *path;
+        const char *interface;
+        const char *member;
+        struct node_vtable *parent;
+        unsigned last_iteration;
+        const sd_bus_vtable *vtable;
+};
+
+enum bus_state {
+        BUS_UNSET,
+        BUS_OPENING,
+        BUS_AUTHENTICATING,
+        BUS_HELLO,
+        BUS_RUNNING,
+        BUS_CLOSING,
+        BUS_CLOSED
+};
+
+static inline bool BUS_IS_OPEN(enum bus_state state) {
+        return state > BUS_UNSET && state < BUS_CLOSING;
+}
+
+enum bus_auth {
+        _BUS_AUTH_INVALID,
+        BUS_AUTH_EXTERNAL,
+        BUS_AUTH_ANONYMOUS
+};
+
+struct sd_bus {
+        /* We use atomic ref counting here since sd_bus_message
+           objects retain references to their originating sd_bus but
+           we want to allow them to be processed in a different
+           thread. We won't provide full thread safety, but only the
+           bare minimum that makes it possible to use sd_bus and
+           sd_bus_message objects independently and on different
+           threads as long as each object is used only once at the
+           same time. */
+        RefCount n_ref;
+
+        enum bus_state state;
+        int input_fd, output_fd;
+        int message_version;
+        int message_endian;
+
+        bool is_kernel:1;
+        bool can_fds:1;
+        bool bus_client:1;
+        bool ucred_valid:1;
+        bool is_server:1;
+        bool anonymous_auth:1;
+        bool prefer_readv:1;
+        bool prefer_writev:1;
+        bool match_callbacks_modified:1;
+        bool filter_callbacks_modified:1;
+        bool nodes_modified:1;
+        bool trusted:1;
+        bool fake_creds_valid:1;
+        bool manual_peer_interface:1;
+
+        int use_memfd;
+
+        void *rbuffer;
+        size_t rbuffer_size;
+
+        sd_bus_message **rqueue;
+        unsigned rqueue_size;
+        size_t rqueue_allocated;
+
+        sd_bus_message **wqueue;
+        unsigned wqueue_size;
+        size_t windex;
+        size_t wqueue_allocated;
+
+        uint64_t cookie;
+
+        char *unique_name;
+        uint64_t unique_id;
+
+        struct bus_match_node match_callbacks;
+        Prioq *reply_callbacks_prioq;
+        Hashmap *reply_callbacks;
+        LIST_HEAD(struct filter_callback, filter_callbacks);
+
+        Hashmap *nodes;
+        Hashmap *vtable_methods;
+        Hashmap *vtable_properties;
+
+        union {
+                struct sockaddr sa;
+                struct sockaddr_un un;
+                struct sockaddr_in in;
+                struct sockaddr_in6 in6;
+        } sockaddr;
+        socklen_t sockaddr_size;
+
+        char *kernel;
+        char *machine;
+
+        sd_id128_t server_id;
+
+        char *address;
+        unsigned address_index;
+
+        int last_connect_error;
+
+        enum bus_auth auth;
+        size_t auth_rbegin;
+        struct iovec auth_iovec[3];
+        unsigned auth_index;
+        char *auth_buffer;
+        usec_t auth_timeout;
+
+        struct ucred ucred;
+        char label[NAME_MAX];
+
+        uint64_t creds_mask;
+
+        int *fds;
+        unsigned n_fds;
+
+        char *exec_path;
+        char **exec_argv;
+
+        uint64_t hello_cookie;
+        unsigned iteration_counter;
+
+        void *kdbus_buffer;
+
+        /* We do locking around the memfd cache, since we want to
+         * allow people to process a sd_bus_message in a different
+         * thread then it was generated on and free it there. Since
+         * adding something to the memfd cache might happen when a
+         * message is released, we hence need to protect this bit with
+         * a mutex. */
+        pthread_mutex_t memfd_cache_mutex;
+        struct memfd_cache memfd_cache[MEMFD_CACHE_MAX];
+        unsigned n_memfd_cache;
+
+        pid_t original_pid;
+
+        uint64_t hello_flags;
+        uint64_t attach_flags;
+
+        uint64_t match_cookie;
+
+        sd_event_source *input_io_event_source;
+        sd_event_source *output_io_event_source;
+        sd_event_source *time_event_source;
+        sd_event_source *quit_event_source;
+        sd_event *event;
+        int event_priority;
+
+        sd_bus_message *current;
+
+        sd_bus **default_bus_ptr;
+        pid_t tid;
+
+        struct kdbus_creds fake_creds;
+        char *fake_label;
+
+        char *cgroup_root;
+};
+
+#define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
+
+#define BUS_WQUEUE_MAX 1024
+#define BUS_RQUEUE_MAX 64*1024
+
+#define BUS_MESSAGE_SIZE_MAX (64*1024*1024)
+#define BUS_AUTH_SIZE_MAX (64*1024)
+
+#define BUS_CONTAINER_DEPTH 128
+
+/* Defined by the specification as maximum size of an array in
+ * bytes */
+#define BUS_ARRAY_MAX_SIZE 67108864
+
+#define BUS_FDS_MAX 1024
+
+#define BUS_EXEC_ARGV_MAX 256
+
+bool interface_name_is_valid(const char *p) _pure_;
+bool service_name_is_valid(const char *p) _pure_;
+bool member_name_is_valid(const char *p) _pure_;
+bool object_path_is_valid(const char *p) _pure_;
+char *object_path_startswith(const char *a, const char *b) _pure_;
+
+bool namespace_complex_pattern(const char *pattern, const char *value) _pure_;
+bool path_complex_pattern(const char *pattern, const char *value) _pure_;
+
+bool namespace_simple_pattern(const char *pattern, const char *value) _pure_;
+bool path_simple_pattern(const char *pattern, const char *value) _pure_;
+
+int bus_message_type_from_string(const char *s, uint8_t *u) _pure_;
+const char *bus_message_type_to_string(uint8_t u) _pure_;
+
+#define error_name_is_valid interface_name_is_valid
+
+int bus_ensure_running(sd_bus *bus);
+int bus_start_running(sd_bus *bus);
+int bus_next_address(sd_bus *bus);
+
+int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m);
+
+int bus_rqueue_make_room(sd_bus *bus);
+
+bool bus_pid_changed(sd_bus *bus);
+
+char *bus_address_escape(const char *v);
+
+#define OBJECT_PATH_FOREACH_PREFIX(prefix, path)                        \
+        for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \
+             _slash && !(_slash[(_slash) == (prefix)] = 0);             \
+             _slash = streq((prefix), "/") ? NULL : strrchr((prefix), '/'))
+
+/* If we are invoking callbacks of a bus object, ensure unreffing the
+ * bus from the callback doesn't destroy the object we are working
+ * on */
+#define BUS_DONT_DESTROY(bus) \
+        _cleanup_bus_unref_ _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus)
diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c
new file mode 100644
index 0000000..d528ab2
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-introspect.c
@@ -0,0 +1,212 @@
+/*-*- 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 "util.h"
+#include "sd-bus-protocol.h"
+#include "bus-introspect.h"
+#include "bus-signature.h"
+#include "bus-internal.h"
+#include "bus-protocol.h"
+
+int introspect_begin(struct introspect *i, bool trusted) {
+        assert(i);
+
+        zero(*i);
+        i->trusted = trusted;
+
+        i->f = open_memstream(&i->introspection, &i->size);
+        if (!i->f)
+                return -ENOMEM;
+
+        fputs(BUS_INTROSPECT_DOCTYPE
+              "<node>\n", i->f);
+
+        return 0;
+}
+
+int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
+        assert(i);
+
+        fputs(BUS_INTROSPECT_INTERFACE_PEER
+              BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
+              BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
+
+        if (object_manager)
+                fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
+
+        return 0;
+}
+
+int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
+        char *node;
+
+        assert(i);
+        assert(prefix);
+
+        while ((node = set_steal_first(s))) {
+                const char *e;
+
+                e = object_path_startswith(node, prefix);
+                if (e && e[0])
+                        fprintf(i->f, " <node name=\"%s\"/>\n", e);
+
+                free(node);
+        }
+
+        return 0;
+}
+
+static void introspect_write_flags(struct introspect *i, int type, int flags) {
+        if (flags & SD_BUS_VTABLE_DEPRECATED)
+                fputs("   <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
+
+        if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
+                fputs("   <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
+
+        if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
+                if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
+                        fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
+                else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
+                        fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
+                else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
+                        fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
+        }
+
+        if (!i->trusted &&
+            (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
+            !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
+                fputs("   <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
+}
+
+static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
+        int r;
+
+        for (;;) {
+                size_t l;
+
+                if (!*signature)
+                        return 0;
+
+                r = signature_element_length(signature, &l);
+                if (r < 0)
+                        return r;
+
+                fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
+
+                if (direction)
+                        fprintf(i->f, " direction=\"%s\"/>\n", direction);
+                else
+                        fputs("/>\n", i->f);
+
+                signature += l;
+        }
+}
+
+int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
+        assert(i);
+        assert(v);
+
+        for (; v->type != _SD_BUS_VTABLE_END; v++) {
+
+                /* Ignore methods, signals and properties that are
+                 * marked "hidden", but do show the interface
+                 * itself */
+
+                if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
+                        continue;
+
+                switch (v->type) {
+
+                case _SD_BUS_VTABLE_START:
+                        if (v->flags & SD_BUS_VTABLE_DEPRECATED)
+                                fputs("  <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
+                        break;
+
+                case _SD_BUS_VTABLE_METHOD:
+                        fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
+                        introspect_write_arguments(i, strempty(v->x.method.signature), "in");
+                        introspect_write_arguments(i, strempty(v->x.method.result), "out");
+                        introspect_write_flags(i, v->type, v->flags);
+                        fputs("  </method>\n", i->f);
+                        break;
+
+                case _SD_BUS_VTABLE_PROPERTY:
+                case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
+                        fprintf(i->f, "  <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
+                                v->x.property.member,
+                                v->x.property.signature,
+                                v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
+                        introspect_write_flags(i, v->type, v->flags);
+                        fputs("  </property>\n", i->f);
+                        break;
+
+                case _SD_BUS_VTABLE_SIGNAL:
+                        fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
+                        introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
+                        introspect_write_flags(i, v->type, v->flags);
+                        fputs("  </signal>\n", i->f);
+                        break;
+                }
+
+        }
+
+        return 0;
+}
+
+int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
+        sd_bus_message *q;
+        int r;
+
+        assert(i);
+        assert(m);
+        assert(reply);
+
+        fputs("</node>\n", i->f);
+        fflush(i->f);
+
+        if (ferror(i->f))
+                return -ENOMEM;
+
+        r = sd_bus_message_new_method_return(m, &q);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(q, "s", i->introspection);
+        if (r < 0) {
+                sd_bus_message_unref(q);
+                return r;
+        }
+
+        *reply = q;
+        return 0;
+}
+
+void introspect_free(struct introspect *i) {
+        assert(i);
+
+        if (i->f)
+                fclose(i->f);
+
+        if (i->introspection)
+                free(i->introspection);
+
+        zero(*i);
+}
diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h
new file mode 100644
index 0000000..98312d1
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-introspect.h
@@ -0,0 +1,42 @@
+/*-*- 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 <sys/types.h>
+#include <stdio.h>
+
+#include "sd-bus.h"
+#include "set.h"
+
+struct introspect {
+        FILE *f;
+        char *introspection;
+        size_t size;
+        bool trusted;
+};
+
+int introspect_begin(struct introspect *i, bool trusted);
+int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
+int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
+int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
+int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
+void introspect_free(struct introspect *i);
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
new file mode 100644
index 0000000..f85b4d5
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -0,0 +1,1348 @@
+/*-*- 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/>.
+***/
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
+#include <fcntl.h>
+#include <malloc.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "strv.h"
+
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-kernel.h"
+#include "bus-bloom.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+
+#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
+
+int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
+        int r;
+
+        assert(s);
+        assert(id);
+
+        if (!startswith(s, ":1."))
+                return 0;
+
+        r = safe_atou64(s + 3, id);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
+        assert(d);
+        assert(sz > 0);
+
+        *d = ALIGN8_PTR(*d);
+
+        /* Note that p can be NULL, which encodes a region full of
+         * zeroes, which is useful to optimize certain padding
+         * conditions */
+
+        (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
+        (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
+        (*d)->vec.address = PTR_TO_UINT64(p);
+        (*d)->vec.size = sz;
+
+        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
+        assert(d);
+        assert(memfd >= 0);
+        assert(sz > 0);
+
+        *d = ALIGN8_PTR(*d);
+        (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
+        (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
+        (*d)->memfd.fd = memfd;
+        (*d)->memfd.size = sz;
+
+        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
+        assert(d);
+        assert(s);
+
+        *d = ALIGN8_PTR(*d);
+
+        (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
+        (*d)->type = KDBUS_ITEM_DST_NAME;
+        memcpy((*d)->str, s, length + 1);
+
+        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static void* append_bloom(struct kdbus_item **d, size_t length) {
+        void *r;
+
+        assert(d);
+
+        *d = ALIGN8_PTR(*d);
+
+        (*d)->size = offsetof(struct kdbus_item, data) + length;
+        (*d)->type = KDBUS_ITEM_BLOOM;
+        r = (*d)->data;
+
+        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+
+        return r;
+}
+
+static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
+        assert(d);
+        assert(fds);
+        assert(n_fds > 0);
+
+        *d = ALIGN8_PTR(*d);
+        (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
+        (*d)->type = KDBUS_ITEM_FDS;
+        memcpy((*d)->fds, fds, sizeof(int) * n_fds);
+
+        *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
+        unsigned i;
+        int r;
+
+        assert(m);
+        assert(bloom);
+
+        memset(bloom, 0, BLOOM_SIZE);
+
+        bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
+
+        if (m->interface)
+                bloom_add_pair(bloom, "interface", m->interface);
+        if (m->member)
+                bloom_add_pair(bloom, "member", m->member);
+        if (m->path) {
+                bloom_add_pair(bloom, "path", m->path);
+                bloom_add_pair(bloom, "path-slash-prefix", m->path);
+                bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
+        }
+
+        r = sd_bus_message_rewind(m, true);
+        if (r < 0)
+                return r;
+
+        for (i = 0; i < 64; i++) {
+                char type;
+                const char *t;
+                char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+                char *e;
+
+                r = sd_bus_message_peek_type(m, &type, NULL);
+                if (r < 0)
+                        return r;
+
+                if (type != SD_BUS_TYPE_STRING &&
+                    type != SD_BUS_TYPE_OBJECT_PATH &&
+                    type != SD_BUS_TYPE_SIGNATURE)
+                        break;
+
+                r = sd_bus_message_read_basic(m, type, &t);
+                if (r < 0)
+                        return r;
+
+                e = stpcpy(buf, "arg");
+                if (i < 10)
+                        *(e++) = '0' + (char) i;
+                else {
+                        *(e++) = '0' + (char) (i / 10);
+                        *(e++) = '0' + (char) (i % 10);
+                }
+
+                *e = 0;
+                bloom_add_pair(bloom, buf, t);
+
+                strcpy(e, "-dot-prefix");
+                bloom_add_prefixes(bloom, buf, t, '.');
+                strcpy(e, "-slash-prefix");
+                bloom_add_prefixes(bloom, buf, t, '/');
+        }
+
+        return 0;
+}
+
+static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
+        struct bus_body_part *part;
+        struct kdbus_item *d;
+        bool well_known;
+        uint64_t unique;
+        size_t sz, dl;
+        unsigned i;
+        int r;
+
+        assert(b);
+        assert(m);
+        assert(m->sealed);
+
+        if (m->kdbus)
+                return 0;
+
+        if (m->destination) {
+                r = bus_kernel_parse_unique_name(m->destination, &unique);
+                if (r < 0)
+                        return r;
+
+                well_known = r == 0;
+        } else
+                well_known = false;
+
+        sz = offsetof(struct kdbus_msg, items);
+
+        assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
+                  ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
+
+        /* Add in fixed header, fields header and payload */
+        sz += (1 + m->n_body_parts) *
+                ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
+
+        /* Add space for bloom filter */
+        sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
+
+        /* Add in well-known destination header */
+        if (well_known) {
+                dl = strlen(m->destination);
+                sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
+        }
+
+        /* Add space for unix fds */
+        if (m->n_fds > 0)
+                sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
+
+        m->kdbus = memalign(8, sz);
+        if (!m->kdbus) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        m->free_kdbus = true;
+        memset(m->kdbus, 0, sz);
+
+        m->kdbus->flags =
+                ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
+                ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+        m->kdbus->dst_id =
+                well_known ? 0 :
+                m->destination ? unique : KDBUS_DST_ID_BROADCAST;
+        m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
+        m->kdbus->cookie = m->header->serial;
+
+        if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                m->kdbus->cookie_reply = m->reply_cookie;
+        else
+                m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
+
+        d = m->kdbus->items;
+
+        if (well_known)
+                append_destination(&d, m->destination, dl);
+
+        append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
+
+        MESSAGE_FOREACH_PART(part, i, m) {
+                if (part->is_zero) {
+                        /* If this is padding then simply send a
+                         * vector with a NULL data pointer which the
+                         * kernel will just pass through. This is the
+                         * most efficient way to encode zeroes */
+
+                        append_payload_vec(&d, NULL, part->size);
+                        continue;
+                }
+
+                if (part->memfd >= 0 && part->sealed && m->destination) {
+                        /* Try to send a memfd, if the part is
+                         * sealed and this is not a broadcast. Since we can only  */
+
+                        append_payload_memfd(&d, part->memfd, part->size);
+                        continue;
+                }
+
+                /* Otherwise let's send a vector to the actual data,
+                 * for that we need to map it first. */
+                r = bus_body_part_map(part);
+                if (r < 0)
+                        goto fail;
+
+                append_payload_vec(&d, part->data, part->size);
+        }
+
+        if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
+                void *p;
+
+                p = append_bloom(&d, BLOOM_SIZE);
+                r = bus_message_setup_bloom(m, p);
+                if (r < 0)
+                        goto fail;
+        }
+
+        if (m->n_fds > 0)
+                append_fds(&d, m->fds, m->n_fds);
+
+        m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
+        assert(m->kdbus->size <= sz);
+
+        return 0;
+
+fail:
+        m->poisoned = true;
+        return r;
+}
+
+static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
+        sd_bus_message *m = NULL;
+        struct kdbus_item *d;
+        unsigned n_fds = 0;
+        _cleanup_free_ int *fds = NULL;
+        struct bus_header *h = NULL;
+        size_t total, n_bytes = 0, idx = 0;
+        const char *destination = NULL, *seclabel = NULL;
+        int r;
+
+        assert(bus);
+        assert(k);
+        assert(k->payload_type == KDBUS_PAYLOAD_DBUS);
+
+        KDBUS_ITEM_FOREACH(d, k, items) {
+                size_t l;
+
+                l = d->size - offsetof(struct kdbus_item, data);
+
+                switch (d->type) {
+
+                case KDBUS_ITEM_PAYLOAD_OFF:
+                        if (!h) {
+                                h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
+
+                                if (!bus_header_is_complete(h, d->vec.size))
+                                        return -EBADMSG;
+                        }
+
+                        n_bytes += d->vec.size;
+                        break;
+
+                case KDBUS_ITEM_PAYLOAD_MEMFD:
+                        if (!h)
+                                return -EBADMSG;
+
+                        n_bytes += d->memfd.size;
+                        break;
+
+                case KDBUS_ITEM_FDS: {
+                        int *f;
+                        unsigned j;
+
+                        j = l / sizeof(int);
+                        f = realloc(fds, sizeof(int) * (n_fds + j));
+                        if (!f)
+                                return -ENOMEM;
+
+                        fds = f;
+                        memcpy(fds + n_fds, d->fds, sizeof(int) * j);
+                        n_fds += j;
+                        break;
+                }
+
+                case KDBUS_ITEM_SECLABEL:
+                        seclabel = d->str;
+                        break;
+                }
+        }
+
+        if (!h)
+                return -EBADMSG;
+
+        r = bus_header_message_size(h, &total);
+        if (r < 0)
+                return r;
+
+        if (n_bytes != total)
+                return -EBADMSG;
+
+        /* on kdbus we only speak native endian gvariant, never dbus1
+         * marshalling or reverse endian */
+        if (h->version != 2 ||
+            h->endian != BUS_NATIVE_ENDIAN)
+                return -EPROTOTYPE;
+
+        r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
+        if (r < 0)
+                return r;
+
+        /* The well-known names list is different from the other
+        credentials. If we asked for it, but nothing is there, this
+        means that the list of well-known names is simply empty, not
+        that we lack any data */
+
+        m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+
+        KDBUS_ITEM_FOREACH(d, k, items) {
+                size_t l;
+
+                l = d->size - offsetof(struct kdbus_item, data);
+
+                switch (d->type) {
+
+                case KDBUS_ITEM_PAYLOAD_OFF: {
+                        size_t begin_body;
+
+                        begin_body = BUS_MESSAGE_BODY_BEGIN(m);
+
+                        if (idx + d->vec.size > begin_body) {
+                                struct bus_body_part *part;
+
+                                /* Contains body material */
+
+                                part = message_append_part(m);
+                                if (!part) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                /* A -1 offset is NUL padding. */
+                                part->is_zero = d->vec.offset == ~0ULL;
+
+                                if (idx >= begin_body) {
+                                        if (!part->is_zero)
+                                                part->data = (uint8_t *)k + d->vec.offset;
+                                        part->size = d->vec.size;
+                                } else {
+                                        if (!part->is_zero)
+                                                part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
+                                        part->size = d->vec.size - (begin_body - idx);
+                                }
+
+                                part->sealed = true;
+                        }
+
+                        idx += d->vec.size;
+                        break;
+                }
+
+                case KDBUS_ITEM_PAYLOAD_MEMFD: {
+                        struct bus_body_part *part;
+
+                        if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+
+                        part = message_append_part(m);
+                        if (!part) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        part->memfd = d->memfd.fd;
+                        part->size = d->memfd.size;
+                        part->sealed = true;
+
+                        idx += d->memfd.size;
+                        break;
+                }
+
+                case KDBUS_ITEM_CREDS:
+                        /* UID/GID/PID are always valid */
+                        m->creds.uid = (uid_t) d->creds.uid;
+                        m->creds.gid = (gid_t) d->creds.gid;
+                        m->creds.pid = (pid_t) d->creds.pid;
+                        m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
+
+                        /* The PID starttime/TID might be missing
+                         * however, when the data is faked by some
+                         * data bus proxy and it lacks that
+                         * information about the real client since
+                         * SO_PEERCRED is used for that */
+
+                        if (d->creds.starttime > 0) {
+                                m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
+                                m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
+                        }
+
+                        if (d->creds.tid > 0) {
+                                m->creds.tid = (pid_t) d->creds.tid;
+                                m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
+                        }
+                        break;
+
+                case KDBUS_ITEM_TIMESTAMP:
+                        m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
+                        m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
+                        break;
+
+                case KDBUS_ITEM_PID_COMM:
+                        m->creds.comm = d->str;
+                        m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
+                        break;
+
+                case KDBUS_ITEM_TID_COMM:
+                        m->creds.tid_comm = d->str;
+                        m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
+                        break;
+
+                case KDBUS_ITEM_EXE:
+                        m->creds.exe = d->str;
+                        m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
+                        break;
+
+                case KDBUS_ITEM_CMDLINE:
+                        m->creds.cmdline = d->str;
+                        m->creds.cmdline_size = l;
+                        m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
+                        break;
+
+                case KDBUS_ITEM_CGROUP:
+                        m->creds.cgroup = d->str;
+                        m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
+
+                        if (!bus->cgroup_root) {
+                                r = cg_get_root_path(&bus->cgroup_root);
+                                if (r < 0)
+                                        goto fail;
+                        }
+
+                        m->creds.cgroup_root = bus->cgroup_root;
+
+                        break;
+
+                case KDBUS_ITEM_AUDIT:
+                        m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+                        m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
+                        m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
+                        break;
+
+                case KDBUS_ITEM_CAPS:
+                        m->creds.capability = d->data;
+                        m->creds.capability_size = l;
+                        m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
+                        break;
+
+                case KDBUS_ITEM_DST_NAME:
+                        if (!service_name_is_valid(d->str))
+                                return -EBADMSG;
+
+                        destination = d->str;
+                        break;
+
+                case KDBUS_ITEM_NAME:
+                        if (!service_name_is_valid(d->name.name))
+                                return -EBADMSG;
+
+                        r = strv_extend(&m->creds.well_known_names, d->name.name);
+                        if (r < 0)
+                                goto fail;
+                        break;
+
+                case KDBUS_ITEM_FDS:
+                case KDBUS_ITEM_SECLABEL:
+                        break;
+
+                default:
+                        log_debug("Got unknown field from kernel %llu", d->type);
+                }
+        }
+
+        r = bus_message_parse_fields(m);
+        if (r < 0)
+                goto fail;
+
+        /* Override information from the user header with data from the kernel */
+        if (k->src_id == KDBUS_SRC_ID_KERNEL)
+                m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
+        else {
+                snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
+                m->sender = m->creds.unique_name = m->sender_buffer;
+        }
+
+        if (destination)
+                m->destination = destination;
+        else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
+                m->destination = NULL;
+        else if (k->dst_id == KDBUS_DST_ID_NAME)
+                m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
+        else {
+                snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
+                m->destination = m->destination_buffer;
+        }
+
+        /* We take possession of the kmsg struct now */
+        m->kdbus = k;
+        m->release_kdbus = true;
+        m->free_fds = true;
+        fds = NULL;
+
+        bus->rqueue[bus->rqueue_size++] = m;
+
+        return 1;
+
+fail:
+        if (m) {
+                struct bus_body_part *part;
+                unsigned i;
+
+                /* Make sure the memfds are not freed twice */
+                MESSAGE_FOREACH_PART(part, i, m)
+                        if (part->memfd >= 0)
+                                part->memfd = -1;
+
+                sd_bus_message_unref(m);
+        }
+
+        return r;
+}
+
+int bus_kernel_take_fd(sd_bus *b) {
+        struct kdbus_cmd_hello *hello;
+        struct kdbus_item *item;
+        size_t l = 0, sz;
+        int r;
+
+        assert(b);
+
+        if (b->is_server)
+                return -EINVAL;
+
+        b->use_memfd = 1;
+
+        sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
+
+        if (b->fake_creds_valid)
+                sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
+
+        if (b->fake_label) {
+                l = strlen(b->fake_label);
+                sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
+        }
+
+        hello = alloca0(sz);
+        hello->size = sz;
+        hello->conn_flags = b->hello_flags;
+        hello->attach_flags = b->attach_flags;
+        hello->pool_size = KDBUS_POOL_SIZE;
+
+        item = hello->items;
+
+        if (b->fake_creds_valid) {
+                item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
+                item->type = KDBUS_ITEM_CREDS;
+                item->creds = b->fake_creds;
+
+                item = KDBUS_ITEM_NEXT(item);
+        }
+
+        if (b->fake_label) {
+                item->size = offsetof(struct kdbus_item, str) + l + 1;
+                memcpy(item->str, b->fake_label, l+1);
+        }
+
+        r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
+        if (r < 0)
+                return -errno;
+
+        if (!b->kdbus_buffer) {
+                b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
+                if (b->kdbus_buffer == MAP_FAILED) {
+                        b->kdbus_buffer = NULL;
+                        return -errno;
+                }
+        }
+
+        /* The higher 32bit of both flags fields are considered
+         * 'incompatible flags'. Refuse them all for now. */
+        if (hello->bus_flags > 0xFFFFFFFFULL ||
+            hello->conn_flags > 0xFFFFFFFFULL)
+                return -ENOTSUP;
+
+        if (hello->bloom_size != BLOOM_SIZE)
+                return -ENOTSUP;
+
+        if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
+                return -ENOMEM;
+
+        b->unique_id = hello->id;
+
+        b->is_kernel = true;
+        b->bus_client = true;
+        b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
+        b->message_version = 2;
+        b->message_endian = BUS_NATIVE_ENDIAN;
+
+        /* the kernel told us the UUID of the underlying bus */
+        memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
+
+        return bus_start_running(b);
+}
+
+int bus_kernel_connect(sd_bus *b) {
+        assert(b);
+        assert(b->input_fd < 0);
+        assert(b->output_fd < 0);
+        assert(b->kernel);
+
+        if (b->is_server)
+                return -EINVAL;
+
+        b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (b->input_fd < 0)
+                return -errno;
+
+        b->output_fd = b->input_fd;
+
+        return bus_kernel_take_fd(b);
+}
+
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(bus->state == BUS_RUNNING);
+
+        /* If we can't deliver, we want room for the error message */
+        r = bus_rqueue_make_room(bus);
+        if (r < 0)
+                return r;
+
+        r = bus_message_setup_kmsg(bus, m);
+        if (r < 0)
+                return r;
+
+        r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
+        if (r < 0) {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                sd_bus_message *reply;
+
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
+                else if (errno == ENXIO || errno == ESRCH) {
+
+                        /* ENXIO: unique name not known
+                         * ESRCH: well-known name not known */
+
+                        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+                                sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
+                        else {
+                                log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
+                                return 0;
+                        }
+
+                } else if (errno == EADDRNOTAVAIL) {
+
+                        /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
+
+                        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+                                sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
+                        else {
+                                log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
+                                return 0;
+                        }
+                } else
+                        return -errno;
+
+                r = bus_message_new_synthetic_error(
+                                bus,
+                                BUS_MESSAGE_COOKIE(m),
+                                &error,
+                                &reply);
+
+                if (r < 0)
+                        return r;
+
+                r = bus_seal_synthetic_message(bus, reply);
+                if (r < 0)
+                        return r;
+
+                bus->rqueue[bus->rqueue_size++] = reply;
+
+                return 0;
+        }
+
+        return 1;
+}
+
+static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
+        uint64_t off;
+        struct kdbus_item *d;
+
+        assert(bus);
+        assert(k);
+
+        off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
+        ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
+
+        KDBUS_ITEM_FOREACH(d, k, items) {
+
+                if (d->type == KDBUS_ITEM_FDS)
+                        close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
+                else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
+                        close_nointr_nofail(d->memfd.fd);
+        }
+}
+
+static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert(bus);
+
+        r = sd_bus_message_new_signal(
+                        bus,
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "NameOwnerChanged",
+                        &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
+        if (r < 0)
+                return r;
+
+        m->sender = "org.freedesktop.DBus";
+
+        r = bus_seal_synthetic_message(bus, m);
+        if (r < 0)
+                return r;
+
+        bus->rqueue[bus->rqueue_size++] = m;
+        m = NULL;
+
+        return 1;
+}
+
+static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+        char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
+
+        assert(bus);
+        assert(k);
+        assert(d);
+
+        if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
+                old_owner[0] = 0;
+        else
+                sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id);
+
+        if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
+
+                if (isempty(old_owner))
+                        return 0;
+
+                new_owner[0] = 0;
+        } else
+                sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id);
+
+        return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
+}
+
+static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+        char owner[UNIQUE_NAME_MAX];
+
+        assert(bus);
+        assert(k);
+        assert(d);
+
+        sprintf(owner, ":1.%llu", d->id_change.id);
+
+        return push_name_owner_changed(
+                        bus, owner,
+                        d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
+                        d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
+}
+
+static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert(bus);
+        assert(k);
+        assert(d);
+
+        r = bus_message_new_synthetic_error(
+                        bus,
+                        k->cookie_reply,
+                        d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
+                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
+                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
+                        &m);
+        if (r < 0)
+                return r;
+
+        m->sender = "org.freedesktop.DBus";
+
+        r = bus_seal_synthetic_message(bus, m);
+        if (r < 0)
+                return r;
+
+        bus->rqueue[bus->rqueue_size++] = m;
+        m = NULL;
+
+        return 1;
+}
+
+static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
+        struct kdbus_item *d, *found = NULL;
+
+        static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
+                [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+                [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+                [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+
+                [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+                [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+
+                [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+                [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+        };
+
+        assert(bus);
+        assert(k);
+        assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
+
+        KDBUS_ITEM_FOREACH(d, k, items) {
+                if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
+                        if (found)
+                                return -EBADMSG;
+                        found = d;
+                } else
+                        log_debug("Got unknown field from kernel %llu", d->type);
+        }
+
+        if (!found) {
+                log_debug("Didn't find a kernel message to translate.");
+                return 0;
+        }
+
+        return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
+}
+
+int bus_kernel_read_message(sd_bus *bus) {
+        struct kdbus_cmd_recv recv = {};
+        struct kdbus_msg *k;
+        int r;
+
+        assert(bus);
+
+        r = bus_rqueue_make_room(bus);
+        if (r < 0)
+                return r;
+
+        r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &recv);
+        if (r < 0) {
+                if (errno == EAGAIN)
+                        return 0;
+
+                return -errno;
+        }
+        k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
+
+        if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
+                r = bus_kernel_make_message(bus, k);
+
+                /* Anybody can send us invalid messages, let's just drop them. */
+                if (r == -EBADMSG || r == -EPROTOTYPE) {
+                        log_debug("Ignoring invalid message: %s", strerror(-r));
+                        r = 0;
+                }
+
+        } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
+                r = bus_kernel_translate_message(bus, k);
+        else
+                r = 0;
+
+        if (r <= 0)
+                close_kdbus_msg(bus, k);
+
+        return r < 0 ? r : 1;
+}
+
+int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated) {
+        struct memfd_cache *c;
+        int fd;
+
+        assert(address);
+        assert(mapped);
+        assert(allocated);
+
+        if (!bus || !bus->is_kernel)
+                return -ENOTSUP;
+
+        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
+
+        if (bus->n_memfd_cache <= 0) {
+                struct kdbus_cmd_memfd_make cmd = {
+                        .size = sizeof(struct kdbus_cmd_memfd_make),
+                };
+                int r;
+
+                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+
+                r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &cmd);
+                if (r < 0)
+                        return -errno;
+
+                *address = NULL;
+                *mapped = 0;
+                *allocated = 0;
+                return cmd.fd;
+        }
+
+        c = &bus->memfd_cache[--bus->n_memfd_cache];
+
+        assert(c->fd >= 0);
+        assert(c->mapped == 0 || c->address);
+
+        *address = c->address;
+        *mapped = c->mapped;
+        *allocated = c->allocated;
+        fd = c->fd;
+
+        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+
+        return fd;
+}
+
+static void close_and_munmap(int fd, void *address, size_t size) {
+        if (size > 0)
+                assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
+
+        close_nointr_nofail(fd);
+}
+
+void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) {
+        struct memfd_cache *c;
+        uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
+
+        assert(fd >= 0);
+        assert(mapped == 0 || address);
+
+        if (!bus || !bus->is_kernel) {
+                close_and_munmap(fd, address, mapped);
+                return;
+        }
+
+        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
+
+        if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
+                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+
+                close_and_munmap(fd, address, mapped);
+                return;
+        }
+
+        c = &bus->memfd_cache[bus->n_memfd_cache++];
+        c->fd = fd;
+        c->address = address;
+
+        /* If overly long, let's return a bit to the OS */
+        if (mapped > max_mapped) {
+                assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_mapped) >= 0);
+                assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0);
+                c->mapped = c->allocated = max_mapped;
+        } else {
+                c->mapped = mapped;
+                c->allocated = allocated;
+        }
+
+        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+}
+
+void bus_kernel_flush_memfd(sd_bus *b) {
+        unsigned i;
+
+        assert(b);
+
+        for (i = 0; i < b->n_memfd_cache; i++)
+                close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
+}
+
+int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) {
+        uint64_t f = 0;
+
+        assert(kdbus_flags);
+
+        if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
+                f |= KDBUS_NAME_ALLOW_REPLACEMENT;
+
+        if (flags & SD_BUS_NAME_REPLACE_EXISTING)
+                f |= KDBUS_NAME_REPLACE_EXISTING;
+
+        if (flags & SD_BUS_NAME_QUEUE)
+                f |= KDBUS_NAME_QUEUE;
+
+        *kdbus_flags = f;
+        return 0;
+}
+
+int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
+        uint64_t m = 0;
+
+        assert(kdbus_mask);
+
+        if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))
+                m |= KDBUS_ATTACH_CREDS;
+
+        if (mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
+                m |= KDBUS_ATTACH_COMM;
+
+        if (mask & SD_BUS_CREDS_EXE)
+                m |= KDBUS_ATTACH_EXE;
+
+        if (mask & SD_BUS_CREDS_CMDLINE)
+                m |= KDBUS_ATTACH_CMDLINE;
+
+        if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))
+                m |= KDBUS_ATTACH_CGROUP;
+
+        if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
+                m |= KDBUS_ATTACH_CAPS;
+
+        if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
+                m |= KDBUS_ATTACH_SECLABEL;
+
+        if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
+                m |= KDBUS_ATTACH_AUDIT;
+
+        if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
+                m |= KDBUS_ATTACH_NAMES;
+
+        *kdbus_mask = m;
+        return 0;
+}
+
+int bus_kernel_create_bus(const char *name, bool world, char **s) {
+        struct kdbus_cmd_make *make;
+        struct kdbus_item *n;
+        int fd;
+
+        assert(name);
+        assert(s);
+
+        fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
+                              offsetof(struct kdbus_item, data64) + sizeof(uint64_t) +
+                              offsetof(struct kdbus_item, str) +
+                              DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1));
+
+        make->size = offsetof(struct kdbus_cmd_make, items);
+
+        n = make->items;
+        n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
+        n->type = KDBUS_ITEM_BLOOM_SIZE;
+        n->data64[0] = BLOOM_SIZE;
+        assert_cc(BLOOM_SIZE % 8 == 0);
+        make->size += ALIGN8(n->size);
+
+        n = KDBUS_ITEM_NEXT(n);
+        sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
+        n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
+        n->type = KDBUS_ITEM_MAKE_NAME;
+        make->size += ALIGN8(n->size);
+
+        make->flags = KDBUS_MAKE_POLICY_OPEN | (world ? KDBUS_MAKE_ACCESS_WORLD : 0);
+
+        if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        /* The higher 32bit of the flags field are considered
+         * 'incompatible flags'. Refuse them all for now. */
+        if (make->flags > 0xFFFFFFFFULL) {
+                close_nointr_nofail(fd);
+                return -ENOTSUP;
+        }
+
+        if (s) {
+                char *p;
+
+                p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
+                if (!p) {
+                        close_nointr_nofail(fd);
+                        return -ENOMEM;
+                }
+
+                *s = p;
+        }
+
+        return fd;
+}
+
+int bus_kernel_create_starter(const char *bus, const char *name) {
+        struct kdbus_cmd_hello *hello;
+        struct kdbus_item *n;
+        char *p;
+        int fd;
+
+        assert(bus);
+        assert(name);
+
+        p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus"));
+        sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus);
+
+        fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        hello = alloca0(ALIGN8(offsetof(struct kdbus_cmd_hello, items) +
+                               offsetof(struct kdbus_item, str) +
+                               strlen(name) + 1));
+
+        n = hello->items;
+        strcpy(n->str, name);
+        n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
+        n->type = KDBUS_ITEM_NAME;
+
+        hello->size = ALIGN8(offsetof(struct kdbus_cmd_hello, items) + n->size);
+        hello->conn_flags = KDBUS_HELLO_ACTIVATOR;
+        hello->pool_size = KDBUS_POOL_SIZE;
+
+        if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        /* The higher 32bit of both flags fields are considered
+         * 'incompatible flags'. Refuse them all for now. */
+        if (hello->bus_flags > 0xFFFFFFFFULL ||
+            hello->conn_flags > 0xFFFFFFFFULL) {
+                close_nointr_nofail(fd);
+                return -ENOTSUP;
+        }
+
+        if (hello->bloom_size != BLOOM_SIZE) {
+                close_nointr_nofail(fd);
+                return -ENOTSUP;
+        }
+
+        return fd;
+}
+
+int bus_kernel_create_namespace(const char *name, char **s) {
+        struct kdbus_cmd_make *make;
+        struct kdbus_item *n;
+        int fd;
+
+        assert(name);
+        assert(s);
+
+        fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
+                              offsetof(struct kdbus_item, str) +
+                              strlen(name) + 1));
+
+        n = make->items;
+        strcpy(n->str, name);
+        n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
+        n->type = KDBUS_ITEM_MAKE_NAME;
+
+        make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size);
+        make->flags = KDBUS_MAKE_POLICY_OPEN | KDBUS_MAKE_ACCESS_WORLD;
+
+        if (ioctl(fd, KDBUS_CMD_NS_MAKE, make) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        /* The higher 32bit of the flags field are considered
+         * 'incompatible flags'. Refuse them all for now. */
+        if (make->flags > 0xFFFFFFFFULL) {
+                close_nointr_nofail(fd);
+                return -ENOTSUP;
+        }
+
+        if (s) {
+                char *p;
+
+                p = strappend("/dev/kdbus/ns/", name);
+                if (!p) {
+                        close_nointr_nofail(fd);
+                        return -ENOMEM;
+                }
+
+                *s = p;
+        }
+
+        return fd;
+}
+
+int bus_kernel_create_monitor(const char *bus) {
+        struct kdbus_cmd_hello *hello;
+        char *p;
+        int fd;
+
+        assert(bus);
+
+        p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus"));
+        sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus);
+
+        fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        hello = alloca0(sizeof(struct kdbus_cmd_hello));
+        hello->size = sizeof(struct kdbus_cmd_hello);
+        hello->conn_flags = KDBUS_HELLO_ACTIVATOR;
+        hello->pool_size = KDBUS_POOL_SIZE;
+
+        if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        /* The higher 32bit of both flags fields are considered
+         * 'incompatible flags'. Refuse them all for now. */
+        if (hello->bus_flags > 0xFFFFFFFFULL ||
+            hello->conn_flags > 0xFFFFFFFFULL) {
+                close_nointr_nofail(fd);
+                return -ENOTSUP;
+        }
+
+        return fd;
+}
+
+int bus_kernel_try_close(sd_bus *bus) {
+        assert(bus);
+        assert(bus->is_kernel);
+
+        if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0)
+                return -errno;
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
new file mode 100644
index 0000000..2aba0bb
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -0,0 +1,81 @@
+/*-*- 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 <stdbool.h>
+
+#include "sd-bus.h"
+
+#define KDBUS_ITEM_NEXT(item) \
+        (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
+
+#define KDBUS_ITEM_FOREACH(part, head, first)                           \
+        for (part = (head)->first;                                      \
+             (uint8_t *)(part) < (uint8_t *)(head) + (head)->size;      \
+             part = KDBUS_ITEM_NEXT(part))
+
+#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
+#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
+
+#define MEMFD_CACHE_MAX 32
+
+/* When we cache a memfd block for reuse, we will truncate blocks
+ * longer than this in order not to keep too much data around. */
+#define MEMFD_CACHE_ITEM_SIZE_MAX (128*1024)
+
+/* This determines at which minimum size we prefer sending memfds over
+ * sending vectors */
+#define MEMFD_MIN_SIZE (128*1024)
+
+/* The size of the per-connection memory pool that we set up and where
+ * the kernel places our incoming messages */
+#define KDBUS_POOL_SIZE (16*1024*1024)
+
+struct memfd_cache {
+        int fd;
+        void *address;
+        size_t mapped;
+        size_t allocated;
+};
+
+int bus_kernel_connect(sd_bus *b);
+int bus_kernel_take_fd(sd_bus *b);
+
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m);
+int bus_kernel_read_message(sd_bus *bus);
+
+int bus_kernel_create_bus(const char *name, bool world, char **s);
+int bus_kernel_create_namespace(const char *name, char **s);
+int bus_kernel_create_starter(const char *bus, const char *name);
+int bus_kernel_create_monitor(const char *bus);
+
+int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated);
+void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated);
+
+void bus_kernel_flush_memfd(sd_bus *bus);
+
+int bus_kernel_parse_unique_name(const char *s, uint64_t *id);
+
+int kdbus_translate_request_name_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags);
+int kdbus_translate_attach_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags);
+
+int bus_kernel_try_close(sd_bus *bus);
diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
new file mode 100644
index 0000000..ffc9756
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -0,0 +1,1078 @@
+/*-*- 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 "bus-internal.h"
+#include "bus-message.h"
+#include "bus-match.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "strv.h"
+
+/* Example:
+ *
+ *  A: type=signal,sender=foo,interface=bar
+ *  B: type=signal,sender=quux,interface=fips
+ *  C: type=signal,sender=quux,interface=waldo
+ *  D: type=signal,member=test
+ *  E: sender=miau
+ *  F: type=signal
+ *  G: type=signal
+ *
+ *  results in this tree:
+ *
+ *  BUS_MATCH_ROOT
+ *  + BUS_MATCH_MESSAGE_TYPE
+ *  | ` BUS_MATCH_VALUE: value == signal
+ *  |   + DBUS_MATCH_SENDER
+ *  |   | + BUS_MATCH_VALUE: value == foo
+ *  |   | | ` DBUS_MATCH_INTERFACE
+ *  |   | |   ` BUS_MATCH_VALUE: value == bar
+ *  |   | |     ` BUS_MATCH_LEAF: A
+ *  |   | ` BUS_MATCH_VALUE: value == quux
+ *  |   |   ` DBUS_MATCH_INTERFACE
+ *  |   |     | BUS_MATCH_VALUE: value == fips
+ *  |   |     | ` BUS_MATCH_LEAF: B
+ *  |   |     ` BUS_MATCH_VALUE: value == waldo
+ *  |   |       ` BUS_MATCH_LEAF: C
+ *  |   + DBUS_MATCH_MEMBER
+ *  |   | ` BUS_MATCH_VALUE: value == test
+ *  |   |   ` BUS_MATCH_LEAF: D
+ *  |   + BUS_MATCH_LEAF: F
+ *  |   ` BUS_MATCH_LEAF: G
+ *  ` BUS_MATCH_SENDER
+ *    ` BUS_MATCH_VALUE: value == miau
+ *      ` BUS_MATCH_LEAF: E
+ */
+
+static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) {
+        return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST;
+}
+
+static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) {
+        return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) ||
+                (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST);
+}
+
+static void bus_match_node_free(struct bus_match_node *node) {
+        assert(node);
+        assert(node->parent);
+        assert(!node->child);
+        assert(node->type != BUS_MATCH_ROOT);
+        assert(node->type < _BUS_MATCH_NODE_TYPE_MAX);
+
+        if (node->parent->child) {
+                /* We are apparently linked into the parent's child
+                 * list. Let's remove us from there. */
+                if (node->prev) {
+                        assert(node->prev->next == node);
+                        node->prev->next = node->next;
+                } else {
+                        assert(node->parent->child == node);
+                        node->parent->child = node->next;
+                }
+
+                if (node->next)
+                        node->next->prev = node->prev;
+        }
+
+        if (node->type == BUS_MATCH_VALUE) {
+                /* We might be in the parent's hash table, so clean
+                 * this up */
+
+                if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
+                        hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8));
+                else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str)
+                        hashmap_remove(node->parent->compare.children, node->value.str);
+
+                free(node->value.str);
+        }
+
+        if (BUS_MATCH_IS_COMPARE(node->type)) {
+                assert(hashmap_isempty(node->compare.children));
+                hashmap_free(node->compare.children);
+        }
+
+        free(node);
+}
+
+static bool bus_match_node_maybe_free(struct bus_match_node *node) {
+        assert(node);
+
+        if (node->child)
+                return false;
+
+        if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children))
+                return true;
+
+        bus_match_node_free(node);
+        return true;
+}
+
+static bool value_node_test(
+                struct bus_match_node *node,
+                enum bus_match_node_type parent_type,
+                uint8_t value_u8,
+                const char *value_str,
+                sd_bus_message *m) {
+
+        assert(node);
+        assert(node->type == BUS_MATCH_VALUE);
+
+        /* Tests parameters against this value node, doing prefix
+         * magic and stuff. */
+
+        switch (parent_type) {
+
+        case BUS_MATCH_MESSAGE_TYPE:
+                return node->value.u8 == value_u8;
+
+        case BUS_MATCH_SENDER:
+                if (streq_ptr(node->value.str, value_str))
+                        return true;
+
+                if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
+                        char **i;
+
+                        /* on kdbus we have the well known names list
+                         * in the credentials, let's make use of that
+                         * for an accurate match */
+
+                        STRV_FOREACH(i, m->creds.well_known_names)
+                                if (streq_ptr(node->value.str, *i))
+                                        return true;
+
+                } else {
+
+                        /* If we don't have kdbus, we don't know the
+                         * well-known names of the senders. In that,
+                         * let's just hope that dbus-daemon doesn't
+                         * send us stuff we didn't want. */
+
+                        if (node->value.str[0] != ':' && value_str && value_str[0] == ':')
+                                return true;
+                }
+
+                return false;
+
+        case BUS_MATCH_DESTINATION:
+        case BUS_MATCH_INTERFACE:
+        case BUS_MATCH_MEMBER:
+        case BUS_MATCH_PATH:
+        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
+                return streq_ptr(node->value.str, value_str);
+
+        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
+                return namespace_simple_pattern(node->value.str, value_str);
+
+        case BUS_MATCH_PATH_NAMESPACE:
+                return path_simple_pattern(node->value.str, value_str);
+
+        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
+                return path_complex_pattern(node->value.str, value_str);
+
+        default:
+                assert_not_reached("Invalid node type");
+        }
+}
+
+static bool value_node_same(
+                struct bus_match_node *node,
+                enum bus_match_node_type parent_type,
+                uint8_t value_u8,
+                const char *value_str) {
+
+        /* Tests parameters against this value node, not doing prefix
+         * magic and stuff, i.e. this one actually compares the match
+         * itself.*/
+
+        assert(node);
+        assert(node->type == BUS_MATCH_VALUE);
+
+        switch (parent_type) {
+
+        case BUS_MATCH_MESSAGE_TYPE:
+                return node->value.u8 == value_u8;
+
+        case BUS_MATCH_SENDER:
+        case BUS_MATCH_DESTINATION:
+        case BUS_MATCH_INTERFACE:
+        case BUS_MATCH_MEMBER:
+        case BUS_MATCH_PATH:
+        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
+        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
+        case BUS_MATCH_PATH_NAMESPACE:
+        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
+                return streq(node->value.str, value_str);
+
+        default:
+                assert_not_reached("Invalid node type");
+        }
+}
+
+int bus_match_run(
+                sd_bus *bus,
+                struct bus_match_node *node,
+                sd_bus_message *m) {
+
+
+        const char *test_str = NULL;
+        uint8_t test_u8 = 0;
+        int r;
+
+        assert(m);
+
+        if (!node)
+                return 0;
+
+        if (bus && bus->match_callbacks_modified)
+                return 0;
+
+        /* Not these special semantics: when traversing the tree we
+         * usually let bus_match_run() when called for a node
+         * recursively invoke bus_match_run(). There's are two
+         * exceptions here though, which are BUS_NODE_ROOT (which
+         * cannot have a sibling), and BUS_NODE_VALUE (whose siblings
+         * are invoked anyway by its parent. */
+
+        switch (node->type) {
+
+        case BUS_MATCH_ROOT:
+
+                /* Run all children. Since we cannot have any siblings
+                 * we won't call any. The children of the root node
+                 * are compares or leaves, they will automatically
+                 * call their siblings. */
+                return bus_match_run(bus, node->child, m);
+
+        case BUS_MATCH_VALUE:
+
+                /* Run all children. We don't execute any siblings, we
+                 * assume our caller does that. The children of value
+                 * nodes are compares or leaves, they will
+                 * automatically call their siblings */
+
+                assert(node->child);
+                return bus_match_run(bus, node->child, m);
+
+        case BUS_MATCH_LEAF:
+
+                if (bus) {
+                        if (node->leaf.last_iteration == bus->iteration_counter)
+                                return 0;
+
+                        node->leaf.last_iteration = bus->iteration_counter;
+                }
+
+                r = sd_bus_message_rewind(m, true);
+                if (r < 0)
+                        return r;
+
+                /* Run the callback. And then invoke siblings. */
+                if (node->leaf.callback) {
+                        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+
+                        r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
+                        r = bus_maybe_reply_error(m, r, &error_buffer);
+                        if (r != 0)
+                                return r;
+                }
+
+                return bus_match_run(bus, node->next, m);
+
+        case BUS_MATCH_MESSAGE_TYPE:
+                test_u8 = m->header->type;
+                break;
+
+        case BUS_MATCH_SENDER:
+                test_str = m->sender;
+                /* FIXME: resolve test_str from a well-known to a unique name first */
+                break;
+
+        case BUS_MATCH_DESTINATION:
+                test_str = m->destination;
+                break;
+
+        case BUS_MATCH_INTERFACE:
+                test_str = m->interface;
+                break;
+
+        case BUS_MATCH_MEMBER:
+                test_str = m->member;
+                break;
+
+        case BUS_MATCH_PATH:
+        case BUS_MATCH_PATH_NAMESPACE:
+                test_str = m->path;
+                break;
+
+        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
+                test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
+                break;
+
+        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
+                test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
+                break;
+
+        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
+                test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
+                break;
+
+        default:
+                assert_not_reached("Unknown match type.");
+        }
+
+        if (BUS_MATCH_CAN_HASH(node->type)) {
+                struct bus_match_node *found;
+
+                /* Lookup via hash table, nice! So let's jump directly. */
+
+                if (test_str)
+                        found = hashmap_get(node->compare.children, test_str);
+                else if (node->type == BUS_MATCH_MESSAGE_TYPE)
+                        found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
+                else
+                        found = NULL;
+
+                if (found) {
+                        r = bus_match_run(bus, found, m);
+                        if (r != 0)
+                                return r;
+                }
+        } else {
+                struct bus_match_node *c;
+
+                /* No hash table, so let's iterate manually... */
+
+                for (c = node->child; c; c = c->next) {
+                        if (!value_node_test(c, node->type, test_u8, test_str, m))
+                                continue;
+
+                        r = bus_match_run(bus, c, m);
+                        if (r != 0)
+                                return r;
+                }
+        }
+
+        if (bus && bus->match_callbacks_modified)
+                return 0;
+
+        /* And now, let's invoke our siblings */
+        return bus_match_run(bus, node->next, m);
+}
+
+static int bus_match_add_compare_value(
+                struct bus_match_node *where,
+                enum bus_match_node_type t,
+                uint8_t value_u8,
+                const char *value_str,
+                struct bus_match_node **ret) {
+
+        struct bus_match_node *c = NULL, *n = NULL;
+        int r;
+
+        assert(where);
+        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+        assert(BUS_MATCH_IS_COMPARE(t));
+        assert(ret);
+
+        for (c = where->child; c && c->type != t; c = c->next)
+                ;
+
+        if (c) {
+                /* Comparison node already exists? Then let's see if
+                 * the value node exists too. */
+
+                if (t == BUS_MATCH_MESSAGE_TYPE)
+                        n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
+                else if (BUS_MATCH_CAN_HASH(t))
+                        n = hashmap_get(c->compare.children, value_str);
+                else {
+                        for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
+                                ;
+                }
+
+                if (n) {
+                        *ret = n;
+                        return 0;
+                }
+        } else {
+                /* Comparison node, doesn't exist yet? Then let's
+                 * create it. */
+
+                c = new0(struct bus_match_node, 1);
+                if (!c) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                c->type = t;
+                c->parent = where;
+                c->next = where->child;
+                if (c->next)
+                        c->next->prev = c;
+                where->child = c;
+
+                if (t == BUS_MATCH_MESSAGE_TYPE) {
+                        c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
+                        if (!c->compare.children) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+                } else if (BUS_MATCH_CAN_HASH(t)) {
+                        c->compare.children = hashmap_new(string_hash_func, string_compare_func);
+                        if (!c->compare.children) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+                }
+        }
+
+        n = new0(struct bus_match_node, 1);
+        if (!n) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        n->type = BUS_MATCH_VALUE;
+        n->value.u8 = value_u8;
+        if (value_str) {
+                n->value.str = strdup(value_str);
+                if (!n->value.str) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        n->parent = c;
+        if (c->compare.children) {
+
+                if (t == BUS_MATCH_MESSAGE_TYPE)
+                        r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n);
+                else
+                        r = hashmap_put(c->compare.children, n->value.str, n);
+
+                if (r < 0)
+                        goto fail;
+        } else {
+                n->next = c->child;
+                if (n->next)
+                        n->next->prev = n;
+                c->child = n;
+        }
+
+        *ret = n;
+        return 1;
+
+fail:
+        if (c)
+                bus_match_node_maybe_free(c);
+
+        if (n) {
+                free(n->value.str);
+                free(n);
+        }
+
+        return r;
+}
+
+static int bus_match_find_compare_value(
+                struct bus_match_node *where,
+                enum bus_match_node_type t,
+                uint8_t value_u8,
+                const char *value_str,
+                struct bus_match_node **ret) {
+
+        struct bus_match_node *c, *n;
+
+        assert(where);
+        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+        assert(BUS_MATCH_IS_COMPARE(t));
+        assert(ret);
+
+        for (c = where->child; c && c->type != t; c = c->next)
+                ;
+
+        if (!c)
+                return 0;
+
+        if (t == BUS_MATCH_MESSAGE_TYPE)
+                n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8));
+        else if (BUS_MATCH_CAN_HASH(t))
+                n = hashmap_get(c->compare.children, value_str);
+        else {
+                for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
+                        ;
+        }
+
+        if (n) {
+                *ret = n;
+                return 1;
+        }
+
+        return 0;
+}
+
+static int bus_match_add_leaf(
+                struct bus_match_node *where,
+                sd_bus_message_handler_t callback,
+                void *userdata,
+                uint64_t cookie,
+                struct bus_match_node **ret) {
+
+        struct bus_match_node *n;
+
+        assert(where);
+        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+        assert(ret);
+
+        n = new0(struct bus_match_node, 1);
+        if (!n)
+                return -ENOMEM;
+
+        n->type = BUS_MATCH_LEAF;
+        n->parent = where;
+        n->next = where->child;
+        if (n->next)
+                n->next->prev = n;
+        n->leaf.callback = callback;
+        n->leaf.userdata = userdata;
+        n->leaf.cookie = cookie;
+
+        where->child = n;
+
+        *ret = n;
+        return 1;
+}
+
+static int bus_match_find_leaf(
+                struct bus_match_node *where,
+                sd_bus_message_handler_t callback,
+                void *userdata,
+                struct bus_match_node **ret) {
+
+        struct bus_match_node *c;
+
+        assert(where);
+        assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+        assert(ret);
+
+        for (c = where->child; c; c = c->next) {
+                if (c->type == BUS_MATCH_LEAF &&
+                    c->leaf.callback == callback &&
+                    c->leaf.userdata == userdata) {
+                        *ret = c;
+                        return 1;
+                }
+        }
+
+        return 0;
+}
+
+enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) {
+        assert(k);
+
+        if (n == 4 && startswith(k, "type"))
+                return BUS_MATCH_MESSAGE_TYPE;
+        if (n == 6 && startswith(k, "sender"))
+                return BUS_MATCH_SENDER;
+        if (n == 11 && startswith(k, "destination"))
+                return BUS_MATCH_DESTINATION;
+        if (n == 9 && startswith(k, "interface"))
+                return BUS_MATCH_INTERFACE;
+        if (n == 6 && startswith(k, "member"))
+                return BUS_MATCH_MEMBER;
+        if (n == 4 && startswith(k, "path"))
+                return BUS_MATCH_PATH;
+        if (n == 14 && startswith(k, "path_namespace"))
+                return BUS_MATCH_PATH_NAMESPACE;
+
+        if (n == 4 && startswith(k, "arg")) {
+                int j;
+
+                j = undecchar(k[3]);
+                if (j < 0)
+                        return -EINVAL;
+
+                return BUS_MATCH_ARG + j;
+        }
+
+        if (n == 5 && startswith(k, "arg")) {
+                int a, b;
+                enum bus_match_node_type t;
+
+                a = undecchar(k[3]);
+                b = undecchar(k[4]);
+                if (a <= 0 || b < 0)
+                        return -EINVAL;
+
+                t = BUS_MATCH_ARG + a * 10 + b;
+                if (t > BUS_MATCH_ARG_LAST)
+                        return -EINVAL;
+
+                return t;
+        }
+
+        if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) {
+                int j;
+
+                j = undecchar(k[3]);
+                if (j < 0)
+                        return -EINVAL;
+
+                return BUS_MATCH_ARG_PATH + j;
+        }
+
+        if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) {
+                enum bus_match_node_type t;
+                int a, b;
+
+                a = undecchar(k[3]);
+                b = undecchar(k[4]);
+                if (a <= 0 || b < 0)
+                        return -EINVAL;
+
+                t = BUS_MATCH_ARG_PATH + a * 10 + b;
+                if (t > BUS_MATCH_ARG_PATH_LAST)
+                        return -EINVAL;
+
+                return t;
+        }
+
+        if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) {
+                int j;
+
+                j = undecchar(k[3]);
+                if (j < 0)
+                        return -EINVAL;
+
+                return BUS_MATCH_ARG_NAMESPACE + j;
+        }
+
+        if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) {
+                enum bus_match_node_type t;
+                int a, b;
+
+                a = undecchar(k[3]);
+                b = undecchar(k[4]);
+                if (a <= 0 || b < 0)
+                        return -EINVAL;
+
+                t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b;
+                if (t > BUS_MATCH_ARG_NAMESPACE_LAST)
+                        return -EINVAL;
+
+                return t;
+        }
+
+        return -EINVAL;
+}
+
+static int match_component_compare(const void *a, const void *b) {
+        const struct bus_match_component *x = a, *y = b;
+
+        if (x->type < y->type)
+                return -1;
+        if (x->type > y->type)
+                return 1;
+
+        return 0;
+}
+
+void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
+        unsigned i;
+
+        for (i = 0; i < n_components; i++)
+                free(components[i].value_str);
+
+        free(components);
+}
+
+int bus_match_parse(
+                const char *match,
+                struct bus_match_component **_components,
+                unsigned *_n_components) {
+
+        const char *p = match;
+        struct bus_match_component *components = NULL;
+        size_t components_allocated = 0;
+        unsigned n_components = 0, i;
+        _cleanup_free_ char *value = NULL;
+        int r;
+
+        assert(match);
+        assert(_components);
+        assert(_n_components);
+
+        while (*p != 0) {
+                const char *eq, *q;
+                enum bus_match_node_type t;
+                unsigned j = 0;
+                size_t value_allocated = 0;
+                bool escaped = false, quoted;
+                uint8_t u;
+
+                eq = strchr(p, '=');
+                if (!eq)
+                        return -EINVAL;
+
+                t = bus_match_node_type_from_string(p, eq - p);
+                if (t < 0)
+                        return -EINVAL;
+
+                quoted = eq[1] == '\'';
+
+                for (q = eq + 1 + quoted;; q++) {
+
+                        if (*q == 0) {
+
+                                if (quoted) {
+                                        r = -EINVAL;
+                                        goto fail;
+                                } else {
+                                        if (value)
+                                                value[j] = 0;
+                                        break;
+                                }
+                        }
+
+                        if (!escaped) {
+                                if (*q == '\\') {
+                                        escaped = true;
+                                        continue;
+                                }
+
+                                if (quoted) {
+                                        if (*q == '\'') {
+                                                if (value)
+                                                        value[j] = 0;
+                                                break;
+                                        }
+                                } else {
+                                        if (*q == ',') {
+                                                if (value)
+                                                        value[j] = 0;
+
+                                                break;
+                                        }
+                                }
+                        }
+
+                        if (!GREEDY_REALLOC(value, value_allocated, j + 2)) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        value[j++] = *q;
+                        escaped = false;
+                }
+
+                if (!value) {
+                        value = strdup("");
+                        if (!value) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+                }
+
+                if (t == BUS_MATCH_MESSAGE_TYPE) {
+                        r = bus_message_type_from_string(value, &u);
+                        if (r < 0)
+                                goto fail;
+
+                        free(value);
+                        value = NULL;
+                } else
+                        u = 0;
+
+                if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                components[n_components].type = t;
+                components[n_components].value_str = value;
+                components[n_components].value_u8 = u;
+                n_components++;
+
+                value = NULL;
+
+                if (q[1] == 0)
+                        break;
+
+                if (q[quoted] != ',') {
+                        r = -EINVAL;
+                        goto fail;
+                }
+
+                p = q + 1 + quoted;
+        }
+
+        /* Order the whole thing, so that we always generate the same tree */
+        qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
+
+        /* Check for duplicates */
+        for (i = 0; i+1 < n_components; i++)
+                if (components[i].type == components[i+1].type) {
+                        r = -EINVAL;
+                        goto fail;
+                }
+
+        *_components = components;
+        *_n_components = n_components;
+
+        return 0;
+
+fail:
+        bus_match_parse_free(components, n_components);
+        return r;
+}
+
+char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) {
+        _cleanup_free_ FILE *f = NULL;
+        char *buffer = NULL;
+        size_t size = 0;
+        unsigned i;
+
+        if (n_components <= 0)
+                return strdup("");
+
+        assert(components);
+
+        f = open_memstream(&buffer, &size);
+        if (!f)
+                return NULL;
+
+        for (i = 0; i < n_components; i++) {
+                char buf[32];
+
+                if (i != 0)
+                        fputc(',', f);
+
+                fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
+                fputc('=', f);
+                fputc('\'', f);
+
+                if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
+                        fputs(bus_message_type_to_string(components[i].value_u8), f);
+                else
+                        fputs(components[i].value_str, f);
+
+                fputc('\'', f);
+        }
+
+        fflush(f);
+        if (ferror(f))
+                return NULL;
+
+        return buffer;
+}
+
+int bus_match_add(
+                struct bus_match_node *root,
+                struct bus_match_component *components,
+                unsigned n_components,
+                sd_bus_message_handler_t callback,
+                void *userdata,
+                uint64_t cookie,
+                struct bus_match_node **ret) {
+
+        unsigned i;
+        struct bus_match_node *n;
+        int r;
+
+        assert(root);
+
+        n = root;
+        for (i = 0; i < n_components; i++) {
+                r = bus_match_add_compare_value(
+                                n, components[i].type,
+                                components[i].value_u8, components[i].value_str, &n);
+                if (r < 0)
+                        return r;
+        }
+
+        r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
+        if (r < 0)
+                return r;
+
+        if (ret)
+                *ret = n;
+
+        return 0;
+}
+
+int bus_match_remove(
+                struct bus_match_node *root,
+                struct bus_match_component *components,
+                unsigned n_components,
+                sd_bus_message_handler_t callback,
+                void *userdata,
+                uint64_t *cookie) {
+
+        unsigned i;
+        struct bus_match_node *n, **gc;
+        int r;
+
+        assert(root);
+
+        gc = newa(struct bus_match_node*, n_components);
+
+        n = root;
+        for (i = 0; i < n_components; i++) {
+                r = bus_match_find_compare_value(
+                                n, components[i].type,
+                                components[i].value_u8, components[i].value_str,
+                                &n);
+                if (r <= 0)
+                        return r;
+
+                gc[i] = n;
+        }
+
+        r = bus_match_find_leaf(n, callback, userdata, &n);
+        if (r <= 0)
+                return r;
+
+        if (cookie)
+                *cookie = n->leaf.cookie;
+
+        /* Free the leaf */
+        bus_match_node_free(n);
+
+        /* Prune the tree above */
+        for (i = n_components; i > 0; i --) {
+                struct bus_match_node *p = gc[i-1]->parent;
+
+                if (!bus_match_node_maybe_free(gc[i-1]))
+                        break;
+
+                if (!bus_match_node_maybe_free(p))
+                        break;
+        }
+
+        return r;
+}
+
+void bus_match_free(struct bus_match_node *node) {
+        struct bus_match_node *c;
+
+        if (!node)
+                return;
+
+        if (BUS_MATCH_CAN_HASH(node->type)) {
+                Iterator i;
+
+                HASHMAP_FOREACH(c, node->compare.children, i)
+                        bus_match_free(c);
+
+                assert(hashmap_isempty(node->compare.children));
+        }
+
+        while ((c = node->child))
+                bus_match_free(c);
+
+        if (node->type != BUS_MATCH_ROOT)
+                bus_match_node_free(node);
+}
+
+const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) {
+        switch (t) {
+
+        case BUS_MATCH_ROOT:
+                return "root";
+
+        case BUS_MATCH_VALUE:
+                return "value";
+
+        case BUS_MATCH_LEAF:
+                return "leaf";
+
+        case BUS_MATCH_MESSAGE_TYPE:
+                return "type";
+
+        case BUS_MATCH_SENDER:
+                return "sender";
+
+        case BUS_MATCH_DESTINATION:
+                return "destination";
+
+        case BUS_MATCH_INTERFACE:
+                return "interface";
+
+        case BUS_MATCH_MEMBER:
+                return "member";
+
+        case BUS_MATCH_PATH:
+                return "path";
+
+        case BUS_MATCH_PATH_NAMESPACE:
+                return "path_namespace";
+
+        case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
+                snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG);
+                return buf;
+
+        case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
+                snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH);
+                return buf;
+
+        case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
+                snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE);
+                return buf;
+
+        default:
+                return NULL;
+        }
+}
+
+void bus_match_dump(struct bus_match_node *node, unsigned level) {
+        struct bus_match_node *c;
+        _cleanup_free_ char *pfx = NULL;
+        char buf[32];
+
+        if (!node)
+                return;
+
+        pfx = strrep("  ", level);
+        printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf)));
+
+        if (node->type == BUS_MATCH_VALUE) {
+                if (node->parent->type == BUS_MATCH_MESSAGE_TYPE)
+                        printf(" <%u>\n", node->value.u8);
+                else
+                        printf(" <%s>\n", node->value.str);
+        } else if (node->type == BUS_MATCH_ROOT)
+                puts(" root");
+        else if (node->type == BUS_MATCH_LEAF)
+                printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
+        else
+                putchar('\n');
+
+        if (BUS_MATCH_CAN_HASH(node->type)) {
+                Iterator i;
+
+                HASHMAP_FOREACH(c, node->compare.children, i)
+                        bus_match_dump(c, level + 1);
+        }
+
+        for (c = node->child; c; c = c->next)
+                bus_match_dump(c, level + 1);
+}
diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h
new file mode 100644
index 0000000..056082b
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-match.h
@@ -0,0 +1,93 @@
+/*-*- 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 "hashmap.h"
+
+#include "sd-bus.h"
+
+enum bus_match_node_type {
+        BUS_MATCH_ROOT,
+        BUS_MATCH_VALUE,
+        BUS_MATCH_LEAF,
+
+        /* The following are all different kinds of compare nodes */
+        BUS_MATCH_SENDER,
+        BUS_MATCH_MESSAGE_TYPE,
+        BUS_MATCH_DESTINATION,
+        BUS_MATCH_INTERFACE,
+        BUS_MATCH_MEMBER,
+        BUS_MATCH_PATH,
+        BUS_MATCH_PATH_NAMESPACE,
+        BUS_MATCH_ARG,
+        BUS_MATCH_ARG_LAST = BUS_MATCH_ARG + 63,
+        BUS_MATCH_ARG_PATH,
+        BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63,
+        BUS_MATCH_ARG_NAMESPACE,
+        BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63,
+        _BUS_MATCH_NODE_TYPE_MAX,
+        _BUS_MATCH_NODE_TYPE_INVALID = -1
+};
+
+struct bus_match_node {
+        enum bus_match_node_type type;
+        struct bus_match_node *parent, *next, *prev, *child;
+
+        union {
+                struct {
+                        char *str;
+                        uint8_t u8;
+                } value;
+                struct {
+                        sd_bus_message_handler_t callback;
+                        void *userdata;
+                        unsigned last_iteration;
+                        uint64_t cookie;
+                } leaf;
+                struct {
+                        /* If this is set, then the child is NULL */
+                        Hashmap *children;
+                } compare;
+        };
+};
+
+struct bus_match_component {
+        enum bus_match_node_type type;
+        uint8_t value_u8;
+        char *value_str;
+};
+
+int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
+
+int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t cookie, struct bus_match_node **ret);
+int bus_match_remove(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t *cookie);
+
+void bus_match_free(struct bus_match_node *node);
+
+void bus_match_dump(struct bus_match_node *node, unsigned level);
+
+const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l);
+enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n);
+
+int bus_match_parse(const char *match, struct bus_match_component **_components, unsigned *_n_components);
+void bus_match_parse_free(struct bus_match_component *components, unsigned n_components);
+char *bus_match_to_string(struct bus_match_component *components, unsigned n_components);
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
new file mode 100644
index 0000000..1a2039b
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -0,0 +1,5535 @@
+/*-*- 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 <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "utf8.h"
+#include "strv.h"
+#include "time-util.h"
+#include "cgroup-util.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#include "bus-internal.h"
+#include "bus-type.h"
+#include "bus-signature.h"
+#include "bus-gvariant.h"
+#include "bus-util.h"
+
+static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
+
+static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
+
+        if (p == NULL)
+                return NULL;
+
+        if (old_base == new_base)
+                return (void*) p;
+
+        if ((uint8_t*) p < (uint8_t*) old_base)
+                return (void*) p;
+
+        if ((uint8_t*) p >= (uint8_t*) old_base + sz)
+                return (void*) p;
+
+        return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
+}
+
+static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
+        assert(m);
+        assert(part);
+
+        if (part->memfd >= 0) {
+                /* If we can reuse the memfd, try that. For that it
+                 * can't be sealed yet. */
+
+                if (!part->sealed)
+                        bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
+                else {
+                        if (part->mapped > 0)
+                                assert_se(munmap(part->data, part->mapped) == 0);
+
+                        close_nointr_nofail(part->memfd);
+                }
+
+        } else if (part->munmap_this)
+                munmap(part->data, part->mapped);
+        else if (part->free_this)
+                free(part->data);
+
+        if (part != &m->body)
+                free(part);
+}
+
+static void message_reset_parts(sd_bus_message *m) {
+        struct bus_body_part *part;
+
+        assert(m);
+
+        part = &m->body;
+        while (m->n_body_parts > 0) {
+                struct bus_body_part *next = part->next;
+                message_free_part(m, part);
+                part = next;
+                m->n_body_parts--;
+        }
+
+        m->body_end = NULL;
+
+        m->cached_rindex_part = NULL;
+        m->cached_rindex_part_begin = 0;
+}
+
+static void message_reset_containers(sd_bus_message *m) {
+        unsigned i;
+
+        assert(m);
+
+        for (i = 0; i < m->n_containers; i++) {
+                free(m->containers[i].signature);
+                free(m->containers[i].offsets);
+        }
+
+        free(m->containers);
+        m->containers = NULL;
+
+        m->n_containers = m->containers_allocated = 0;
+        m->root_container.index = 0;
+}
+
+static void message_free(sd_bus_message *m) {
+        assert(m);
+
+        if (m->free_header)
+                free(m->header);
+
+        message_reset_parts(m);
+
+        if (m->free_kdbus)
+                free(m->kdbus);
+
+        if (m->release_kdbus) {
+                uint64_t off;
+
+                off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer;
+                ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off);
+        }
+
+        if (m->bus)
+                sd_bus_unref(m->bus);
+
+        if (m->free_fds) {
+                close_many(m->fds, m->n_fds);
+                free(m->fds);
+        }
+
+        if (m->iovec != m->iovec_fixed)
+                free(m->iovec);
+
+        message_reset_containers(m);
+        free(m->root_container.signature);
+        free(m->root_container.offsets);
+
+        free(m->root_container.peeked_signature);
+
+        bus_creds_done(&m->creds);
+        free(m);
+}
+
+static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
+        void *op, *np;
+        size_t old_size, new_size, start;
+
+        assert(m);
+
+        if (m->poisoned)
+                return NULL;
+
+        old_size = sizeof(struct bus_header) + m->header->fields_size;
+        start = ALIGN_TO(old_size, align);
+        new_size = start + sz;
+
+        if (old_size == new_size)
+                return (uint8_t*) m->header + old_size;
+
+        if (new_size > (size_t) ((uint32_t) -1))
+                goto poison;
+
+        if (m->free_header) {
+                np = realloc(m->header, ALIGN8(new_size));
+                if (!np)
+                        goto poison;
+        } else {
+                /* Initially, the header is allocated as part of of
+                 * the sd_bus_message itself, let's replace it by
+                 * dynamic data */
+
+                np = malloc(ALIGN8(new_size));
+                if (!np)
+                        goto poison;
+
+                memcpy(np, m->header, sizeof(struct bus_header));
+        }
+
+        /* Zero out padding */
+        if (start > old_size)
+                memset((uint8_t*) np + old_size, 0, start - old_size);
+
+        op = m->header;
+        m->header = np;
+        m->header->fields_size = new_size - sizeof(struct bus_header);
+
+        /* Adjust quick access pointers */
+        m->path = adjust_pointer(m->path, op, old_size, m->header);
+        m->interface = adjust_pointer(m->interface, op, old_size, m->header);
+        m->member = adjust_pointer(m->member, op, old_size, m->header);
+        m->destination = adjust_pointer(m->destination, op, old_size, m->header);
+        m->sender = adjust_pointer(m->sender, op, old_size, m->header);
+        m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
+
+        m->free_header = true;
+
+        if (add_offset) {
+                if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
+                        goto poison;
+
+                m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
+        }
+
+        return (uint8_t*) np + start;
+
+poison:
+        m->poisoned = true;
+        return NULL;
+}
+
+static int message_append_field_string(
+                sd_bus_message *m,
+                uint8_t h,
+                char type,
+                const char *s,
+                const char **ret) {
+
+        size_t l;
+        uint8_t *p;
+
+        assert(m);
+
+        /* dbus1 doesn't allow strings over 32bit, let's enforce this
+         * globally, to not risk convertability */
+        l = strlen(s);
+        if (l > (size_t) (uint32_t) -1)
+                return -EINVAL;
+
+        /* Signature "(yv)" where the variant contains "s" */
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+
+                /* (field id byte + 7x padding, ((string + NUL) + NUL + signature string 's') */
+                p = message_extend_fields(m, 8, 1 + 7 + l + 1 + 1 + 1, true);
+                if (!p)
+                        return -ENOMEM;
+
+                p[0] = h;
+                memset(p+1, 0, 7);
+                memcpy(p+8, s, l);
+                p[8+l] = 0;
+                p[8+l+1] = 0;
+                p[8+l+2] = type;
+
+                if (ret)
+                        *ret = (char*) p + 8;
+
+        } else {
+                /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
+                p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
+                if (!p)
+                        return -ENOMEM;
+
+                p[0] = h;
+                p[1] = 1;
+                p[2] = type;
+                p[3] = 0;
+
+                ((uint32_t*) p)[1] = l;
+                memcpy(p + 8, s, l + 1);
+
+                if (ret)
+                        *ret = (char*) p + 8;
+        }
+
+        return 0;
+}
+
+static int message_append_field_signature(
+                sd_bus_message *m,
+                uint8_t h,
+                const char *s,
+                const char **ret) {
+
+        size_t l;
+        uint8_t *p;
+
+        assert(m);
+
+        /* dbus1 doesn't allow signatures over 32bit, let's enforce
+         * this globally, to not risk convertability */
+        l = strlen(s);
+        if (l > 255)
+                return -EINVAL;
+
+        /* Signature "(yv)" where the variant contains "g" */
+
+        if (BUS_MESSAGE_IS_GVARIANT(m))
+                /* For gvariant the serialization is the same as for normal strings */
+                return message_append_field_string(m, h, 'g', s, ret);
+        else {
+                /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
+                p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
+                if (!p)
+                        return -ENOMEM;
+
+                p[0] = h;
+                p[1] = 1;
+                p[2] = SD_BUS_TYPE_SIGNATURE;
+                p[3] = 0;
+                p[4] = l;
+                memcpy(p + 5, s, l + 1);
+
+                if (ret)
+                        *ret = (const char*) p + 5;
+        }
+
+        return 0;
+}
+
+static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) {
+        uint8_t *p;
+
+        assert(m);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                /* (field id byte + 7x padding + ((value + NUL + signature string 'u') */
+
+                p = message_extend_fields(m, 8, 1 + 7 + 4 + 1 + 1, true);
+                if (!p)
+                        return -ENOMEM;
+
+                p[0] = h;
+                memset(p+1, 0, 7);
+                *((uint32_t*) (p + 8)) = x;
+                p[12] = 0;
+                p[13] = 'u';
+        } else {
+                /* (field id byte + (signature length + signature 'u' + NUL) + value) */
+                p = message_extend_fields(m, 8, 4 + 4, false);
+                if (!p)
+                        return -ENOMEM;
+
+                p[0] = h;
+                p[1] = 1;
+                p[2] = SD_BUS_TYPE_UINT32;
+                p[3] = 0;
+
+                ((uint32_t*) p)[1] = x;
+        }
+
+        return 0;
+}
+
+int bus_message_from_header(
+                sd_bus *bus,
+                void *buffer,
+                size_t length,
+                int *fds,
+                unsigned n_fds,
+                const struct ucred *ucred,
+                const char *label,
+                size_t extra,
+                sd_bus_message **ret) {
+
+        sd_bus_message *m;
+        struct bus_header *h;
+        size_t a, label_sz;
+
+        assert(buffer || length <= 0);
+        assert(fds || n_fds <= 0);
+        assert(ret);
+
+        if (length < sizeof(struct bus_header))
+                return -EBADMSG;
+
+        h = buffer;
+        if (h->version != 1 &&
+            h->version != 2)
+                return -EBADMSG;
+
+        if (h->serial == 0)
+                return -EBADMSG;
+
+        if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
+                return -EBADMSG;
+
+        if (h->endian != BUS_LITTLE_ENDIAN &&
+            h->endian != BUS_BIG_ENDIAN)
+                return -EBADMSG;
+
+        a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
+
+        if (label) {
+                label_sz = strlen(label);
+                a += label_sz + 1;
+        }
+
+        m = malloc0(a);
+        if (!m)
+                return -ENOMEM;
+
+        m->n_ref = 1;
+        m->sealed = true;
+        m->header = h;
+        m->fds = fds;
+        m->n_fds = n_fds;
+
+        if (ucred) {
+                m->creds.uid = ucred->uid;
+                m->creds.pid = ucred->pid;
+                m->creds.gid = ucred->gid;
+                m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID;
+        }
+
+        if (label) {
+                m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
+                memcpy(m->creds.label, label, label_sz + 1);
+
+                m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+        }
+
+        if (bus)
+                m->bus = sd_bus_ref(bus);
+
+        *ret = m;
+        return 0;
+}
+
+int bus_message_from_malloc(
+                sd_bus *bus,
+                void *buffer,
+                size_t length,
+                int *fds,
+                unsigned n_fds,
+                const struct ucred *ucred,
+                const char *label,
+                sd_bus_message **ret) {
+
+        sd_bus_message *m;
+        size_t sz;
+        int r;
+
+        r = bus_message_from_header(bus, buffer, length, fds, n_fds, ucred, label, 0, &m);
+        if (r < 0)
+                return r;
+
+        if (length != BUS_MESSAGE_SIZE(m)) {
+                r = -EBADMSG;
+                goto fail;
+        }
+
+        sz = length - sizeof(struct bus_header) - ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
+        if (sz > 0) {
+                m->n_body_parts = 1;
+                m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
+                m->body.size = sz;
+                m->body.sealed = true;
+                m->body.memfd = -1;
+        }
+
+        m->n_iovec = 1;
+        m->iovec = m->iovec_fixed;
+        m->iovec[0].iov_base = buffer;
+        m->iovec[0].iov_len = length;
+
+        r = bus_message_parse_fields(m);
+        if (r < 0)
+                goto fail;
+
+        /* We take possession of the memory and fds now */
+        m->free_header = true;
+        m->free_fds = true;
+
+        *ret = m;
+        return 0;
+
+fail:
+        message_free(m);
+        return r;
+}
+
+static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
+        sd_bus_message *m;
+
+        m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
+        if (!m)
+                return NULL;
+
+        m->n_ref = 1;
+        m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
+        m->header->endian = BUS_NATIVE_ENDIAN;
+        m->header->type = type;
+        m->header->version = bus ? bus->message_version : 1;
+        m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
+        m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
+
+        if (bus)
+                m->bus = sd_bus_ref(bus);
+
+        return m;
+}
+
+_public_ int sd_bus_message_new_signal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_message **m) {
+
+        sd_bus_message *t;
+        int r;
+
+        assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(m, -EINVAL);
+
+        t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
+        if (!t)
+                return -ENOMEM;
+
+        t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
+        if (r < 0)
+                goto fail;
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
+        if (r < 0)
+                goto fail;
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
+        if (r < 0)
+                goto fail;
+
+        *m = t;
+        return 0;
+
+fail:
+        sd_bus_message_unref(t);
+        return r;
+}
+
+_public_ int sd_bus_message_new_method_call(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const char *interface,
+                const char *member,
+                sd_bus_message **m) {
+
+        sd_bus_message *t;
+        int r;
+
+        assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(!destination || service_name_is_valid(destination), -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
+        assert_return(member_name_is_valid(member), -EINVAL);
+        assert_return(m, -EINVAL);
+
+        t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
+        if (!t)
+                return -ENOMEM;
+
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
+        if (r < 0)
+                goto fail;
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
+        if (r < 0)
+                goto fail;
+
+        if (interface) {
+                r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
+                if (r < 0)
+                        goto fail;
+        }
+
+        if (destination) {
+                r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
+                if (r < 0)
+                        goto fail;
+        }
+
+        *m = t;
+        return 0;
+
+fail:
+        message_free(t);
+        return r;
+}
+
+static int message_new_reply(
+                sd_bus_message *call,
+                uint8_t type,
+                sd_bus_message **m) {
+
+        sd_bus_message *t;
+        int r;
+
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(!call->bus || call->bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(m, -EINVAL);
+
+        t = message_new(call->bus, type);
+        if (!t)
+                return -ENOMEM;
+
+        t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+        t->reply_cookie = BUS_MESSAGE_COOKIE(call);
+
+        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
+        if (r < 0)
+                goto fail;
+
+        if (call->sender) {
+                r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
+                if (r < 0)
+                        goto fail;
+        }
+
+        t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
+        t->enforced_reply_signature = call->enforced_reply_signature;
+
+        *m = t;
+        return 0;
+
+fail:
+        message_free(t);
+        return r;
+}
+
+_public_ int sd_bus_message_new_method_return(
+                sd_bus_message *call,
+                sd_bus_message **m) {
+
+        return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
+}
+
+_public_ int sd_bus_message_new_method_error(
+                sd_bus_message *call,
+                const sd_bus_error *e,
+                sd_bus_message **m) {
+
+        sd_bus_message *t;
+        int r;
+
+        assert_return(sd_bus_error_is_set(e), -EINVAL);
+        assert_return(m, -EINVAL);
+
+        r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
+        if (r < 0)
+                return r;
+
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
+        if (r < 0)
+                goto fail;
+
+        if (e->message) {
+                r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
+                if (r < 0)
+                        goto fail;
+        }
+
+        t->error._need_free = -1;
+
+        *m = t;
+        return 0;
+
+fail:
+        message_free(t);
+        return r;
+}
+
+_public_ int sd_bus_message_new_method_errorf(
+                sd_bus_message *call,
+                sd_bus_message **m,
+                const char *name,
+                const char *format,
+                ...) {
+
+        _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        va_list ap;
+
+        assert_return(name, -EINVAL);
+        assert_return(m, -EINVAL);
+
+        va_start(ap, format);
+        bus_error_setfv(&error, name, format, ap);
+        va_end(ap);
+
+        return sd_bus_message_new_method_error(call, &error, m);
+}
+
+_public_ int sd_bus_message_new_method_errno(
+                sd_bus_message *call,
+                int error,
+                const sd_bus_error *p,
+                sd_bus_message **m) {
+
+        _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+
+        if (sd_bus_error_is_set(p))
+                return sd_bus_message_new_method_error(call, p, m);
+
+        sd_bus_error_set_errno(&berror, error);
+
+        return sd_bus_message_new_method_error(call, &berror, m);
+}
+
+_public_ int sd_bus_message_new_method_errnof(
+                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;
+
+        va_start(ap, format);
+        bus_error_set_errnofv(&berror, error, format, ap);
+        va_end(ap);
+
+        return sd_bus_message_new_method_error(call, &berror, m);
+}
+
+int bus_message_new_synthetic_error(
+                sd_bus *bus,
+                uint64_t cookie,
+                const sd_bus_error *e,
+                sd_bus_message **m) {
+
+        sd_bus_message *t;
+        int r;
+
+        assert(sd_bus_error_is_set(e));
+        assert(m);
+
+        t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
+        if (!t)
+                return -ENOMEM;
+
+        t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+        t->reply_cookie = cookie;
+
+        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
+        if (r < 0)
+                goto fail;
+
+        if (bus && bus->unique_name) {
+                r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
+                if (r < 0)
+                        goto fail;
+        }
+
+        r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
+        if (r < 0)
+                goto fail;
+
+        if (e->message) {
+                r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
+                if (r < 0)
+                        goto fail;
+        }
+
+        t->error._need_free = -1;
+
+        *m = t;
+        return 0;
+
+fail:
+        message_free(t);
+        return r;
+}
+
+_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        assert(m->n_ref > 0);
+        m->n_ref++;
+
+        return m;
+}
+
+_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
+
+        if (!m)
+                return NULL;
+
+        assert(m->n_ref > 0);
+        m->n_ref--;
+
+        if (m->n_ref <= 0)
+                message_free(m);
+
+        return NULL;
+}
+
+_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
+        assert_return(m, -EINVAL);
+        assert_return(type, -EINVAL);
+
+        *type = m->header->type;
+        return 0;
+}
+
+_public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
+        assert_return(m, -EINVAL);
+        assert_return(cookie, -EINVAL);
+        assert_return(m->header->serial != 0, -ENODATA);
+
+        *cookie = BUS_MESSAGE_COOKIE(m);
+        return 0;
+}
+
+_public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
+        assert_return(m, -EINVAL);
+        assert_return(cookie, -EINVAL);
+        assert_return(m->reply_cookie != 0, -ENODATA);
+
+        *cookie = m->reply_cookie;
+        return 0;
+}
+
+_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
+
+        return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
+}
+
+_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
+
+        return !!(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
+}
+
+_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        return m->path;
+}
+
+_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        return m->interface;
+}
+
+_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        return m->member;
+}
+
+_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        return m->destination;
+}
+
+_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        return m->sender;
+}
+
+_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
+        assert_return(m, NULL);
+        assert_return(sd_bus_error_is_set(&m->error), NULL);
+
+        return &m->error;
+}
+
+_public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) {
+        assert_return(m, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(m->monotonic > 0, -ENODATA);
+
+        *usec = m->monotonic;
+        return 0;
+}
+
+_public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) {
+        assert_return(m, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(m->realtime > 0, -ENODATA);
+
+        *usec = m->realtime;
+        return 0;
+}
+
+_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        if (m->creds.mask == 0)
+                return NULL;
+
+        return &m->creds;
+}
+
+_public_ int sd_bus_message_is_signal(sd_bus_message *m,
+                                      const char *interface,
+                                      const char *member) {
+        assert_return(m, -EINVAL);
+
+        if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
+                return 0;
+
+        if (interface && (!m->interface || !streq(m->interface, interface)))
+                return 0;
+
+        if (member &&  (!m->member || !streq(m->member, member)))
+                return 0;
+
+        return 1;
+}
+
+_public_ int sd_bus_message_is_method_call(sd_bus_message *m,
+                                           const char *interface,
+                                           const char *member) {
+        assert_return(m, -EINVAL);
+
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
+                return 0;
+
+        if (interface && (!m->interface || !streq(m->interface, interface)))
+                return 0;
+
+        if (member &&  (!m->member || !streq(m->member, member)))
+                return 0;
+
+        return 1;
+}
+
+_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
+        assert_return(m, -EINVAL);
+
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
+                return 0;
+
+        if (name && (!m->error.name || !streq(m->error.name, name)))
+                return 0;
+
+        return 1;
+}
+
+_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
+
+        if (b)
+                m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+        else
+                m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
+
+        return 0;
+}
+
+_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        if (b)
+                m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
+        else
+                m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
+
+        return 0;
+}
+
+static struct bus_container *message_get_container(sd_bus_message *m) {
+        assert(m);
+
+        if (m->n_containers == 0)
+                return &m->root_container;
+
+        assert(m->containers);
+        return m->containers + m->n_containers - 1;
+}
+
+struct bus_body_part *message_append_part(sd_bus_message *m) {
+        struct bus_body_part *part;
+
+        assert(m);
+
+        if (m->poisoned)
+                return NULL;
+
+        if (m->n_body_parts <= 0) {
+                part = &m->body;
+                zero(*part);
+        } else {
+                assert(m->body_end);
+
+                part = new0(struct bus_body_part, 1);
+                if (!part) {
+                        m->poisoned = true;
+                        return NULL;
+                }
+
+                m->body_end->next = part;
+        }
+
+        part->memfd = -1;
+        m->body_end = part;
+        m->n_body_parts ++;
+
+        return part;
+}
+
+static void part_zero(struct bus_body_part *part, size_t sz) {
+        assert(part);
+        assert(sz > 0);
+        assert(sz < 8);
+
+        /* All other fields can be left in their defaults */
+        assert(!part->data);
+        assert(part->memfd < 0);
+
+        part->size = sz;
+        part->is_zero = true;
+        part->sealed = true;
+}
+
+static int part_make_space(
+                struct sd_bus_message *m,
+                struct bus_body_part *part,
+                size_t sz,
+                void **q) {
+
+        void *n;
+        int r;
+
+        assert(m);
+        assert(part);
+        assert(!part->sealed);
+
+        if (m->poisoned)
+                return -ENOMEM;
+
+        if (!part->data && part->memfd < 0)
+                part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
+
+        if (part->memfd >= 0) {
+
+                if (part->allocated == 0 || sz > part->allocated) {
+                        uint64_t new_allocated;
+
+                        new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
+                        r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated);
+                        if (r < 0) {
+                                m->poisoned = true;
+                                return -errno;
+                        }
+
+                        part->allocated = new_allocated;
+                }
+
+                if (!part->data || sz > part->mapped) {
+                        size_t psz;
+
+                        psz = PAGE_ALIGN(sz > 0 ? sz : 1);
+                        if (part->mapped <= 0)
+                                n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
+                        else
+                                n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
+
+                        if (n == MAP_FAILED) {
+                                m->poisoned = true;
+                                return -errno;
+                        }
+
+                        part->mapped = psz;
+                        part->data = n;
+                }
+
+                part->munmap_this = true;
+        } else {
+                if (part->allocated == 0 || sz > part->allocated) {
+                        size_t new_allocated;
+
+                        new_allocated = sz > 0 ? 2 * sz : 64;
+                        n = realloc(part->data, new_allocated);
+                        if (!n) {
+                                m->poisoned = true;
+                                return -ENOMEM;
+                        }
+
+                        part->data = n;
+                        part->allocated = new_allocated;
+                        part->free_this = true;
+                }
+        }
+
+        if (q)
+                *q = part->data ? (uint8_t*) part->data + part->size : NULL;
+
+        part->size = sz;
+        return 0;
+}
+
+static int message_add_offset(sd_bus_message *m, size_t offset) {
+        struct bus_container *c;
+
+        assert(m);
+        assert(BUS_MESSAGE_IS_GVARIANT(m));
+
+        /* Add offset to current container, unless this is the first
+         * item in it, which will have the 0 offset, which we can
+         * ignore. */
+        c = message_get_container(m);
+
+        if (!c->need_offsets)
+                return 0;
+
+        if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
+                return -ENOMEM;
+
+        c->offsets[c->n_offsets++] = offset;
+        return 0;
+}
+
+static void message_extend_containers(sd_bus_message *m, size_t expand) {
+        struct bus_container *c;
+
+        assert(m);
+
+        if (expand <= 0)
+                return;
+
+        /* Update counters */
+        for (c = m->containers; c < m->containers + m->n_containers; c++) {
+
+                if (c->array_size)
+                        *c->array_size += expand;
+        }
+}
+
+static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
+        size_t start_body, end_body, padding, added;
+        void *p;
+        int r;
+
+        assert(m);
+        assert(align > 0);
+        assert(!m->sealed);
+
+        if (m->poisoned)
+                return NULL;
+
+        start_body = ALIGN_TO((size_t) m->header->body_size, align);
+        end_body = start_body + sz;
+
+        padding = start_body - m->header->body_size;
+        added = padding + sz;
+
+        /* Check for 32bit overflows */
+        if (end_body > (size_t) ((uint32_t) -1)) {
+                m->poisoned = true;
+                return NULL;
+        }
+
+        if (added > 0) {
+                struct bus_body_part *part = NULL;
+                bool add_new_part;
+
+                add_new_part =
+                        m->n_body_parts <= 0 ||
+                        m->body_end->sealed ||
+                        padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
+
+                if (add_new_part) {
+                        if (padding > 0) {
+                                part = message_append_part(m);
+                                if (!part)
+                                        return NULL;
+
+                                part_zero(part, padding);
+                        }
+
+                        part = message_append_part(m);
+                        if (!part)
+                                return NULL;
+
+                        r = part_make_space(m, part, sz, &p);
+                        if (r < 0)
+                                return NULL;
+                } else {
+                        struct bus_container *c;
+                        void *op;
+                        size_t os, start_part, end_part;
+
+                        part = m->body_end;
+                        op = part->data;
+                        os = part->size;
+
+                        start_part = ALIGN_TO(part->size, align);
+                        end_part = start_part + sz;
+
+                        r = part_make_space(m, part, end_part, &p);
+                        if (r < 0)
+                                return NULL;
+
+                        if (padding > 0) {
+                                memset(p, 0, padding);
+                                p = (uint8_t*) p + padding;
+                        }
+
+                        /* Readjust pointers */
+                        for (c = m->containers; c < m->containers + m->n_containers; c++)
+                                c->array_size = adjust_pointer(c->array_size, op, os, part->data);
+
+                        m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
+                }
+        } else
+                /* Return something that is not NULL and is aligned */
+                p = (uint8_t *) NULL + align;
+
+        m->header->body_size = end_body;
+        message_extend_containers(m, added);
+
+        if (add_offset) {
+                r = message_add_offset(m, end_body);
+                if (r < 0) {
+                        m->poisoned = true;
+                        return NULL;
+                }
+        }
+
+        return p;
+}
+
+static int message_push_fd(sd_bus_message *m, int fd) {
+        int *f, copy;
+
+        assert(m);
+
+        if (fd < 0)
+                return -EINVAL;
+
+        if (!m->allow_fds)
+                return -ENOTSUP;
+
+        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+        if (copy < 0)
+                return -errno;
+
+        f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
+        if (!f) {
+                m->poisoned = true;
+                close_nointr_nofail(copy);
+                return -ENOMEM;
+        }
+
+        m->fds = f;
+        m->fds[m->n_fds] = copy;
+        m->free_fds = true;
+
+        return copy;
+}
+
+int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
+        _cleanup_close_ int fd = -1;
+        struct bus_container *c;
+        ssize_t align, sz;
+        void *a;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(bus_type_is_basic(type), -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        c = message_get_container(m);
+
+        if (c->signature && c->signature[c->index]) {
+                /* Container signature is already set */
+
+                if (c->signature[c->index] != type)
+                        return -ENXIO;
+        } else {
+                char *e;
+
+                /* Maybe we can append to the signature? But only if this is the top-level container*/
+                if (c->enclosing != 0)
+                        return -ENXIO;
+
+                e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
+                if (!e) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+        }
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                uint8_t u8;
+                uint32_t u32;
+
+                switch (type) {
+
+                case SD_BUS_TYPE_SIGNATURE:
+                case SD_BUS_TYPE_STRING:
+                        p = strempty(p);
+
+                        /* Fall through... */
+                case SD_BUS_TYPE_OBJECT_PATH:
+                        if (!p)
+                                return -EINVAL;
+
+                        align = 1;
+                        sz = strlen(p) + 1;
+                        break;
+
+                case SD_BUS_TYPE_BOOLEAN:
+
+                        u8 = p && *(int*) p;
+                        p = &u8;
+
+                        align = sz = 1;
+                        break;
+
+                case SD_BUS_TYPE_UNIX_FD:
+
+                        if (!p)
+                                return -EINVAL;
+
+                        fd = message_push_fd(m, *(int*) p);
+                        if (fd < 0)
+                                return fd;
+
+                        u32 = m->n_fds;
+                        p = &u32;
+
+                        align = sz = 4;
+                        break;
+
+                default:
+                        align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
+                        sz = bus_gvariant_get_size(CHAR_TO_STR(type));
+                        break;
+                }
+
+                assert(align > 0);
+                assert(sz > 0);
+
+                a = message_extend_body(m, align, sz, true);
+                if (!a)
+                        return -ENOMEM;
+
+                memcpy(a, p, sz);
+
+                if (stored)
+                        *stored = (const uint8_t*) a;
+
+        } else {
+                uint32_t u32;
+
+                switch (type) {
+
+                case SD_BUS_TYPE_STRING:
+                        /* To make things easy we'll serialize a NULL string
+                         * into the empty string */
+                        p = strempty(p);
+
+                        /* Fall through... */
+                case SD_BUS_TYPE_OBJECT_PATH:
+
+                        if (!p)
+                                return -EINVAL;
+
+                        align = 4;
+                        sz = 4 + strlen(p) + 1;
+                        break;
+
+                case SD_BUS_TYPE_SIGNATURE:
+
+                        p = strempty(p);
+
+                        align = 1;
+                        sz = 1 + strlen(p) + 1;
+                        break;
+
+                case SD_BUS_TYPE_BOOLEAN:
+
+                        u32 = p && *(int*) p;
+                        p = &u32;
+
+                        align = sz = 4;
+                        break;
+
+                case SD_BUS_TYPE_UNIX_FD:
+
+                        if (!p)
+                                return -EINVAL;
+
+                        fd = message_push_fd(m, *(int*) p);
+                        if (fd < 0)
+                                return fd;
+
+                        u32 = m->n_fds;
+                        p = &u32;
+
+                        align = sz = 4;
+                        break;
+
+                default:
+                        align = bus_type_get_alignment(type);
+                        sz = bus_type_get_size(type);
+                        break;
+                }
+
+                assert(align > 0);
+                assert(sz > 0);
+
+                a = message_extend_body(m, align, sz, false);
+                if (!a)
+                        return -ENOMEM;
+
+                if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
+                        *(uint32_t*) a = sz - 5;
+                        memcpy((uint8_t*) a + 4, p, sz - 4);
+
+                        if (stored)
+                                *stored = (const uint8_t*) a + 4;
+
+                } else if (type == SD_BUS_TYPE_SIGNATURE) {
+                        *(uint8_t*) a = sz - 2;
+                        memcpy((uint8_t*) a + 1, p, sz - 1);
+
+                        if (stored)
+                                *stored = (const uint8_t*) a + 1;
+                } else {
+                        memcpy(a, p, sz);
+
+                        if (stored)
+                                *stored = a;
+                }
+        }
+
+        if (type == SD_BUS_TYPE_UNIX_FD)
+                m->n_fds ++;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index++;
+
+        fd = -1;
+        return 0;
+}
+
+_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
+        return message_append_basic(m, type, p, NULL);
+}
+
+_public_ int sd_bus_message_append_string_space(
+                sd_bus_message *m,
+                size_t size,
+                char **s) {
+
+        struct bus_container *c;
+        void *a;
+
+        assert_return(m, -EINVAL);
+        assert_return(s, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->poisoned, -ESTALE);
+
+        c = message_get_container(m);
+
+        if (c->signature && c->signature[c->index]) {
+                /* Container signature is already set */
+
+                if (c->signature[c->index] != SD_BUS_TYPE_STRING)
+                        return -ENXIO;
+        } else {
+                char *e;
+
+                /* Maybe we can append to the signature? But only if this is the top-level container*/
+                if (c->enclosing != 0)
+                        return -ENXIO;
+
+                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
+                if (!e) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+        }
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                a = message_extend_body(m, 1, size + 1, true);
+                if (!a)
+                        return -ENOMEM;
+
+                *s = a;
+        } else {
+                a = message_extend_body(m, 4, 4 + size + 1, false);
+                if (!a)
+                        return -ENOMEM;
+
+                *(uint32_t*) a = size;
+                *s = (char*) a + 4;
+        }
+
+        (*s)[size] = 0;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index++;
+
+        return 0;
+}
+
+_public_ int sd_bus_message_append_string_iovec(
+                sd_bus_message *m,
+                const struct iovec *iov,
+                unsigned n) {
+
+        size_t size;
+        unsigned i;
+        char *p;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(iov || n == 0, -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        size = IOVEC_TOTAL_SIZE(iov, n);
+
+        r = sd_bus_message_append_string_space(m, size, &p);
+        if (r < 0)
+                return r;
+
+        for (i = 0; i < n; i++) {
+
+                if (iov[i].iov_base)
+                        memcpy(p, iov[i].iov_base, iov[i].iov_len);
+                else
+                        memset(p, ' ', iov[i].iov_len);
+
+                p += iov[i].iov_len;
+        }
+
+        return 0;
+}
+
+static int bus_message_open_array(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                uint32_t **array_size,
+                size_t *begin,
+                bool *need_offsets) {
+
+        unsigned nindex;
+        int alignment, r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(array_size);
+        assert(begin);
+        assert(need_offsets);
+
+        if (!signature_is_single(contents, true))
+                return -EINVAL;
+
+        if (c->signature && c->signature[c->index]) {
+
+                /* Verify the existing signature */
+
+                if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
+                        return -ENXIO;
+
+                if (!startswith(c->signature + c->index + 1, contents))
+                        return -ENXIO;
+
+                nindex = c->index + 1 + strlen(contents);
+        } else {
+                char *e;
+
+                if (c->enclosing != 0)
+                        return -ENXIO;
+
+                /* Extend the existing signature */
+
+                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
+                if (!e) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+
+                nindex = e - c->signature;
+        }
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                alignment = bus_gvariant_get_alignment(contents);
+                if (alignment < 0)
+                        return alignment;
+
+                /* Add alignment padding and add to offset list */
+                if (!message_extend_body(m, alignment, 0, false))
+                        return -ENOMEM;
+
+                r = bus_gvariant_is_fixed_size(contents);
+                if (r < 0)
+                        return r;
+
+                *begin = m->header->body_size;
+                *need_offsets = r == 0;
+        } else {
+                void *a, *op;
+                size_t os;
+                struct bus_body_part *o;
+
+                alignment = bus_type_get_alignment(contents[0]);
+                if (alignment < 0)
+                        return alignment;
+
+                a = message_extend_body(m, 4, 4, false);
+                if (!a)
+                        return -ENOMEM;
+
+                o = m->body_end;
+                op = m->body_end->data;
+                os = m->body_end->size;
+
+                /* Add alignment between size and first element */
+                if (!message_extend_body(m, alignment, 0, false))
+                        return -ENOMEM;
+
+                /* location of array size might have changed so let's readjust a */
+                if (o == m->body_end)
+                        a = adjust_pointer(a, op, os, m->body_end->data);
+
+                *(uint32_t*) a = 0;
+                *array_size = a;
+        }
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index = nindex;
+
+        return 0;
+}
+
+static int bus_message_open_variant(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents) {
+
+        assert(m);
+        assert(c);
+        assert(contents);
+
+        if (!signature_is_single(contents, false))
+                return -EINVAL;
+
+        if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
+                return -EINVAL;
+
+        if (c->signature && c->signature[c->index]) {
+
+                if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
+                        return -ENXIO;
+
+        } else {
+                char *e;
+
+                if (c->enclosing != 0)
+                        return -ENXIO;
+
+                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
+                if (!e) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+        }
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                /* Variants are always aligned to 8 */
+
+                if (!message_extend_body(m, 8, 0, false))
+                        return -ENOMEM;
+
+        } else {
+                size_t l;
+                void *a;
+
+                l = strlen(contents);
+                a = message_extend_body(m, 1, 1 + l + 1, false);
+                if (!a)
+                        return -ENOMEM;
+
+                *(uint8_t*) a = l;
+                memcpy((uint8_t*) a + 1, contents, l + 1);
+        }
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index++;
+
+        return 0;
+}
+
+static int bus_message_open_struct(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                size_t *begin,
+                bool *need_offsets) {
+
+        size_t nindex;
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(begin);
+        assert(need_offsets);
+
+        if (!signature_is_valid(contents, false))
+                return -EINVAL;
+
+        if (c->signature && c->signature[c->index]) {
+                size_t l;
+
+                l = strlen(contents);
+
+                if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
+                    !startswith(c->signature + c->index + 1, contents) ||
+                    c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
+                        return -ENXIO;
+
+                nindex = c->index + 1 + l + 1;
+        } else {
+                char *e;
+
+                if (c->enclosing != 0)
+                        return -ENXIO;
+
+                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
+                if (!e) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+
+                nindex = e - c->signature;
+        }
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                int alignment;
+
+                alignment = bus_gvariant_get_alignment(contents);
+                if (alignment < 0)
+                        return alignment;
+
+                if (!message_extend_body(m, alignment, 0, false))
+                        return -ENOMEM;
+
+                r = bus_gvariant_is_fixed_size(contents);
+                if (r < 0)
+                        return r;
+
+                *begin = m->header->body_size;
+                *need_offsets = r == 0;
+        } else {
+                /* Align contents to 8 byte boundary */
+                if (!message_extend_body(m, 8, 0, false))
+                        return -ENOMEM;
+        }
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index = nindex;
+
+        return 0;
+}
+
+static int bus_message_open_dict_entry(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                size_t *begin,
+                bool *need_offsets) {
+
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(begin);
+        assert(need_offsets);
+
+        if (!signature_is_pair(contents))
+                return -EINVAL;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                return -ENXIO;
+
+        if (c->signature && c->signature[c->index]) {
+                size_t l;
+
+                l = strlen(contents);
+
+                if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
+                    !startswith(c->signature + c->index + 1, contents) ||
+                    c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
+                        return -ENXIO;
+        } else
+                return -ENXIO;
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                int alignment;
+
+                alignment = bus_gvariant_get_alignment(contents);
+                if (alignment < 0)
+                        return alignment;
+
+                if (!message_extend_body(m, alignment, 0, false))
+                        return -ENOMEM;
+
+                r = bus_gvariant_is_fixed_size(contents);
+                if (r < 0)
+                        return r;
+
+                *begin = m->header->body_size;
+                *need_offsets = r == 0;
+        } else {
+                /* Align contents to 8 byte boundary */
+                if (!message_extend_body(m, 8, 0, false))
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_message_open_container(
+                sd_bus_message *m,
+                char type,
+                const char *contents) {
+
+        struct bus_container *c, *w;
+        uint32_t *array_size = NULL;
+        char *signature;
+        size_t before, begin;
+        bool need_offsets = false;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(contents, -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        /* Make sure we have space for one more container */
+        if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
+                m->poisoned = true;
+                return -ENOMEM;
+        }
+
+        c = message_get_container(m);
+
+        signature = strdup(contents);
+        if (!signature) {
+                m->poisoned = true;
+                return -ENOMEM;
+        }
+
+        /* Save old index in the parent container, in case we have to
+         * abort this container */
+        c->saved_index = c->index;
+        before = m->header->body_size;
+
+        if (type == SD_BUS_TYPE_ARRAY)
+                r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
+        else if (type == SD_BUS_TYPE_VARIANT)
+                r = bus_message_open_variant(m, c, contents);
+        else if (type == SD_BUS_TYPE_STRUCT)
+                r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
+        else if (type == SD_BUS_TYPE_DICT_ENTRY)
+                r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
+        else
+                r = -EINVAL;
+
+        if (r < 0) {
+                free(signature);
+                return r;
+        }
+
+        /* OK, let's fill it in */
+        w = m->containers + m->n_containers++;
+        w->enclosing = type;
+        w->signature = signature;
+        w->index = 0;
+        w->array_size = array_size;
+        w->before = before;
+        w->begin = begin;
+        w->n_offsets = w->offsets_allocated = 0;
+        w->offsets = NULL;
+        w->need_offsets = need_offsets;
+
+        return 0;
+}
+
+static size_t determine_word_size(size_t sz, size_t extra) {
+        if (sz + extra <= 0xFF)
+                return 1;
+        else if (sz + extra*2 <= 0xFFFF)
+                return 2;
+        else if (sz + extra*4 <= 0xFFFFFFFF)
+                return 4;
+        else
+                return 8;
+}
+
+static size_t read_word_le(void *p, size_t sz) {
+        union {
+                uint16_t u16;
+                uint32_t u32;
+                uint64_t u64;
+        } x;
+
+        assert(p);
+
+        if (sz == 1)
+                return *(uint8_t*) p;
+
+        memcpy(&x, p, sz);
+
+        if (sz == 2)
+                return le16toh(x.u16);
+        else if (sz == 4)
+                return le32toh(x.u32);
+        else if (sz == 8)
+                return le64toh(x.u64);
+
+        assert_not_reached("unknown word width");
+}
+
+static void write_word_le(void *p, size_t sz, size_t value) {
+        union {
+                uint16_t u16;
+                uint32_t u32;
+                uint64_t u64;
+        } x;
+
+        assert(p);
+        assert(sz == 8 || (value < (1ULL << (sz*8))));
+
+        if (sz == 1) {
+                *(uint8_t*) p = value;
+                return;
+        } else if (sz == 2)
+                x.u16 = htole16((uint16_t) value);
+        else if (sz == 4)
+                x.u32 = htole32((uint32_t) value);
+        else if (sz == 8)
+                x.u64 = htole64((uint64_t) value);
+        else
+                assert_not_reached("unknown word width");
+
+        memcpy(p, &x, sz);
+}
+
+static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
+
+        assert(m);
+        assert(c);
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m))
+                return 0;
+
+        if (c->need_offsets) {
+                size_t payload, sz, i;
+                uint8_t *a;
+
+                /* Variable-width arrays */
+
+                payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
+                sz = determine_word_size(payload, c->n_offsets);
+
+                a = message_extend_body(m, 1, sz * c->n_offsets, true);
+                if (!a)
+                        return -ENOMEM;
+
+                for (i = 0; i < c->n_offsets; i++)
+                        write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
+        } else {
+                void *a;
+
+                /* Fixed-width or empty arrays */
+
+                a = message_extend_body(m, 1, 0, true); /* let's add offset to parent */
+                if (!a)
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
+static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
+        uint8_t *a;
+        size_t l;
+
+        assert(m);
+        assert(c);
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m))
+                return 0;
+
+        l = strlen(c->signature);
+
+        a = message_extend_body(m, 1, 1 + l, true);
+        if (!a)
+                return -ENOMEM;
+
+        a[0] = 0;
+        memcpy(a+1, c->signature, l);
+
+        return 0;
+}
+
+static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
+        size_t n_variable = 0;
+        unsigned i = 0;
+        const char *p;
+        uint8_t *a;
+        int r;
+
+        assert(m);
+        assert(c);
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m))
+                return 0;
+
+        p = strempty(c->signature);
+        while (*p != 0) {
+                size_t n;
+
+                r = signature_element_length(p, &n);
+                if (r < 0)
+                        return r;
+                else {
+                        char t[n+1];
+
+                        memcpy(t, p, n);
+                        t[n] = 0;
+
+                        r = bus_gvariant_is_fixed_size(t);
+                        if (r < 0)
+                                return r;
+                }
+
+                assert(!c->need_offsets || i <= c->n_offsets);
+
+                /* We need to add an offset for each item that has a
+                 * variable size and that is not the last one in the
+                 * list */
+                if (r == 0 && p[n] != 0)
+                        n_variable++;
+
+                i++;
+                p += n;
+        }
+
+        assert(!c->need_offsets || i == c->n_offsets);
+        assert(c->need_offsets || n_variable == 0);
+
+        if (n_variable <= 0) {
+                a = message_extend_body(m, 1, 0, add_offset);
+                if (!a)
+                        return -ENOMEM;
+        } else {
+                size_t sz;
+                unsigned j;
+
+                assert(c->offsets[c->n_offsets-1] == m->header->body_size);
+
+                sz = determine_word_size(m->header->body_size - c->begin, n_variable);
+
+                a = message_extend_body(m, 1, sz * n_variable, add_offset);
+                if (!a)
+                        return -ENOMEM;
+
+                p = strempty(c->signature);
+                for (i = 0, j = 0; i < c->n_offsets; i++) {
+                        unsigned k;
+                        size_t n;
+
+                        r = signature_element_length(p, &n);
+                        if (r < 0)
+                                return r;
+                        else {
+                                char t[n+1];
+
+                                memcpy(t, p, n);
+                                t[n] = 0;
+
+                                p += n;
+
+                                r = bus_gvariant_is_fixed_size(t);
+                                if (r < 0)
+                                        return r;
+                                if (r > 0 || p[0] == 0)
+                                        continue;
+                        }
+
+                        k = n_variable - 1 - j;
+
+                        write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
+
+                        j++;
+                }
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_message_close_container(sd_bus_message *m) {
+        struct bus_container *c;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers > 0, -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        c = message_get_container(m);
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                if (c->signature && c->signature[c->index] != 0)
+                        return -EINVAL;
+
+        m->n_containers--;
+
+        if (c->enclosing == SD_BUS_TYPE_ARRAY)
+                r = bus_message_close_array(m, c);
+        else if (c->enclosing == SD_BUS_TYPE_VARIANT)
+                r = bus_message_close_variant(m, c);
+        else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
+                r = bus_message_close_struct(m, c, true);
+        else
+                assert_not_reached("Unknown container type");
+
+        free(c->signature);
+        free(c->offsets);
+
+        return r;
+}
+
+typedef struct {
+        const char *types;
+        unsigned n_struct;
+        unsigned n_array;
+} TypeStack;
+
+static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
+        assert(stack);
+        assert(max > 0);
+
+        if (*i >= max)
+                return -EINVAL;
+
+        stack[*i].types = types;
+        stack[*i].n_struct = n_struct;
+        stack[*i].n_array = n_array;
+        (*i)++;
+
+        return 0;
+}
+
+static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
+        assert(stack);
+        assert(max > 0);
+        assert(types);
+        assert(n_struct);
+        assert(n_array);
+
+        if (*i <= 0)
+                return 0;
+
+        (*i)--;
+        *types = stack[*i].types;
+        *n_struct = stack[*i].n_struct;
+        *n_array = stack[*i].n_array;
+
+        return 1;
+}
+
+int bus_message_append_ap(
+                sd_bus_message *m,
+                const char *types,
+                va_list ap) {
+
+        unsigned n_array, n_struct;
+        TypeStack stack[BUS_CONTAINER_DEPTH];
+        unsigned stack_ptr = 0;
+        int r;
+
+        assert(m);
+
+        if (!types)
+                return 0;
+
+        n_array = (unsigned) -1;
+        n_struct = strlen(types);
+
+        for (;;) {
+                const char *t;
+
+                if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
+                        r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                break;
+
+                        r = sd_bus_message_close_container(m);
+                        if (r < 0)
+                                return r;
+
+                        continue;
+                }
+
+                t = types;
+                if (n_array != (unsigned) -1)
+                        n_array --;
+                else {
+                        types ++;
+                        n_struct--;
+                }
+
+                switch (*t) {
+
+                case SD_BUS_TYPE_BYTE: {
+                        uint8_t x;
+
+                        x = (uint8_t) va_arg(ap, int);
+                        r = sd_bus_message_append_basic(m, *t, &x);
+                        break;
+                }
+
+                case SD_BUS_TYPE_BOOLEAN:
+                case SD_BUS_TYPE_INT32:
+                case SD_BUS_TYPE_UINT32:
+                case SD_BUS_TYPE_UNIX_FD: {
+                        uint32_t x;
+
+                        /* We assume a boolean is the same as int32_t */
+                        assert_cc(sizeof(int32_t) == sizeof(int));
+
+                        x = va_arg(ap, uint32_t);
+                        r = sd_bus_message_append_basic(m, *t, &x);
+                        break;
+                }
+
+                case SD_BUS_TYPE_INT16:
+                case SD_BUS_TYPE_UINT16: {
+                        uint16_t x;
+
+                        x = (uint16_t) va_arg(ap, int);
+                        r = sd_bus_message_append_basic(m, *t, &x);
+                        break;
+                }
+
+                case SD_BUS_TYPE_INT64:
+                case SD_BUS_TYPE_UINT64:
+                case SD_BUS_TYPE_DOUBLE: {
+                        uint64_t x;
+
+                        x = va_arg(ap, uint64_t);
+                        r = sd_bus_message_append_basic(m, *t, &x);
+                        break;
+                }
+
+                case SD_BUS_TYPE_STRING:
+                case SD_BUS_TYPE_OBJECT_PATH:
+                case SD_BUS_TYPE_SIGNATURE: {
+                        const char *x;
+
+                        x = va_arg(ap, const char*);
+                        r = sd_bus_message_append_basic(m, *t, x);
+                        break;
+                }
+
+                case SD_BUS_TYPE_ARRAY: {
+                        size_t k;
+
+                        r = signature_element_length(t + 1, &k);
+                        if (r < 0)
+                                return r;
+
+                        {
+                                char s[k + 1];
+                                memcpy(s, t + 1, k);
+                                s[k] = 0;
+
+                                r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        if (n_array == (unsigned) -1) {
+                                types += k;
+                                n_struct -= k;
+                        }
+
+                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+                        if (r < 0)
+                                return r;
+
+                        types = t + 1;
+                        n_struct = k;
+                        n_array = va_arg(ap, unsigned);
+
+                        break;
+                }
+
+                case SD_BUS_TYPE_VARIANT: {
+                        const char *s;
+
+                        s = va_arg(ap, const char*);
+                        if (!s)
+                                return -EINVAL;
+
+                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
+                        if (r < 0)
+                                return r;
+
+                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+                        if (r < 0)
+                                return r;
+
+                        types = s;
+                        n_struct = strlen(s);
+                        n_array = (unsigned) -1;
+
+                        break;
+                }
+
+                case SD_BUS_TYPE_STRUCT_BEGIN:
+                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                        size_t k;
+
+                        r = signature_element_length(t, &k);
+                        if (r < 0)
+                                return r;
+
+                        {
+                                char s[k - 1];
+
+                                memcpy(s, t + 1, k - 2);
+                                s[k - 2] = 0;
+
+                                r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        if (n_array == (unsigned) -1) {
+                                types += k - 1;
+                                n_struct -= k - 1;
+                        }
+
+                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+                        if (r < 0)
+                                return r;
+
+                        types = t + 1;
+                        n_struct = k - 2;
+                        n_array = (unsigned) -1;
+
+                        break;
+                }
+
+                default:
+                        r = -EINVAL;
+                }
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 1;
+}
+
+_public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
+        va_list ap;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(types, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->poisoned, -ESTALE);
+
+        va_start(ap, types);
+        r = bus_message_append_ap(m, types, ap);
+        va_end(ap);
+
+        return r;
+}
+
+_public_ int sd_bus_message_append_array_space(
+                sd_bus_message *m,
+                char type,
+                size_t size,
+                void **ptr) {
+
+        ssize_t align, sz;
+        void *a;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
+        assert_return(ptr || size == 0, -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        /* alignment and size of the trivial types (except bool) is
+         * identical for gvariant and dbus1 marshalling */
+        align = bus_type_get_alignment(type);
+        sz = bus_type_get_size(type);
+
+        assert_se(align > 0);
+        assert_se(sz > 0);
+
+        if (size % sz != 0)
+                return -EINVAL;
+
+        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
+        if (r < 0)
+                return r;
+
+        a = message_extend_body(m, align, size, false);
+        if (!a)
+                return -ENOMEM;
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        *ptr = a;
+        return 0;
+}
+
+_public_ int sd_bus_message_append_array(sd_bus_message *m,
+                                         char type,
+                                         const void *ptr,
+                                         size_t size) {
+        int r;
+        void *p;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(bus_type_is_trivial(type), -EINVAL);
+        assert_return(ptr || size == 0, -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        r = sd_bus_message_append_array_space(m, type, size, &p);
+        if (r < 0)
+                return r;
+
+        if (size > 0)
+                memcpy(p, ptr, size);
+
+        return 0;
+}
+
+_public_ int sd_bus_message_append_array_iovec(
+                sd_bus_message *m,
+                char type,
+                const struct iovec *iov,
+                unsigned n) {
+
+        size_t size;
+        unsigned i;
+        void *p;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(bus_type_is_trivial(type), -EINVAL);
+        assert_return(iov || n == 0, -EINVAL);
+        assert_return(!m->poisoned, -ESTALE);
+
+        size = IOVEC_TOTAL_SIZE(iov, n);
+
+        r = sd_bus_message_append_array_space(m, type, size, &p);
+        if (r < 0)
+                return r;
+
+        for (i = 0; i < n; i++) {
+
+                if (iov[i].iov_base)
+                        memcpy(p, iov[i].iov_base, iov[i].iov_len);
+                else
+                        memset(p, 0, iov[i].iov_len);
+
+                p = (uint8_t*) p + iov[i].iov_len;
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
+                                               char type,
+                                               sd_memfd *memfd) {
+        _cleanup_close_ int copy_fd = -1;
+        struct bus_body_part *part;
+        ssize_t align, sz;
+        uint64_t size;
+        void *a;
+        int r;
+
+        if (!m)
+                return -EINVAL;
+        if (!memfd)
+                return -EINVAL;
+        if (m->sealed)
+                return -EPERM;
+        if (!bus_type_is_trivial(type))
+                return -EINVAL;
+        if (m->poisoned)
+                return -ESTALE;
+
+        r = sd_memfd_set_sealed(memfd, true);
+        if (r < 0)
+                return r;
+
+        copy_fd = sd_memfd_dup_fd(memfd);
+        if (copy_fd < 0)
+                return copy_fd;
+
+        r = sd_memfd_get_size(memfd, &size);
+        if (r < 0)
+                return r;
+
+        align = bus_type_get_alignment(type);
+        sz = bus_type_get_size(type);
+
+        assert_se(align > 0);
+        assert_se(sz > 0);
+
+        if (size % sz != 0)
+                return -EINVAL;
+
+        if (size > (uint64_t) (uint32_t) -1)
+                return -EINVAL;
+
+        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
+        if (r < 0)
+                return r;
+
+        a = message_extend_body(m, align, 0, false);
+        if (!a)
+                return -ENOMEM;
+
+        part = message_append_part(m);
+        if (!part)
+                return -ENOMEM;
+
+        part->memfd = copy_fd;
+        part->sealed = true;
+        part->size = size;
+        copy_fd = -1;
+
+        m->header->body_size += size;
+        message_extend_containers(m, size);
+
+        return sd_bus_message_close_container(m);
+}
+
+_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
+        _cleanup_close_ int copy_fd = -1;
+        struct bus_body_part *part;
+        struct bus_container *c;
+        uint64_t size;
+        void *a;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(memfd, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->poisoned, -ESTALE);
+
+        r = sd_memfd_set_sealed(memfd, true);
+        if (r < 0)
+                return r;
+
+        copy_fd = sd_memfd_dup_fd(memfd);
+        if (copy_fd < 0)
+                return copy_fd;
+
+        r = sd_memfd_get_size(memfd, &size);
+        if (r < 0)
+                return r;
+
+        /* We require this to be NUL terminated */
+        if (size == 0)
+                return -EINVAL;
+
+        if (size > (uint64_t) (uint32_t) -1)
+                return -EINVAL;
+
+        c = message_get_container(m);
+        if (c->signature && c->signature[c->index]) {
+                /* Container signature is already set */
+
+                if (c->signature[c->index] != SD_BUS_TYPE_STRING)
+                        return -ENXIO;
+        } else {
+                char *e;
+
+                /* Maybe we can append to the signature? But only if this is the top-level container*/
+                if (c->enclosing != 0)
+                        return -ENXIO;
+
+                e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
+                if (!e) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+        }
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m)) {
+                a = message_extend_body(m, 4, 4, false);
+                if (!a)
+                        return -ENOMEM;
+
+                *(uint32_t*) a = size - 1;
+        }
+
+        part = message_append_part(m);
+        if (!part)
+                return -ENOMEM;
+
+        part->memfd = copy_fd;
+        part->sealed = true;
+        part->size = size;
+        copy_fd = -1;
+
+        m->header->body_size += size;
+        message_extend_containers(m, size);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                r = message_add_offset(m, m->header->body_size);
+                if (r < 0) {
+                        m->poisoned = true;
+                        return -ENOMEM;
+                }
+        }
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index++;
+
+        return 0;
+}
+
+_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
+        char **i;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->poisoned, -ESTALE);
+
+        r = sd_bus_message_open_container(m, 'a', "s");
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, l) {
+                r = sd_bus_message_append_basic(m, 's', *i);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(m);
+}
+
+static int bus_message_close_header(sd_bus_message *m) {
+        uint8_t *a;
+        size_t sz, i;
+
+        assert(m);
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m))
+                return 0;
+
+        if (m->n_header_offsets < 1)
+                return 0;
+
+        assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
+
+        sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
+
+        a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
+        if (!a)
+                return -ENOMEM;
+
+        for (i = 0; i < m->n_header_offsets; i++)
+                write_word_le(a + sz*i, sz, m->header_offsets[i]);
+
+        return 0;
+}
+
+int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
+        struct bus_body_part *part;
+        size_t l, a;
+        unsigned i;
+        int r;
+
+        assert(m);
+
+        if (m->sealed)
+                return -EPERM;
+
+        if (m->n_containers > 0)
+                return -EBADMSG;
+
+        if (m->poisoned)
+                return -ESTALE;
+
+        /* In vtables the return signature of method calls is listed,
+         * let's check if they match if this is a response */
+        if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
+            m->enforced_reply_signature &&
+            !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
+                return -ENOMSG;
+
+        /* If gvariant marshalling is used we need to close the body structure */
+        r = bus_message_close_struct(m, &m->root_container, false);
+        if (r < 0)
+                return r;
+
+        /* If there's a non-trivial signature set, then add it in here */
+        if (!isempty(m->root_container.signature)) {
+                r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        if (m->n_fds > 0) {
+                r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
+                if (r < 0)
+                        return r;
+        }
+
+        r = bus_message_close_header(m);
+        if (r < 0)
+                return r;
+
+        m->header->serial = (uint32_t) cookie;
+        m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
+
+        /* Add padding at the end of the fields part, since we know
+         * the body needs to start at an 8 byte alignment. We made
+         * sure we allocated enough space for this, so all we need to
+         * do here is to zero it out. */
+        l = BUS_MESSAGE_FIELDS_SIZE(m);
+        a = ALIGN8(l) - l;
+        if (a > 0)
+                memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
+
+        /* If this is something we can send as memfd, then let's seal
+        the memfd now. Note that we can send memfds as payload only
+        for directed messages, and not for broadcasts. */
+        if (m->destination && m->bus && m->bus->use_memfd) {
+                MESSAGE_FOREACH_PART(part, i, m)
+                        if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
+                                uint64_t sz;
+
+                                /* Try to seal it if that makes
+                                 * sense. First, unmap our own map to
+                                 * make sure we don't keep it busy. */
+                                bus_body_part_unmap(part);
+
+                                /* Then, sync up real memfd size */
+                                sz = part->size;
+                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0)
+                                        return -errno;
+
+                                /* Finally, try to seal */
+                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
+                                        part->sealed = true;
+                        }
+        }
+
+        m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
+        m->root_container.index = 0;
+        m->root_container.offset_index = 0;
+        m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
+
+        m->sealed = true;
+
+        return 0;
+}
+
+int bus_body_part_map(struct bus_body_part *part) {
+        void *p;
+        size_t psz;
+
+        assert_se(part);
+
+        if (part->data)
+                return 0;
+
+        if (part->size <= 0)
+                return 0;
+
+        /* For smaller zero parts (as used for padding) we don't need to map anything... */
+        if (part->memfd < 0 && part->is_zero && part->size < 8) {
+                static const uint8_t zeroes[7] = { };
+                part->data = (void*) zeroes;
+                return 0;
+        }
+
+        psz = PAGE_ALIGN(part->size);
+
+        if (part->memfd >= 0)
+                p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
+        else if (part->is_zero)
+                p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+        else
+                return -EINVAL;
+
+        if (p == MAP_FAILED)
+                return -errno;
+
+        part->mapped = psz;
+        part->data = p;
+        part->munmap_this = true;
+
+        return 0;
+}
+
+void bus_body_part_unmap(struct bus_body_part *part) {
+
+        assert_se(part);
+
+        if (part->memfd < 0)
+                return;
+
+        if (!part->data)
+                return;
+
+        if (!part->munmap_this)
+                return;
+
+        assert_se(munmap(part->data, part->mapped) == 0);
+
+        part->data = NULL;
+        part->mapped = 0;
+        part->munmap_this = false;
+
+        return;
+}
+
+static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
+        size_t k, start, end;
+
+        assert(rindex);
+        assert(align > 0);
+
+        start = ALIGN_TO((size_t) *rindex, align);
+        end = start + nbytes;
+
+        if (end > sz)
+                return -EBADMSG;
+
+        /* Verify that padding is 0 */
+        for (k = *rindex; k < start; k++)
+                if (((const uint8_t*) p)[k] != 0)
+                        return -EBADMSG;
+
+        if (r)
+                *r = (uint8_t*) p + start;
+
+        *rindex = end;
+
+        return 1;
+}
+
+static bool message_end_of_signature(sd_bus_message *m) {
+        struct bus_container *c;
+
+        assert(m);
+
+        c = message_get_container(m);
+        return !c->signature || c->signature[c->index] == 0;
+}
+
+static bool message_end_of_array(sd_bus_message *m, size_t index) {
+        struct bus_container *c;
+
+        assert(m);
+
+        c = message_get_container(m);
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                return false;
+
+        if (BUS_MESSAGE_IS_GVARIANT(m))
+                return index >= c->end;
+        else {
+                assert(c->array_size);
+                return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
+        }
+}
+
+_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+
+        if (complete && m->n_containers > 0)
+                return false;
+
+        if (message_end_of_signature(m))
+                return true;
+
+        if (message_end_of_array(m, m->rindex))
+                return true;
+
+        return false;
+}
+
+static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
+        struct bus_body_part *part;
+        size_t begin;
+        int r;
+
+        assert(m);
+
+        if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
+                part = m->cached_rindex_part;
+                begin = m->cached_rindex_part_begin;
+        } else {
+                part = &m->body;
+                begin = 0;
+        }
+
+        while (part) {
+                if (index < begin)
+                        return NULL;
+
+                if (index + sz <= begin + part->size) {
+
+                        r = bus_body_part_map(part);
+                        if (r < 0)
+                                return NULL;
+
+                        if (p)
+                                *p = (uint8_t*) part->data + index - begin;
+
+                        m->cached_rindex_part = part;
+                        m->cached_rindex_part_begin = begin;
+
+                        return part;
+                }
+
+                begin += part->size;
+                part = part->next;
+        }
+
+        return NULL;
+}
+
+static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(rindex);
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m))
+                return 0;
+
+        if (c->enclosing == SD_BUS_TYPE_ARRAY) {
+                int sz;
+
+                sz = bus_gvariant_get_size(c->signature);
+                if (sz < 0) {
+                        int alignment;
+
+                        if (c->offset_index+1 >= c->n_offsets)
+                                goto end;
+
+                        /* Variable-size array */
+
+                        alignment = bus_gvariant_get_alignment(c->signature);
+                        assert(alignment > 0);
+
+                        *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
+                        c->item_size = c->offsets[c->offset_index+1] - *rindex;
+                } else {
+
+                        if (c->offset_index+1 >= (c->end-c->begin)/sz)
+                                goto end;
+
+                        /* Fixed-size array */
+                        *rindex = c->begin + (c->offset_index+1) * sz;
+                        c->item_size = sz;
+                }
+
+                c->offset_index++;
+
+        } else if (c->enclosing == 0 ||
+                   c->enclosing == SD_BUS_TYPE_STRUCT ||
+                   c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
+
+                int alignment;
+                size_t n, j;
+
+                if (c->offset_index+1 >= c->n_offsets)
+                        goto end;
+
+                r = signature_element_length(c->signature + c->index, &n);
+                if (r < 0)
+                        return r;
+
+                r = signature_element_length(c->signature + c->index + n, &j);
+                if (r < 0)
+                        return r;
+                else {
+                        char t[j+1];
+                        memcpy(t, c->signature + c->index + n, j);
+                        t[j] = 0;
+
+                        alignment = bus_gvariant_get_alignment(t);
+                }
+
+                assert(alignment > 0);
+
+                *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
+                c->item_size = c->offsets[c->offset_index+1] - *rindex;
+
+                c->offset_index++;
+
+        } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
+                goto end;
+        else
+                assert_not_reached("Unknown container type");
+
+        return 0;
+
+end:
+        /* Reached the end */
+        *rindex = c->end;
+        c->item_size = 0;
+        return 0;
+}
+
+
+static int message_peek_body(
+                sd_bus_message *m,
+                size_t *rindex,
+                size_t align,
+                size_t nbytes,
+                void **ret) {
+
+        size_t k, start, end, padding;
+        struct bus_body_part *part;
+        uint8_t *q;
+
+        assert(m);
+        assert(rindex);
+        assert(align > 0);
+
+        start = ALIGN_TO((size_t) *rindex, align);
+        padding = start - *rindex;
+        end = start + nbytes;
+
+        if (end > BUS_MESSAGE_BODY_SIZE(m))
+                return -EBADMSG;
+
+        part = find_part(m, *rindex, padding, (void**) &q);
+        if (!part)
+                return -EBADMSG;
+
+        if (q) {
+                /* Verify padding */
+                for (k = 0; k < padding; k++)
+                        if (q[k] != 0)
+                                return -EBADMSG;
+        }
+
+        part = find_part(m, start, nbytes, (void**) &q);
+        if (!part || (nbytes > 0 && !q))
+                return -EBADMSG;
+
+        *rindex = end;
+
+        if (ret)
+                *ret = q;
+
+        return 0;
+}
+
+static bool validate_nul(const char *s, size_t l) {
+
+        /* Check for NUL chars in the string */
+        if (memchr(s, 0, l))
+                return false;
+
+        /* Check for NUL termination */
+        if (s[l] != 0)
+                return false;
+
+        return true;
+}
+
+static bool validate_string(const char *s, size_t l) {
+
+        if (!validate_nul(s, l))
+                return false;
+
+        /* Check if valid UTF8 */
+        if (!utf8_is_valid(s))
+                return false;
+
+        return true;
+}
+
+static bool validate_signature(const char *s, size_t l) {
+
+        if (!validate_nul(s, l))
+                return false;
+
+        /* Check if valid signature */
+        if (!signature_is_valid(s, true))
+                return false;
+
+        return true;
+}
+
+static bool validate_object_path(const char *s, size_t l) {
+
+        if (!validate_nul(s, l))
+                return false;
+
+        if (!object_path_is_valid(s))
+                return false;
+
+        return true;
+}
+
+_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
+        struct bus_container *c;
+        size_t rindex;
+        void *q;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(bus_type_is_basic(type), -EINVAL);
+
+        if (message_end_of_signature(m))
+                return -ENXIO;
+
+        if (message_end_of_array(m, m->rindex))
+                return 0;
+
+        c = message_get_container(m);
+        if (c->signature[c->index] != type)
+                return -ENXIO;
+
+        rindex = m->rindex;
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+
+                if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
+                        bool ok;
+
+                        r = message_peek_body(m, &rindex, 1, c->item_size, &q);
+                        if (r < 0)
+                                return r;
+
+                        if (type == SD_BUS_TYPE_STRING)
+                                ok = validate_string(q, c->item_size-1);
+                        else if (type == SD_BUS_TYPE_OBJECT_PATH)
+                                ok = validate_object_path(q, c->item_size-1);
+                        else
+                                ok = validate_signature(q, c->item_size-1);
+
+                        if (!ok)
+                                return -EBADMSG;
+
+                        if (p)
+                                *(const char**) p = q;
+                } else {
+                        int sz, align;
+
+                        sz = bus_gvariant_get_size(CHAR_TO_STR(type));
+                        assert(sz > 0);
+                        if ((size_t) sz != c->item_size)
+                                return -EBADMSG;
+
+                        align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
+                        assert(align > 0);
+
+                        r = message_peek_body(m, &rindex, align, c->item_size, &q);
+                        if (r < 0)
+                                return r;
+
+                        switch (type) {
+
+                        case SD_BUS_TYPE_BYTE:
+                                if (p)
+                                        *(uint8_t*) p = *(uint8_t*) q;
+                                break;
+
+                        case SD_BUS_TYPE_BOOLEAN:
+                                if (p)
+                                        *(int*) p = !!*(uint8_t*) q;
+                                break;
+
+                        case SD_BUS_TYPE_INT16:
+                        case SD_BUS_TYPE_UINT16:
+                                if (p)
+                                        *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
+                                break;
+
+                        case SD_BUS_TYPE_INT32:
+                        case SD_BUS_TYPE_UINT32:
+                                if (p)
+                                        *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                                break;
+
+                        case SD_BUS_TYPE_INT64:
+                        case SD_BUS_TYPE_UINT64:
+                        case SD_BUS_TYPE_DOUBLE:
+                                if (p)
+                                        *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
+                                break;
+
+                        case SD_BUS_TYPE_UNIX_FD: {
+                                uint32_t j;
+
+                                j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                                if (j >= m->n_fds)
+                                        return -EBADMSG;
+
+                                if (p)
+                                        *(int*) p = m->fds[j];
+
+                                break;
+                        }
+
+                        default:
+                                assert_not_reached("unexpected type");
+                        }
+                }
+
+                r = container_next_item(m, c, &rindex);
+                if (r < 0)
+                        return r;
+        } else {
+
+                rindex = m->rindex;
+
+                if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
+                        uint32_t l;
+                        bool ok;
+
+                        r = message_peek_body(m, &rindex, 4, 4, &q);
+                        if (r < 0)
+                                return r;
+
+                        l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                        r = message_peek_body(m, &rindex, 1, l+1, &q);
+                        if (r < 0)
+                                return r;
+
+                        if (type == SD_BUS_TYPE_OBJECT_PATH)
+                                ok = validate_object_path(q, l);
+                        else
+                                ok = validate_string(q, l);
+                        if (!ok)
+                                return -EBADMSG;
+
+                        if (p)
+                                *(const char**) p = q;
+
+                } else if (type == SD_BUS_TYPE_SIGNATURE) {
+                        uint8_t l;
+
+                        r = message_peek_body(m, &rindex, 1, 1, &q);
+                        if (r < 0)
+                                return r;
+
+                        l = *(uint8_t*) q;
+                        r = message_peek_body(m, &rindex, 1, l+1, &q);
+                        if (r < 0)
+                                return r;
+
+                        if (!validate_signature(q, l))
+                                return -EBADMSG;
+
+                        if (p)
+                                *(const char**) p = q;
+
+                } else {
+                        ssize_t sz, align;
+
+                        align = bus_type_get_alignment(type);
+                        assert(align > 0);
+
+                        sz = bus_type_get_size(type);
+                        assert(sz > 0);
+
+                        r = message_peek_body(m, &rindex, align, sz, &q);
+                        if (r < 0)
+                                return r;
+
+                        switch (type) {
+
+                        case SD_BUS_TYPE_BYTE:
+                                if (p)
+                                        *(uint8_t*) p = *(uint8_t*) q;
+                                break;
+
+                        case SD_BUS_TYPE_BOOLEAN:
+                                if (p)
+                                        *(int*) p = !!*(uint32_t*) q;
+                                break;
+
+                        case SD_BUS_TYPE_INT16:
+                        case SD_BUS_TYPE_UINT16:
+                                if (p)
+                                        *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
+                                break;
+
+                        case SD_BUS_TYPE_INT32:
+                        case SD_BUS_TYPE_UINT32:
+                                if (p)
+                                        *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                                break;
+
+                        case SD_BUS_TYPE_INT64:
+                        case SD_BUS_TYPE_UINT64:
+                        case SD_BUS_TYPE_DOUBLE:
+                                if (p)
+                                        *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
+                                break;
+
+                        case SD_BUS_TYPE_UNIX_FD: {
+                                uint32_t j;
+
+                                j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                                if (j >= m->n_fds)
+                                        return -EBADMSG;
+
+                                if (p)
+                                        *(int*) p = m->fds[j];
+                                break;
+                        }
+
+                        default:
+                                assert_not_reached("Unknown basic type...");
+                        }
+                }
+        }
+
+        m->rindex = rindex;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index++;
+
+        return 1;
+}
+
+static int bus_message_enter_array(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                uint32_t **array_size,
+                size_t *item_size,
+                size_t **offsets,
+                size_t *n_offsets) {
+
+        size_t rindex;
+        void *q;
+        int r, alignment;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(array_size);
+        assert(item_size);
+        assert(offsets);
+        assert(n_offsets);
+
+        if (!signature_is_single(contents, true))
+                return -EINVAL;
+
+        if (!c->signature || c->signature[c->index] == 0)
+                return -ENXIO;
+
+        if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
+                return -ENXIO;
+
+        if (!startswith(c->signature + c->index + 1, contents))
+                return -ENXIO;
+
+        rindex = m->rindex;
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m)) {
+                /* dbus1 */
+
+                r = message_peek_body(m, &rindex, 4, 4, &q);
+                if (r < 0)
+                        return r;
+
+                if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
+                        return -EBADMSG;
+
+                alignment = bus_type_get_alignment(contents[0]);
+                if (alignment < 0)
+                        return alignment;
+
+                r = message_peek_body(m, &rindex, alignment, 0, NULL);
+                if (r < 0)
+                        return r;
+
+                *array_size = (uint32_t*) q;
+
+        } else if (c->item_size <= 0) {
+
+                /* gvariant: empty array */
+                *item_size = 0;
+                *offsets = NULL;
+                *n_offsets = 0;
+
+        } else if (bus_gvariant_is_fixed_size(contents)) {
+
+                /* gvariant: fixed length array */
+                *item_size = bus_gvariant_get_size(contents);
+                *offsets = NULL;
+                *n_offsets = 0;
+
+        } else {
+                size_t where, p = 0, framing, sz;
+                unsigned i;
+
+                /* gvariant: variable length array */
+                sz = determine_word_size(c->item_size, 0);
+
+                where = rindex + c->item_size - sz;
+                r = message_peek_body(m, &where, 1, sz, &q);
+                if (r < 0)
+                        return r;
+
+                framing = read_word_le(q, sz);
+                if (framing > c->item_size - sz)
+                        return -EBADMSG;
+                if ((c->item_size - framing) % sz != 0)
+                        return -EBADMSG;
+
+                *n_offsets = (c->item_size - framing) / sz;
+
+                where = rindex + framing;
+                r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
+                if (r < 0)
+                        return r;
+
+                *offsets = new(size_t, *n_offsets);
+                if (!*offsets)
+                        return -ENOMEM;
+
+                for (i = 0; i < *n_offsets; i++) {
+                        size_t x;
+
+                        x = read_word_le((uint8_t*) q + i * sz, sz);
+                        if (x > c->item_size - sz)
+                                return -EBADMSG;
+                        if (x < p)
+                                return -EBADMSG;
+
+                        (*offsets)[i] = rindex + x;
+                        p = x;
+                }
+
+                *item_size = (*offsets)[0] - rindex;
+        }
+
+        m->rindex = rindex;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index += 1 + strlen(contents);
+
+        return 1;
+}
+
+static int bus_message_enter_variant(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                size_t *item_size) {
+
+        size_t rindex;
+        uint8_t l;
+        void *q;
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(item_size);
+
+        if (!signature_is_single(contents, false))
+                return -EINVAL;
+
+        if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
+                return -EINVAL;
+
+        if (!c->signature || c->signature[c->index] == 0)
+                return -ENXIO;
+
+        if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
+                return -ENXIO;
+
+        rindex = m->rindex;
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                size_t k, where;
+
+                k = strlen(contents);
+                if (1+k > c->item_size)
+                        return -EBADMSG;
+
+                where = rindex + c->item_size - (1+k);
+                r = message_peek_body(m, &where, 1, 1+k, &q);
+                if (r < 0)
+                        return r;
+
+                if (*(char*) q != 0)
+                        return -EBADMSG;
+
+                if (memcmp((uint8_t*) q+1, contents, k))
+                        return -ENXIO;
+
+                *item_size = c->item_size - (1+k);
+
+        } else {
+                r = message_peek_body(m, &rindex, 1, 1, &q);
+                if (r < 0)
+                        return r;
+
+                l = *(uint8_t*) q;
+                r = message_peek_body(m, &rindex, 1, l+1, &q);
+                if (r < 0)
+                        return r;
+
+                if (!validate_signature(q, l))
+                        return -EBADMSG;
+
+                if (!streq(q, contents))
+                        return -ENXIO;
+        }
+
+        m->rindex = rindex;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index++;
+
+        return 1;
+}
+
+static int build_struct_offsets(
+                sd_bus_message *m,
+                const char *signature,
+                size_t size,
+                size_t *item_size,
+                size_t **offsets,
+                size_t *n_offsets) {
+
+        unsigned n_variable = 0, n_total = 0, v;
+        size_t previous = 0, where;
+        const char *p;
+        size_t sz;
+        void *q;
+        int r;
+
+        assert(m);
+        assert(item_size);
+        assert(offsets);
+        assert(n_offsets);
+
+        if (isempty(signature)) {
+                *item_size = 0;
+                *offsets = NULL;
+                *n_offsets = 0;
+                return 0;
+        }
+
+        sz = determine_word_size(size, 0);
+        if (sz <= 0)
+                return -EBADMSG;
+
+        /* First, loop over signature and count variable elements and
+         * elements in general. We use this to know how large the
+         * offset array is at the end of the structure. Note that
+         * GVariant only stores offsets for all variable size elements
+         * that are not the last item. */
+
+        p = signature;
+        while (*p != 0) {
+                size_t n;
+
+                r = signature_element_length(p, &n);
+                if (r < 0)
+                        return r;
+                else {
+                        char t[n+1];
+
+                        memcpy(t, p, n);
+                        t[n] = 0;
+
+                        r = bus_gvariant_is_fixed_size(t);
+                }
+
+                if (r < 0)
+                        return r;
+                if (r == 0 && p[n] != 0) /* except the last item */
+                        n_variable ++;
+                n_total++;
+
+                p += n;
+        }
+
+        if (size < n_variable * sz)
+                return -EBADMSG;
+
+        where = m->rindex + size - (n_variable * sz);
+        r = message_peek_body(m, &where, 1, n_variable * sz, &q);
+        if (r < 0)
+                return r;
+
+        v = n_variable;
+
+        *offsets = new(size_t, n_total);
+        if (!*offsets)
+                return -ENOMEM;
+
+        *n_offsets = 0;
+
+        /* Second, loop again and build an offset table */
+        p = signature;
+        while (*p != 0) {
+                size_t n, offset;
+                int k;
+
+                r = signature_element_length(p, &n);
+                if (r < 0)
+                        return r;
+                else {
+                        char t[n+1];
+
+                        memcpy(t, p, n);
+                        t[n] = 0;
+
+                        k = bus_gvariant_get_size(t);
+                        if (k < 0) {
+                                size_t x;
+
+                                /* variable size */
+                                if (v > 0) {
+                                        v--;
+
+                                        x = read_word_le((uint8_t*) q + v*sz, sz);
+                                        if (x >= size)
+                                                return -EBADMSG;
+                                        if (m->rindex + x < previous)
+                                                return -EBADMSG;
+                                } else
+                                        /* The last item's end
+                                         * is determined from
+                                         * the start of the
+                                         * offset array */
+                                        x = size - (n_variable * sz);
+
+                                offset = m->rindex + x;
+
+                        } else {
+                                size_t align;
+
+                                /* fixed size */
+                                align = bus_gvariant_get_alignment(t);
+                                assert(align > 0);
+
+                                offset = (*n_offsets == 0 ? m->rindex  : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
+                        }
+                }
+
+                previous = (*offsets)[(*n_offsets)++] = offset;
+                p += n;
+        }
+
+        assert(v == 0);
+        assert(*n_offsets == n_total);
+
+        *item_size = (*offsets)[0] - m->rindex;
+        return 0;
+}
+
+static int enter_struct_or_dict_entry(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                size_t *item_size,
+                size_t **offsets,
+                size_t *n_offsets) {
+
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(item_size);
+        assert(offsets);
+        assert(n_offsets);
+
+        if (!BUS_MESSAGE_IS_GVARIANT(m)) {
+
+                /* dbus1 */
+                r = message_peek_body(m, &m->rindex, 8, 0, NULL);
+                if (r < 0)
+                        return r;
+
+        } else if (c->item_size <= 0) {
+
+                /* gvariant empty struct */
+                *item_size = 0;
+                *offsets = NULL;
+                *n_offsets = 0;
+        } else
+                /* gvariant with contents */
+                return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
+
+        return 0;
+}
+
+static int bus_message_enter_struct(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                size_t *item_size,
+                size_t **offsets,
+                size_t *n_offsets) {
+
+        size_t l;
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+        assert(item_size);
+        assert(offsets);
+        assert(n_offsets);
+
+        if (!signature_is_valid(contents, false))
+                return -EINVAL;
+
+        if (!c->signature || c->signature[c->index] == 0)
+                return -ENXIO;
+
+        l = strlen(contents);
+
+        if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
+            !startswith(c->signature + c->index + 1, contents) ||
+            c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
+                return -ENXIO;
+
+        r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
+        if (r < 0)
+                return r;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index += 1 + l + 1;
+
+        return 1;
+}
+
+static int bus_message_enter_dict_entry(
+                sd_bus_message *m,
+                struct bus_container *c,
+                const char *contents,
+                size_t *item_size,
+                size_t **offsets,
+                size_t *n_offsets) {
+
+        size_t l;
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(contents);
+
+        if (!signature_is_pair(contents))
+                return -EINVAL;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                return -ENXIO;
+
+        if (!c->signature || c->signature[c->index] == 0)
+                return 0;
+
+        l = strlen(contents);
+
+        if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
+            !startswith(c->signature + c->index + 1, contents) ||
+            c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
+                return -ENXIO;
+
+        r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
+        if (r < 0)
+                return r;
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY)
+                c->index += 1 + l + 1;
+
+        return 1;
+}
+
+_public_ int sd_bus_message_enter_container(sd_bus_message *m,
+                                            char type,
+                                            const char *contents) {
+        struct bus_container *c, *w;
+        uint32_t *array_size = NULL;
+        char *signature;
+        size_t before;
+        size_t *offsets = NULL;
+        size_t n_offsets = 0, item_size = 0;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(type != 0 || !contents, -EINVAL);
+
+        if (type == 0 || !contents) {
+                const char *cc;
+                char tt;
+
+                /* Allow entering into anonymous containers */
+                r = sd_bus_message_peek_type(m, &tt, &cc);
+                if (r < 0)
+                        return r;
+
+                if (type != 0 && type != tt)
+                        return -ENXIO;
+
+                if (contents && !streq(contents, cc))
+                        return -ENXIO;
+
+                type = tt;
+                contents = cc;
+        }
+
+        /*
+         * We enforce a global limit on container depth, that is much
+         * higher than the 32 structs and 32 arrays the specification
+         * mandates. This is simpler to implement for us, and we need
+         * this only to ensure our container array doesn't grow
+         * without bounds. We are happy to return any data from a
+         * message as long as the data itself is valid, even if the
+         * overall message might be not.
+         *
+         * Note that the message signature is validated when
+         * parsing the headers, and that validation does check the
+         * 32/32 limit.
+         *
+         * Note that the specification defines no limits on the depth
+         * of stacked variants, but we do.
+         */
+        if (m->n_containers >= BUS_CONTAINER_DEPTH)
+                return -EBADMSG;
+
+        if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
+                return -ENOMEM;
+
+        if (message_end_of_signature(m))
+                return -ENXIO;
+
+        if (message_end_of_array(m, m->rindex))
+                return 0;
+
+        c = message_get_container(m);
+
+        signature = strdup(contents);
+        if (!signature)
+                return -ENOMEM;
+
+        c->saved_index = c->index;
+        before = m->rindex;
+
+        if (type == SD_BUS_TYPE_ARRAY)
+                r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
+        else if (type == SD_BUS_TYPE_VARIANT)
+                r = bus_message_enter_variant(m, c, contents, &item_size);
+        else if (type == SD_BUS_TYPE_STRUCT)
+                r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
+        else if (type == SD_BUS_TYPE_DICT_ENTRY)
+                r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
+        else
+                r = -EINVAL;
+
+        if (r <= 0) {
+                free(signature);
+                free(offsets);
+                return r;
+        }
+
+        /* OK, let's fill it in */
+        w = m->containers + m->n_containers++;
+        w->enclosing = type;
+        w->signature = signature;
+        w->peeked_signature = NULL;
+        w->index = 0;
+
+        w->before = before;
+        w->begin = m->rindex;
+        w->end = m->rindex + c->item_size;
+
+        w->array_size = array_size;
+        w->item_size = item_size;
+        w->offsets = offsets;
+        w->n_offsets = n_offsets;
+        w->offset_index = 0;
+
+        return 1;
+}
+
+_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
+        struct bus_container *c;
+        unsigned saved;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(m->n_containers > 0, -ENXIO);
+
+        c = message_get_container(m);
+
+        if (c->enclosing != SD_BUS_TYPE_ARRAY) {
+                if (c->signature && c->signature[c->index] != 0)
+                        return -EBUSY;
+        }
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                if (m->rindex < c->end)
+                        return -EBUSY;
+
+        } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
+                uint32_t l;
+
+                l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
+                if (c->begin + l != m->rindex)
+                        return -EBUSY;
+        }
+
+        free(c->signature);
+        free(c->peeked_signature);
+        free(c->offsets);
+        m->n_containers--;
+
+        c = message_get_container(m);
+
+        saved = c->index;
+        c->index = c->saved_index;
+        r = container_next_item(m, c, &m->rindex);
+        c->index = saved;
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static void message_quit_container(sd_bus_message *m) {
+        struct bus_container *c;
+
+        assert(m);
+        assert(m->sealed);
+        assert(m->n_containers > 0);
+
+        c = message_get_container(m);
+
+        /* Undo seeks */
+        assert(m->rindex >= c->before);
+        m->rindex = c->before;
+
+        /* Free container */
+        free(c->signature);
+        free(c->offsets);
+        m->n_containers--;
+
+        /* Correct index of new top-level container */
+        c = message_get_container(m);
+        c->index = c->saved_index;
+}
+
+_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
+        struct bus_container *c;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+
+        if (message_end_of_signature(m))
+                goto eof;
+
+        if (message_end_of_array(m, m->rindex))
+                goto eof;
+
+        c = message_get_container(m);
+
+        if (bus_type_is_basic(c->signature[c->index])) {
+                if (contents)
+                        *contents = NULL;
+                if (type)
+                        *type = c->signature[c->index];
+                return 1;
+        }
+
+        if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
+
+                if (contents) {
+                        size_t l;
+                        char *sig;
+
+                        r = signature_element_length(c->signature+c->index+1, &l);
+                        if (r < 0)
+                                return r;
+
+                        assert(l >= 1);
+
+                        sig = strndup(c->signature + c->index + 1, l);
+                        if (!sig)
+                                return -ENOMEM;
+
+                        free(c->peeked_signature);
+                        *contents = c->peeked_signature = sig;
+                }
+
+                if (type)
+                        *type = SD_BUS_TYPE_ARRAY;
+
+                return 1;
+        }
+
+        if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
+            c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
+
+                if (contents) {
+                        size_t l;
+                        char *sig;
+
+                        r = signature_element_length(c->signature+c->index, &l);
+                        if (r < 0)
+                                return r;
+
+                        assert(l >= 2);
+                        sig = strndup(c->signature + c->index + 1, l - 2);
+                        if (!sig)
+                                return -ENOMEM;
+
+                        free(c->peeked_signature);
+                        *contents = c->peeked_signature = sig;
+                }
+
+                if (type)
+                        *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
+
+                return 1;
+        }
+
+        if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
+                if (contents) {
+                        void *q;
+
+                        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                                size_t k;
+
+                                if (c->item_size < 2)
+                                        return -EBADMSG;
+
+                                /* Look for the NUL delimiter that
+                                   separates the payload from the
+                                   signature. Since the body might be
+                                   in a different part that then the
+                                   signature we map byte by byte. */
+
+                                for (k = 2; k <= c->item_size; k++) {
+                                        size_t where;
+
+                                        where = m->rindex + c->item_size - k;
+                                        r = message_peek_body(m, &where, 1, k, &q);
+                                        if (r < 0)
+                                                return r;
+
+                                        if (*(char*) q == 0)
+                                                break;
+                                }
+
+                                if (k > c->item_size)
+                                        return -EBADMSG;
+
+                                free(c->peeked_signature);
+                                c->peeked_signature = strndup((char*) q + 1, k - 1);
+                                if (!c->peeked_signature)
+                                        return -ENOMEM;
+
+                                if (!signature_is_valid(c->peeked_signature, true))
+                                        return -EBADMSG;
+
+                                *contents = c->peeked_signature;
+                        } else {
+                                size_t rindex, l;
+
+                                rindex = m->rindex;
+                                r = message_peek_body(m, &rindex, 1, 1, &q);
+                                if (r < 0)
+                                        return r;
+
+                                l = *(uint8_t*) q;
+                                r = message_peek_body(m, &rindex, 1, l+1, &q);
+                                if (r < 0)
+                                        return r;
+
+                                if (!validate_signature(q, l))
+                                        return -EBADMSG;
+
+                                *contents = q;
+                        }
+                }
+
+                if (type)
+                        *type = SD_BUS_TYPE_VARIANT;
+
+                return 1;
+        }
+
+        return -EINVAL;
+
+eof:
+        if (type)
+                *type = 0;
+        if (contents)
+                *contents = NULL;
+        return 0;
+}
+
+_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
+        struct bus_container *c;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+
+        if (complete) {
+                message_reset_containers(m);
+                m->rindex = 0;
+
+                c = message_get_container(m);
+        } else {
+                c = message_get_container(m);
+
+                c->offset_index = 0;
+                c->index = 0;
+                m->rindex = c->begin;
+        }
+
+        c->offset_index = 0;
+        c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
+
+        return !isempty(c->signature);
+}
+
+static int message_read_ap(
+                sd_bus_message *m,
+                const char *types,
+                va_list ap) {
+
+        unsigned n_array, n_struct;
+        TypeStack stack[BUS_CONTAINER_DEPTH];
+        unsigned stack_ptr = 0;
+        unsigned n_loop = 0;
+        int r;
+
+        assert(m);
+
+        if (isempty(types))
+                return 0;
+
+        /* Ideally, we'd just call ourselves recursively on every
+         * complex type. However, the state of a va_list that is
+         * passed to a function is undefined after that function
+         * returns. This means we need to docode the va_list linearly
+         * in a single stackframe. We hence implement our own
+         * home-grown stack in an array. */
+
+        n_array = (unsigned) -1; /* lenght of current array entries */
+        n_struct = strlen(types); /* length of current struct contents signature */
+
+        for (;;) {
+                const char *t;
+
+                n_loop++;
+
+                if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
+                        r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                break;
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return r;
+
+                        continue;
+                }
+
+                t = types;
+                if (n_array != (unsigned) -1)
+                        n_array --;
+                else {
+                        types ++;
+                        n_struct--;
+                }
+
+                switch (*t) {
+
+                case SD_BUS_TYPE_BYTE:
+                case SD_BUS_TYPE_BOOLEAN:
+                case SD_BUS_TYPE_INT16:
+                case SD_BUS_TYPE_UINT16:
+                case SD_BUS_TYPE_INT32:
+                case SD_BUS_TYPE_UINT32:
+                case SD_BUS_TYPE_INT64:
+                case SD_BUS_TYPE_UINT64:
+                case SD_BUS_TYPE_DOUBLE:
+                case SD_BUS_TYPE_STRING:
+                case SD_BUS_TYPE_OBJECT_PATH:
+                case SD_BUS_TYPE_SIGNATURE:
+                case SD_BUS_TYPE_UNIX_FD: {
+                        void *p;
+
+                        p = va_arg(ap, void*);
+                        r = sd_bus_message_read_basic(m, *t, p);
+                        if (r < 0)
+                                return r;
+                        if (r == 0) {
+                                if (n_loop <= 1)
+                                        return 0;
+
+                                return -ENXIO;
+                        }
+
+                        break;
+                }
+
+                case SD_BUS_TYPE_ARRAY: {
+                        size_t k;
+
+                        r = signature_element_length(t + 1, &k);
+                        if (r < 0)
+                                return r;
+
+                        {
+                                char s[k + 1];
+                                memcpy(s, t + 1, k);
+                                s[k] = 0;
+
+                                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
+                                if (r < 0)
+                                        return r;
+                                if (r == 0) {
+                                        if (n_loop <= 1)
+                                                return 0;
+
+                                        return -ENXIO;
+                                }
+                        }
+
+                        if (n_array == (unsigned) -1) {
+                                types += k;
+                                n_struct -= k;
+                        }
+
+                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+                        if (r < 0)
+                                return r;
+
+                        types = t + 1;
+                        n_struct = k;
+                        n_array = va_arg(ap, unsigned);
+
+                        break;
+                }
+
+                case SD_BUS_TYPE_VARIANT: {
+                        const char *s;
+
+                        s = va_arg(ap, const char *);
+                        if (!s)
+                                return -EINVAL;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
+                        if (r < 0)
+                                return r;
+                        if (r == 0) {
+                                if (n_loop <= 1)
+                                        return 0;
+
+                                return -ENXIO;
+                        }
+
+                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+                        if (r < 0)
+                                return r;
+
+                        types = s;
+                        n_struct = strlen(s);
+                        n_array = (unsigned) -1;
+
+                        break;
+                }
+
+                case SD_BUS_TYPE_STRUCT_BEGIN:
+                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                        size_t k;
+
+                        r = signature_element_length(t, &k);
+                        if (r < 0)
+                                return r;
+
+                        {
+                                char s[k - 1];
+                                memcpy(s, t + 1, k - 2);
+                                s[k - 2] = 0;
+
+                                r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
+                                if (r < 0)
+                                        return r;
+                                if (r == 0) {
+                                        if (n_loop <= 1)
+                                                return 0;
+                                        return -ENXIO;
+                                }
+                        }
+
+                        if (n_array == (unsigned) -1) {
+                                types += k - 1;
+                                n_struct -= k - 1;
+                        }
+
+                        r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+                        if (r < 0)
+                                return r;
+
+                        types = t + 1;
+                        n_struct = k - 2;
+                        n_array = (unsigned) -1;
+
+                        break;
+                }
+
+                default:
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
+
+_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
+        va_list ap;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(types, -EINVAL);
+
+        va_start(ap, types);
+        r = message_read_ap(m, types, ap);
+        va_end(ap);
+
+        return r;
+}
+
+_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(types, -EINVAL);
+
+        if (isempty(types))
+                return 0;
+
+        switch (*types) {
+
+        case SD_BUS_TYPE_BYTE:
+        case SD_BUS_TYPE_BOOLEAN:
+        case SD_BUS_TYPE_INT16:
+        case SD_BUS_TYPE_UINT16:
+        case SD_BUS_TYPE_INT32:
+        case SD_BUS_TYPE_UINT32:
+        case SD_BUS_TYPE_INT64:
+        case SD_BUS_TYPE_UINT64:
+        case SD_BUS_TYPE_DOUBLE:
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_OBJECT_PATH:
+        case SD_BUS_TYPE_SIGNATURE:
+        case SD_BUS_TYPE_UNIX_FD:
+
+                r = sd_bus_message_read_basic(m, *types, NULL);
+                if (r <= 0)
+                        return r;
+
+                r = sd_bus_message_skip(m, types + 1);
+                if (r < 0)
+                        return r;
+
+                return 1;
+
+        case SD_BUS_TYPE_ARRAY: {
+                size_t k;
+
+                r = signature_element_length(types + 1, &k);
+                if (r < 0)
+                        return r;
+
+                {
+                        char s[k+1];
+                        memcpy(s, types+1, k);
+                        s[k] = 0;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
+                        if (r <= 0)
+                                return r;
+
+                        for (;;) {
+                                r = sd_bus_message_skip(m, s);
+                                if (r < 0)
+                                        return r;
+                                if (r == 0)
+                                        break;
+                        }
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_skip(m, types + 1 + k);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_VARIANT: {
+                const char *contents;
+                char x;
+
+                r = sd_bus_message_peek_type(m, &x, &contents);
+                if (r <= 0)
+                        return r;
+
+                if (x != SD_BUS_TYPE_VARIANT)
+                        return -ENXIO;
+
+                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
+                if (r <= 0)
+                        return r;
+
+                r = sd_bus_message_skip(m, contents);
+                if (r < 0)
+                        return r;
+                assert(r != 0);
+
+                r = sd_bus_message_exit_container(m);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_skip(m, types + 1);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_STRUCT_BEGIN:
+        case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                size_t k;
+
+                r = signature_element_length(types, &k);
+                if (r < 0)
+                        return r;
+
+                {
+                        char s[k-1];
+                        memcpy(s, types+1, k-2);
+                        s[k-2] = 0;
+
+                        r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
+                        if (r <= 0)
+                                return r;
+
+                        r = sd_bus_message_skip(m, s);
+                        if (r < 0)
+                                return r;
+                        assert(r != 0);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_skip(m, types + k);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        default:
+                return -EINVAL;
+        }
+}
+
+_public_ int sd_bus_message_read_array(sd_bus_message *m,
+                                       char type,
+                                       const void **ptr,
+                                       size_t *size) {
+        struct bus_container *c;
+        void *p;
+        size_t sz;
+        ssize_t align;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(bus_type_is_trivial(type), -EINVAL);
+        assert_return(ptr, -EINVAL);
+        assert_return(size, -EINVAL);
+        assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
+        if (r <= 0)
+                return r;
+
+        c = message_get_container(m);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
+                if (align < 0)
+                        return align;
+
+                sz = c->end - c->begin;
+        } else {
+                align = bus_type_get_alignment(type);
+                if (align < 0)
+                        return align;
+
+                sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
+        }
+
+        if (sz == 0)
+                /* Zero length array, let's return some aligned
+                 * pointer that is not NULL */
+                p = (uint8_t*) NULL + align;
+        else {
+                r = message_peek_body(m, &m->rindex, align, sz, &p);
+                if (r < 0)
+                        goto fail;
+        }
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                goto fail;
+
+        *ptr = (const void*) p;
+        *size = sz;
+
+        return 1;
+
+fail:
+        message_quit_container(m);
+        return r;
+}
+
+static int message_peek_fields(
+                sd_bus_message *m,
+                size_t *rindex,
+                size_t align,
+                size_t nbytes,
+                void **ret) {
+
+        assert(m);
+        assert(rindex);
+        assert(align > 0);
+
+        return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
+}
+
+static int message_peek_field_uint32(
+                sd_bus_message *m,
+                size_t *ri,
+                size_t item_size,
+                uint32_t *ret) {
+
+        int r;
+        void *q;
+
+        assert(m);
+        assert(ri);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
+                return -EBADMSG;
+
+        /* identical for gvariant and dbus1 */
+
+        r = message_peek_fields(m, ri, 4, 4, &q);
+        if (r < 0)
+                return r;
+
+        if (ret)
+                *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+
+        return 0;
+}
+
+static int message_peek_field_string(
+                sd_bus_message *m,
+                bool (*validate)(const char *p),
+                size_t *ri,
+                size_t item_size,
+                const char **ret) {
+
+        uint32_t l;
+        int r;
+        void *q;
+
+        assert(m);
+        assert(ri);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+
+                if (item_size <= 0)
+                        return -EBADMSG;
+
+                r = message_peek_fields(m, ri, 1, item_size, &q);
+                if (r < 0)
+                        return r;
+
+                l = item_size - 1;
+        } else {
+                r = message_peek_field_uint32(m, ri, 4, &l);
+                if (r < 0)
+                        return r;
+
+                r = message_peek_fields(m, ri, 1, l+1, &q);
+                if (r < 0)
+                        return r;
+        }
+
+        if (validate) {
+                if (!validate_nul(q, l))
+                        return -EBADMSG;
+
+                if (!validate(q))
+                        return -EBADMSG;
+        } else {
+                if (!validate_string(q, l))
+                        return -EBADMSG;
+        }
+
+        if (ret)
+                *ret = q;
+
+        return 0;
+}
+
+static int message_peek_field_signature(
+                sd_bus_message *m,
+                size_t *ri,
+                size_t item_size,
+                const char **ret) {
+
+        size_t l;
+        int r;
+        void *q;
+
+        assert(m);
+        assert(ri);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+
+                if (item_size <= 0)
+                        return -EBADMSG;
+
+                r = message_peek_fields(m, ri, 1, item_size, &q);
+                if (r < 0)
+                        return r;
+
+                l = item_size - 1;
+        } else {
+                r = message_peek_fields(m, ri, 1, 1, &q);
+                if (r < 0)
+                        return r;
+
+                l = *(uint8_t*) q;
+                r = message_peek_fields(m, ri, 1, l+1, &q);
+                if (r < 0)
+                        return r;
+        }
+
+        if (!validate_signature(q, l))
+                return -EBADMSG;
+
+        if (ret)
+                *ret = q;
+
+        return 0;
+}
+
+static int message_skip_fields(
+                sd_bus_message *m,
+                size_t *ri,
+                uint32_t array_size,
+                const char **signature) {
+
+        size_t original_index;
+        int r;
+
+        assert(m);
+        assert(ri);
+        assert(signature);
+        assert(!BUS_MESSAGE_IS_GVARIANT(m));
+
+        original_index = *ri;
+
+        for (;;) {
+                char t;
+                size_t l;
+
+                if (array_size != (uint32_t) -1 &&
+                    array_size <= *ri - original_index)
+                        return 0;
+
+                t = **signature;
+                if (!t)
+                        return 0;
+
+                if (t == SD_BUS_TYPE_STRING) {
+
+                        r = message_peek_field_string(m, NULL, ri, 0, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
+
+                        r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_SIGNATURE) {
+
+                        r = message_peek_field_signature(m, ri, 0, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (bus_type_is_basic(t)) {
+                        ssize_t align, k;
+
+                        align = bus_type_get_alignment(t);
+                        k = bus_type_get_size(t);
+                        assert(align > 0 && k > 0);
+
+                        r = message_peek_fields(m, ri, align, k, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_ARRAY) {
+
+                        r = signature_element_length(*signature+1, &l);
+                        if (r < 0)
+                                return r;
+
+                        assert(l >= 1);
+                        {
+                                char sig[l-1], *s;
+                                uint32_t nas;
+                                int alignment;
+
+                                strncpy(sig, *signature + 1, l-1);
+                                s = sig;
+
+                                alignment = bus_type_get_alignment(sig[0]);
+                                if (alignment < 0)
+                                        return alignment;
+
+                                r = message_peek_field_uint32(m, ri, 0, &nas);
+                                if (r < 0)
+                                        return r;
+                                if (nas > BUS_ARRAY_MAX_SIZE)
+                                        return -EBADMSG;
+
+                                r = message_peek_fields(m, ri, alignment, 0, NULL);
+                                if (r < 0)
+                                        return r;
+
+                                r = message_skip_fields(m, ri, nas, (const char**) &s);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        (*signature) += 1 + l;
+
+                } else if (t == SD_BUS_TYPE_VARIANT) {
+                        const char *s;
+
+                        r = message_peek_field_signature(m, ri, 0, &s);
+                        if (r < 0)
+                                return r;
+
+                        r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_STRUCT ||
+                           t == SD_BUS_TYPE_DICT_ENTRY) {
+
+                        r = signature_element_length(*signature, &l);
+                        if (r < 0)
+                                return r;
+
+                        assert(l >= 2);
+                        {
+                                char sig[l-1], *s;
+                                strncpy(sig, *signature + 1, l-1);
+                                s = sig;
+
+                                r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        *signature += l;
+                } else
+                        return -EINVAL;
+        }
+}
+
+int bus_message_parse_fields(sd_bus_message *m) {
+        size_t ri;
+        int r;
+        uint32_t unix_fds = 0;
+        void *offsets = NULL;
+        unsigned n_offsets = 0;
+        size_t sz = 0;
+        unsigned i = 0;
+
+        assert(m);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                void *q;
+
+                sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0);
+                if (sz > 0) {
+                        size_t framing;
+
+                        ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz;
+                        r = message_peek_fields(m, &ri, 1, sz, &q);
+                        if (r < 0)
+                                return r;
+
+                        framing = read_word_le(q, sz);
+                        if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz)
+                                return -EBADMSG;
+                        if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0)
+                                return -EBADMSG;
+
+                        ri = framing;
+                        r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets);
+                        if (r < 0)
+                                return r;
+
+                        n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz;
+                }
+        }
+
+        ri = 0;
+        while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) {
+                _cleanup_free_ char *sig = NULL;
+                const char *signature;
+                uint8_t *header;
+                size_t item_size = (size_t) -1;
+
+                if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                        if (i >= n_offsets)
+                                break;
+
+                        if (i == 0)
+                                ri = 0;
+                        else
+                                ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
+                }
+
+                r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
+                if (r < 0)
+                        return r;
+
+                if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                        size_t where, end;
+                        char *b;
+                        void *q;
+
+                        end = read_word_le((uint8_t*) offsets + i*sz, sz);
+
+                        if (end < ri)
+                                return -EBADMSG;
+
+                        where = ri = ALIGN_TO(ri, 8);
+                        item_size = end - ri;
+                        r = message_peek_fields(m, &where, 1, item_size, &q);
+                        if (r < 0)
+                                return r;
+
+                        b = memrchr(q, 0, item_size);
+                        if (!b)
+                                return -EBADMSG;
+
+                        sig = strndup(b+1, item_size - (b+1-(char*) q));
+                        if (!sig)
+                                return -ENOMEM;
+
+                        signature = sig;
+                        item_size = b - (char*) q;
+                } else {
+                        r = message_peek_field_signature(m, &ri, 0, &signature);
+                        if (r < 0)
+                                return r;
+                }
+
+                switch (*header) {
+                case _BUS_MESSAGE_HEADER_INVALID:
+                        return -EBADMSG;
+
+                case BUS_MESSAGE_HEADER_PATH:
+
+                        if (m->path)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "o"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
+                        break;
+
+                case BUS_MESSAGE_HEADER_INTERFACE:
+
+                        if (m->interface)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
+                        break;
+
+                case BUS_MESSAGE_HEADER_MEMBER:
+
+                        if (m->member)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
+                        break;
+
+                case BUS_MESSAGE_HEADER_ERROR_NAME:
+
+                        if (m->error.name)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
+                        if (r >= 0)
+                                m->error._need_free = -1;
+
+                        break;
+
+                case BUS_MESSAGE_HEADER_DESTINATION:
+
+                        if (m->destination)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
+                        break;
+
+                case BUS_MESSAGE_HEADER_SENDER:
+
+                        if (m->sender)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
+
+                        if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
+                                m->creds.unique_name = (char*) m->sender;
+                                m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
+                        }
+
+                        break;
+
+
+                case BUS_MESSAGE_HEADER_SIGNATURE: {
+                        const char *s;
+                        char *c;
+
+                        if (m->root_container.signature)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "g"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_signature(m, &ri, item_size, &s);
+                        if (r < 0)
+                                return r;
+
+                        c = strdup(s);
+                        if (!c)
+                                return -ENOMEM;
+
+                        free(m->root_container.signature);
+                        m->root_container.signature = c;
+                        break;
+                }
+
+                case BUS_MESSAGE_HEADER_REPLY_SERIAL:
+                        if (m->reply_cookie != 0)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "u"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_uint32(m, &ri, item_size, &m->reply_cookie);
+                        if (r < 0)
+                                return r;
+
+                        if (m->reply_cookie == 0)
+                                return -EBADMSG;
+
+                        break;
+
+                case BUS_MESSAGE_HEADER_UNIX_FDS:
+                        if (unix_fds != 0)
+                                return -EBADMSG;
+
+                        if (!streq(signature, "u"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
+                        if (r < 0)
+                                return -EBADMSG;
+
+                        if (unix_fds == 0)
+                                return -EBADMSG;
+
+                        break;
+
+                default:
+                        if (!BUS_MESSAGE_IS_GVARIANT(m))
+                                r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
+                }
+
+                if (r < 0)
+                        return r;
+
+                i++;
+        }
+
+        if (m->n_fds != unix_fds)
+                return -EBADMSG;
+
+        switch (m->header->type) {
+
+        case SD_BUS_MESSAGE_SIGNAL:
+                if (!m->path || !m->interface || !m->member)
+                        return -EBADMSG;
+                break;
+
+        case SD_BUS_MESSAGE_METHOD_CALL:
+
+                if (!m->path || !m->member)
+                        return -EBADMSG;
+
+                break;
+
+        case SD_BUS_MESSAGE_METHOD_RETURN:
+
+                if (m->reply_cookie == 0)
+                        return -EBADMSG;
+                break;
+
+        case SD_BUS_MESSAGE_METHOD_ERROR:
+
+                if (m->reply_cookie == 0 || !m->error.name)
+                        return -EBADMSG;
+                break;
+        }
+
+        /* Refuse non-local messages that claim they are local */
+        if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
+                return -EBADMSG;
+        if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
+                return -EBADMSG;
+        if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
+                return -EBADMSG;
+
+        m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
+
+        if (BUS_MESSAGE_IS_GVARIANT(m)) {
+                r = build_struct_offsets(
+                                m,
+                                m->root_container.signature,
+                                BUS_MESSAGE_BODY_SIZE(m),
+                                &m->root_container.item_size,
+                                &m->root_container.offsets,
+                                &m->root_container.n_offsets);
+                if (r < 0)
+                        return r;
+        }
+
+        /* Try to read the error message, but if we can't it's a non-issue */
+        if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
+                sd_bus_message_read(m, "s", &m->error.message);
+
+        return 0;
+}
+
+_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
+        assert_return(m, -EINVAL);
+        assert_return(destination, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->destination, -EEXIST);
+
+        return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
+}
+
+int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
+        size_t total;
+        void *p, *e;
+        unsigned i;
+        struct bus_body_part *part;
+
+        assert(m);
+        assert(buffer);
+        assert(sz);
+
+        total = BUS_MESSAGE_SIZE(m);
+
+        p = malloc(total);
+        if (!p)
+                return -ENOMEM;
+
+        e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
+        MESSAGE_FOREACH_PART(part, i, m)
+                e = mempcpy(e, part->data, part->size);
+
+        assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
+
+        *buffer = p;
+        *sz = total;
+
+        return 0;
+}
+
+int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
+        int r;
+
+        assert(m);
+        assert(l);
+
+        r = sd_bus_message_enter_container(m, 'a', "s");
+        if (r <= 0)
+                return r;
+
+        for (;;) {
+                const char *s;
+
+                r = sd_bus_message_read_basic(m, 's', &s);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = strv_extend(l, s);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
+        char **strv = NULL;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(l, -EINVAL);
+
+        r = bus_message_read_strv_extend(m, &strv);
+        if (r <= 0) {
+                strv_free(strv);
+                return r;
+        }
+
+        *l = strv;
+        return 1;
+}
+
+const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
+        int r;
+        const char *t = NULL;
+        unsigned j;
+
+        assert(m);
+
+        r = sd_bus_message_rewind(m, true);
+        if (r < 0)
+                return NULL;
+
+        for (j = 0; j <= i; j++) {
+                char type;
+
+                r = sd_bus_message_peek_type(m, &type, NULL);
+                if (r < 0)
+                        return NULL;
+
+                if (type != SD_BUS_TYPE_STRING &&
+                    type != SD_BUS_TYPE_OBJECT_PATH &&
+                    type != SD_BUS_TYPE_SIGNATURE)
+                        return NULL;
+
+                r = sd_bus_message_read_basic(m, type, &t);
+                if (r < 0)
+                        return NULL;
+        }
+
+        return t;
+}
+
+bool bus_header_is_complete(struct bus_header *h, size_t size) {
+        size_t full;
+
+        assert(h);
+        assert(size);
+
+        if (size < sizeof(struct bus_header))
+                return false;
+
+        full = sizeof(struct bus_header) +
+                (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
+
+        return size >= full;
+}
+
+int bus_header_message_size(struct bus_header *h, size_t *sum) {
+        size_t fs, bs;
+
+        assert(h);
+        assert(sum);
+
+        if (h->endian == BUS_NATIVE_ENDIAN) {
+                fs = h->fields_size;
+                bs = h->body_size;
+        } else if (h->endian == BUS_REVERSE_ENDIAN) {
+                fs = bswap_32(h->fields_size);
+                bs = bswap_32(h->body_size);
+        } else
+                return -EBADMSG;
+
+        *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
+        return 0;
+}
+
+_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
+
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
+                return 0;
+
+        return sd_bus_error_get_errno(&m->error);
+}
+
+_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
+        struct bus_container *c;
+
+        assert_return(m, NULL);
+
+        c = complete ? &m->root_container : message_get_container(m);
+        return strempty(c->signature);
+}
+
+_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
+        bool done_something = false;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(source, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(source->sealed, -EPERM);
+
+        do {
+                const char *contents;
+                char type;
+                union {
+                        uint8_t u8;
+                        uint16_t u16;
+                        int16_t s16;
+                        uint32_t u32;
+                        int32_t s32;
+                        uint64_t u64;
+                        int64_t s64;
+                        double d64;
+                        const char *string;
+                        int i;
+                } basic;
+
+                r = sd_bus_message_peek_type(source, &type, &contents);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                done_something = true;
+
+                if (bus_type_is_container(type) > 0) {
+
+                        r = sd_bus_message_enter_container(source, type, contents);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_open_container(m, type, contents);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_copy(m, source, true);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_close_container(m);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_exit_container(source);
+                        if (r < 0)
+                                return r;
+
+                        continue;
+                }
+
+                r = sd_bus_message_read_basic(source, type, &basic);
+                if (r < 0)
+                        return r;
+
+                assert(r > 0);
+
+                if (type == SD_BUS_TYPE_OBJECT_PATH ||
+                    type == SD_BUS_TYPE_SIGNATURE ||
+                    type == SD_BUS_TYPE_STRING)
+                        r = sd_bus_message_append_basic(m, type, basic.string);
+                else
+                        r = sd_bus_message_append_basic(m, type, &basic);
+
+                if (r < 0)
+                        return r;
+
+        } while (all);
+
+        return done_something;
+}
+
+_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
+        const char *c;
+        char t;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(!type || bus_type_is_valid(type), -EINVAL);
+        assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
+        assert_return(type || contents, -EINVAL);
+        assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
+
+        r = sd_bus_message_peek_type(m, &t, &c);
+        if (r <= 0)
+                return r;
+
+        if (type != 0 && type != t)
+                return 0;
+
+        if (contents && !streq_ptr(contents, c))
+                return 0;
+
+        return 1;
+}
+
+_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
+        assert_return(m, NULL);
+
+        return m->bus;
+}
+
+int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
+        _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
+        usec_t timeout;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(*m);
+
+        switch ((*m)->header->type) {
+
+        case SD_BUS_MESSAGE_SIGNAL:
+                r = sd_bus_message_new_signal(bus, (*m)->path, (*m)->interface, (*m)->member, &n);
+                if (r < 0)
+                        return r;
+
+                break;
+
+        case SD_BUS_MESSAGE_METHOD_CALL:
+                r = sd_bus_message_new_method_call(bus, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member, &n);
+                if (r < 0)
+                        return r;
+
+                break;
+
+        case SD_BUS_MESSAGE_METHOD_RETURN:
+        case SD_BUS_MESSAGE_METHOD_ERROR:
+
+                n = message_new(bus, (*m)->header->type);
+                if (!n)
+                        return -ENOMEM;
+
+                n->reply_cookie = (*m)->reply_cookie;
+                r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_cookie);
+                if (r < 0)
+                        return r;
+
+                if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
+                        r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
+                        if (r < 0)
+                                return r;
+
+                        n->error._need_free = -1;
+                }
+
+                break;
+
+        default:
+                return -EINVAL;
+        }
+
+        if ((*m)->destination && !n->destination) {
+                r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
+                if (r < 0)
+                        return r;
+        }
+
+        if ((*m)->sender && !n->sender) {
+                r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
+                if (r < 0)
+                        return r;
+        }
+
+        n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
+
+        r = sd_bus_message_copy(n, *m, true);
+        if (r < 0)
+                return r;
+
+        timeout = (*m)->timeout;
+        if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED))
+                timeout = BUS_DEFAULT_TIMEOUT;
+
+        r = bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
+        if (r < 0)
+                return r;
+
+        sd_bus_message_unref(*m);
+        *m = n;
+        n = NULL;
+
+        return 0;
+}
+
+int bus_message_append_sender(sd_bus_message *m, const char *sender) {
+        assert(m);
+        assert(sender);
+
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->sender, -EPERM);
+
+        return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
+}
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
new file mode 100644
index 0000000..5322375
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -0,0 +1,244 @@
+/*-*- 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 <stdbool.h>
+#include <byteswap.h>
+#include <sys/socket.h>
+
+#include "macro.h"
+#include "sd-bus.h"
+#include "kdbus.h"
+#include "time-util.h"
+#include "bus-creds.h"
+#include "bus-protocol.h"
+
+struct bus_container {
+        char enclosing;
+        bool need_offsets:1;
+
+        /* Indexes into the signature  string */
+        unsigned index, saved_index;
+        char *signature;
+
+        size_t before, begin, end;
+
+        /* dbus1: pointer to the array size value, if this is a value */
+        uint32_t *array_size;
+
+        /* gvariant: list of offsets to end of children if this is struct/dict entry/array */
+        size_t *offsets, n_offsets, offsets_allocated, offset_index;
+        size_t item_size;
+
+        char *peeked_signature;
+};
+
+struct bus_header {
+        uint8_t endian;
+        uint8_t type;
+        uint8_t flags;
+        uint8_t version;
+        uint32_t body_size;
+
+        /* Note that what the bus spec calls "serial" we'll call
+        "cookie" instead, because we don't want to imply that the
+        cookie was in any way monotonically increasing. */
+        uint32_t serial;
+        uint32_t fields_size;
+} _packed_;
+
+struct bus_body_part {
+        struct bus_body_part *next;
+        void *data;
+        size_t size;
+        size_t mapped;
+        size_t allocated;
+        int memfd;
+        bool free_this:1;
+        bool munmap_this:1;
+        bool sealed:1;
+        bool is_zero:1;
+};
+
+struct sd_bus_message {
+        unsigned n_ref;
+
+        sd_bus *bus;
+
+        uint32_t reply_cookie;
+
+        const char *path;
+        const char *interface;
+        const char *member;
+        const char *destination;
+        const char *sender;
+
+        sd_bus_error error;
+
+        sd_bus_creds creds;
+
+        usec_t monotonic;
+        usec_t realtime;
+
+        bool sealed:1;
+        bool dont_send:1;
+        bool allow_fds:1;
+        bool free_header:1;
+        bool free_kdbus:1;
+        bool free_fds:1;
+        bool release_kdbus:1;
+        bool poisoned:1;
+
+        struct bus_header *header;
+        struct bus_body_part body;
+        struct bus_body_part *body_end;
+        unsigned n_body_parts;
+
+        size_t rindex;
+        struct bus_body_part *cached_rindex_part;
+        size_t cached_rindex_part_begin;
+
+        uint32_t n_fds;
+        int *fds;
+
+        struct bus_container root_container, *containers;
+        unsigned n_containers;
+        size_t containers_allocated;
+
+        struct iovec *iovec;
+        struct iovec iovec_fixed[2];
+        unsigned n_iovec;
+
+        struct kdbus_msg *kdbus;
+
+        char *peeked_signature;
+
+        /* If set replies to this message must carry the signature
+         * specified here to successfully seal. This is initialized
+         * from the vtable data */
+        const char *enforced_reply_signature;
+
+        usec_t timeout;
+
+        char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
+        char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
+
+        size_t header_offsets[_BUS_MESSAGE_HEADER_MAX];
+        unsigned n_header_offsets;
+};
+
+#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != BUS_NATIVE_ENDIAN)
+
+static inline uint16_t BUS_MESSAGE_BSWAP16(sd_bus_message *m, uint16_t u) {
+        return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_16(u) : u;
+}
+
+static inline uint32_t BUS_MESSAGE_BSWAP32(sd_bus_message *m, uint32_t u) {
+        return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_32(u) : u;
+}
+
+static inline uint64_t BUS_MESSAGE_BSWAP64(sd_bus_message *m, uint64_t u) {
+        return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_64(u) : u;
+}
+
+static inline uint32_t BUS_MESSAGE_COOKIE(sd_bus_message *m) {
+        return BUS_MESSAGE_BSWAP32(m, m->header->serial);
+}
+
+static inline uint32_t BUS_MESSAGE_BODY_SIZE(sd_bus_message *m) {
+        return BUS_MESSAGE_BSWAP32(m, m->header->body_size);
+}
+
+static inline uint32_t BUS_MESSAGE_FIELDS_SIZE(sd_bus_message *m) {
+        return BUS_MESSAGE_BSWAP32(m, m->header->fields_size);
+}
+
+static inline uint32_t BUS_MESSAGE_SIZE(sd_bus_message *m) {
+        return
+                sizeof(struct bus_header) +
+                ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) +
+                BUS_MESSAGE_BODY_SIZE(m);
+}
+
+static inline uint32_t BUS_MESSAGE_BODY_BEGIN(sd_bus_message *m) {
+        return
+                sizeof(struct bus_header) +
+                ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
+}
+
+static inline void* BUS_MESSAGE_FIELDS(sd_bus_message *m) {
+        return (uint8_t*) m->header + sizeof(struct bus_header);
+}
+
+static inline bool BUS_MESSAGE_IS_GVARIANT(sd_bus_message *m) {
+        return m->header->version == 2;
+}
+
+int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout);
+int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);
+int bus_message_read_strv_extend(sd_bus_message *m, char ***l);
+
+int bus_message_from_header(
+                sd_bus *bus,
+                void *header,
+                size_t length,
+                int *fds,
+                unsigned n_fds,
+                const struct ucred *ucred,
+                const char *label,
+                size_t extra,
+                sd_bus_message **ret);
+
+int bus_message_from_malloc(
+                sd_bus *bus,
+                void *buffer,
+                size_t length,
+                int *fds,
+                unsigned n_fds,
+                const struct ucred *ucred,
+                const char *label,
+                sd_bus_message **ret);
+
+const char* bus_message_get_arg(sd_bus_message *m, unsigned i);
+
+int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
+
+int bus_message_parse_fields(sd_bus_message *m);
+
+bool bus_header_is_complete(struct bus_header *h, size_t size);
+int bus_header_message_size(struct bus_header *h, size_t *sum);
+
+struct bus_body_part *message_append_part(sd_bus_message *m);
+
+#define MESSAGE_FOREACH_PART(part, i, m) \
+        for ((i) = 0, (part) = &(m)->body; (i) < (m)->n_body_parts; (i)++, (part) = (part)->next)
+
+int bus_body_part_map(struct bus_body_part *part);
+void bus_body_part_unmap(struct bus_body_part *part);
+
+int bus_message_to_errno(sd_bus_message *m);
+
+int bus_message_new_synthetic_error(sd_bus *bus, uint64_t serial, const sd_bus_error *e, sd_bus_message **m);
+
+int bus_message_remarshal(sd_bus *bus, sd_bus_message **m);
+
+int bus_message_append_sender(sd_bus_message *m, const char *sender);
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
new file mode 100644
index 0000000..b116a5d
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -0,0 +1,2507 @@
+/*-*- 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 <sys/capability.h>
+
+#include "strv.h"
+#include "set.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-type.h"
+#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,
+                const char *path,
+                struct node_vtable *c,
+                void **userdata,
+                sd_bus_error *error) {
+
+        void *u;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(c);
+
+        u = c->userdata;
+        if (c->find) {
+                r = c->find(bus, path, c->interface, u, &u, error);
+                if (r < 0)
+                        return r;
+                if (sd_bus_error_is_set(error))
+                        return -sd_bus_error_get_errno(error);
+                if (r == 0)
+                        return r;
+        }
+
+        if (userdata)
+                *userdata = u;
+
+        return 1;
+}
+
+static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
+        assert(p);
+
+        return (uint8_t*) u + p->x.property.offset;
+}
+
+static int vtable_property_get_userdata(
+                sd_bus *bus,
+                const char *path,
+                struct vtable_member *p,
+                void **userdata,
+                sd_bus_error *error) {
+
+        void *u;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(p);
+        assert(userdata);
+
+        r = node_vtable_get_userdata(bus, path, p->parent, &u, error);
+        if (r <= 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        *userdata = vtable_property_convert_userdata(p->vtable, u);
+        return 1;
+}
+
+static int add_enumerated_to_set(
+                sd_bus *bus,
+                const char *prefix,
+                struct node_enumerator *first,
+                Set *s,
+                sd_bus_error *error) {
+
+        struct node_enumerator *c;
+        int r;
+
+        assert(bus);
+        assert(prefix);
+        assert(s);
+
+        LIST_FOREACH(enumerators, c, first) {
+                char **children = NULL, **k;
+
+                if (bus->nodes_modified)
+                        return 0;
+
+                r = c->callback(bus, prefix, c->userdata, &children, error);
+                if (r < 0)
+                        return r;
+                if (sd_bus_error_is_set(error))
+                        return -sd_bus_error_get_errno(error);
+
+                STRV_FOREACH(k, children) {
+                        if (r < 0) {
+                                free(*k);
+                                continue;
+                        }
+
+                        if (!object_path_is_valid(*k)){
+                                free(*k);
+                                r = -EINVAL;
+                                continue;
+                        }
+
+                        if (!object_path_startswith(*k, prefix)) {
+                                free(*k);
+                                continue;
+                        }
+
+                        r = set_consume(s, *k);
+                        if (r == -EEXIST)
+                                r = 0;
+                }
+
+                free(children);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int add_subtree_to_set(
+                sd_bus *bus,
+                const char *prefix,
+                struct node *n,
+                Set *s,
+                sd_bus_error *error) {
+
+        struct node *i;
+        int r;
+
+        assert(bus);
+        assert(prefix);
+        assert(n);
+        assert(s);
+
+        r = add_enumerated_to_set(bus, prefix, n->enumerators, s, error);
+        if (r < 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        LIST_FOREACH(siblings, i, n->child) {
+                char *t;
+
+                if (!object_path_startswith(i->path, prefix))
+                        continue;
+
+                t = strdup(i->path);
+                if (!t)
+                        return -ENOMEM;
+
+                r = set_consume(s, t);
+                if (r < 0 && r != -EEXIST)
+                        return r;
+
+                r = add_subtree_to_set(bus, prefix, i, s, error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        return 0;
+}
+
+static int get_child_nodes(
+                sd_bus *bus,
+                const char *prefix,
+                struct node *n,
+                Set **_s,
+                sd_bus_error *error) {
+
+        Set *s = NULL;
+        int r;
+
+        assert(bus);
+        assert(prefix);
+        assert(n);
+        assert(_s);
+
+        s = set_new(string_hash_func, string_compare_func);
+        if (!s)
+                return -ENOMEM;
+
+        r = add_subtree_to_set(bus, prefix, n, s, error);
+        if (r < 0) {
+                set_free_free(s);
+                return r;
+        }
+
+        *_s = s;
+        return 0;
+}
+
+static int node_callbacks_run(
+                sd_bus *bus,
+                sd_bus_message *m,
+                struct node_callback *first,
+                bool require_fallback,
+                bool *found_object) {
+
+        struct node_callback *c;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(found_object);
+
+        LIST_FOREACH(callbacks, c, first) {
+                _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+
+                if (bus->nodes_modified)
+                        return 0;
+
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                *found_object = true;
+
+                if (c->last_iteration == bus->iteration_counter)
+                        continue;
+
+                c->last_iteration = bus->iteration_counter;
+
+                r = sd_bus_message_rewind(m, true);
+                if (r < 0)
+                        return r;
+
+                r = c->callback(bus, m, c->userdata, &error_buffer);
+                r = bus_maybe_reply_error(m, r, &error_buffer);
+                if (r != 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+#define CAPABILITY_SHIFT(x) (((x) >> __builtin_ctzll(_SD_BUS_VTABLE_CAPABILITY_MASK)) & 0xFFFF)
+
+static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        uint64_t cap;
+        uid_t uid;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(c);
+
+        /* If the entire bus is trusted let's grant access */
+        if (bus->trusted)
+                return 0;
+
+        /* If the member is marked UNPRIVILEGED let's grant access */
+        if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED)
+                return 0;
+
+        /* If we are not connected to kdbus we cannot retrieve the
+         * effective capability set without race. Since we need this
+         * for a security decision we cannot use racy data, hence
+         * don't request it. */
+        if (bus->is_kernel)
+                r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
+        else
+                r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        /* Check have the caller has the requested capability
+         * set. Note that the flags value contains the capability
+         * number plus one, which we need to subtract here. We do this
+         * so that we have 0 as special value for "default
+         * capability". */
+        cap = CAPABILITY_SHIFT(c->vtable->flags);
+        if (cap == 0)
+                cap = CAPABILITY_SHIFT(c->parent->vtable[0].flags);
+        if (cap == 0)
+                cap = CAP_SYS_ADMIN;
+        else
+                cap --;
+
+        r = sd_bus_creds_has_effective_cap(creds, cap);
+        if (r > 0)
+                return 1;
+
+        /* Caller has same UID as us, then let's grant access */
+        r = sd_bus_creds_get_uid(creds, &uid);
+        if (r >= 0) {
+                if (uid == getuid())
+                        return 1;
+        }
+
+        return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member);
+}
+
+static int method_callbacks_run(
+                sd_bus *bus,
+                sd_bus_message *m,
+                struct vtable_member *c,
+                bool require_fallback,
+                bool *found_object) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *signature;
+        void *u;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(c);
+        assert(found_object);
+
+        if (require_fallback && !c->parent->is_fallback)
+                return 0;
+
+        r = check_access(bus, m, c, &error);
+        if (r < 0)
+                return bus_maybe_reply_error(m, r, &error);
+
+        r = node_vtable_get_userdata(bus, m->path, c->parent, &u, &error);
+        if (r <= 0)
+                return bus_maybe_reply_error(m, r, &error);
+        if (bus->nodes_modified)
+                return 0;
+
+        *found_object = true;
+
+        if (c->last_iteration == bus->iteration_counter)
+                return 0;
+
+        c->last_iteration = bus->iteration_counter;
+
+        r = sd_bus_message_rewind(m, true);
+        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))
+                return sd_bus_reply_method_errorf(
+                                m,
+                                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));
+
+        /* Keep track what the signature of the reply to this message
+         * should be, so that this can be enforced when sealing the
+         * reply. */
+        m->enforced_reply_signature = strempty(c->vtable->x.method.result);
+
+        if (c->vtable->x.method.handler) {
+                r = c->vtable->x.method.handler(bus, m, u, &error);
+                return bus_maybe_reply_error(m, r, &error);
+        }
+
+        /* If the method callback is NULL, make this a successful NOP */
+        r = sd_bus_reply_method_return(m, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int invoke_property_get(
+                sd_bus *bus,
+                const sd_bus_vtable *v,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        const void *p;
+        int r;
+
+        assert(bus);
+        assert(v);
+        assert(path);
+        assert(interface);
+        assert(property);
+        assert(reply);
+
+        if (v->x.property.get) {
+                r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
+                if (r < 0)
+                        return r;
+                if (sd_bus_error_is_set(error))
+                        return -sd_bus_error_get_errno(error);
+                return r;
+        }
+
+        /* Automatic handling if no callback is defined. */
+
+        if (streq(v->x.property.signature, "as"))
+                return sd_bus_message_append_strv(reply, *(char***) userdata);
+
+        assert(signature_is_single(v->x.property.signature, false));
+        assert(bus_type_is_basic(v->x.property.signature[0]));
+
+        switch (v->x.property.signature[0]) {
+
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_SIGNATURE:
+                p = strempty(*(char**) userdata);
+                break;
+
+        case SD_BUS_TYPE_OBJECT_PATH:
+                p = *(char**) userdata;
+                assert(p);
+                break;
+
+        default:
+                p = userdata;
+                break;
+        }
+
+        return sd_bus_message_append_basic(reply, v->x.property.signature[0], p);
+}
+
+static int invoke_property_set(
+                sd_bus *bus,
+                const sd_bus_vtable *v,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                void *userdata,
+                sd_bus_error *error) {
+
+        int r;
+
+        assert(bus);
+        assert(v);
+        assert(path);
+        assert(interface);
+        assert(property);
+        assert(value);
+
+        if (v->x.property.set) {
+                r = v->x.property.set(bus, path, interface, property, value, userdata, error);
+                if (r < 0)
+                        return r;
+                if (sd_bus_error_is_set(error))
+                        return -sd_bus_error_get_errno(error);
+                return r;
+        }
+
+        /*  Automatic handling if no callback is defined. */
+
+        assert(signature_is_single(v->x.property.signature, false));
+        assert(bus_type_is_basic(v->x.property.signature[0]));
+
+        switch (v->x.property.signature[0]) {
+
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_OBJECT_PATH:
+        case SD_BUS_TYPE_SIGNATURE: {
+                const char *p;
+                char *n;
+
+                r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p);
+                if (r < 0)
+                        return r;
+
+                n = strdup(p);
+                if (!n)
+                        return -ENOMEM;
+
+                free(*(char**) userdata);
+                *(char**) userdata = n;
+
+                break;
+        }
+
+        default:
+                r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata);
+                if (r < 0)
+                        return r;
+
+                break;
+        }
+
+        return 1;
+}
+
+static int property_get_set_callbacks_run(
+                sd_bus *bus,
+                sd_bus_message *m,
+                struct vtable_member *c,
+                bool require_fallback,
+                bool is_get,
+                bool *found_object) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        void *u;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(c);
+        assert(found_object);
+
+        if (require_fallback && !c->parent->is_fallback)
+                return 0;
+
+        r = vtable_property_get_userdata(bus, m->path, c, &u, &error);
+        if (r <= 0)
+                return bus_maybe_reply_error(m, r, &error);
+        if (bus->nodes_modified)
+                return 0;
+
+        *found_object = true;
+
+        r = sd_bus_message_new_method_return(m, &reply);
+        if (r < 0)
+                return r;
+
+        if (is_get) {
+                /* Note that we do not protect against reexecution
+                 * here (using the last_iteration check, see below),
+                 * should the node tree have changed and we got called
+                 * again. We assume that property Get() calls are
+                 * ultimately without side-effects or if they aren't
+                 * then at least idempotent. */
+
+                r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature);
+                if (r < 0)
+                        return r;
+
+                /* Note that we do not do an access check here. Read
+                 * access to properties is always unrestricted, since
+                 * PropertiesChanged signals broadcast contents
+                 * anyway. */
+
+                r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, u, &error);
+                if (r < 0)
+                        return bus_maybe_reply_error(m, r, &error);
+
+                if (bus->nodes_modified)
+                        return 0;
+
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
+
+        } else {
+                if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+                        return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
+
+                /* Avoid that we call the set routine more than once
+                 * if the processing of this message got restarted
+                 * because the node tree changed. */
+                if (c->last_iteration == bus->iteration_counter)
+                        return 0;
+
+                c->last_iteration = bus->iteration_counter;
+
+                r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
+                if (r < 0)
+                        return r;
+
+                r = check_access(bus, m, c, &error);
+                if (r < 0)
+                        return bus_maybe_reply_error(m, r, &error);
+
+                r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, u, &error);
+                if (r < 0)
+                        return bus_maybe_reply_error(m, r, &error);
+
+                if (bus->nodes_modified)
+                        return 0;
+
+                r = sd_bus_message_exit_container(m);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_send(bus, reply, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int vtable_append_one_property(
+                sd_bus *bus,
+                sd_bus_message *reply,
+                const char *path,
+                struct node_vtable *c,
+                const sd_bus_vtable *v,
+                void *userdata,
+                sd_bus_error *error) {
+
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(path);
+        assert(c);
+        assert(v);
+
+        r = sd_bus_message_open_container(reply, 'e', "sv");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(reply, "s", v->x.property.member);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
+        if (r < 0)
+                return r;
+
+        r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
+        if (r < 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int vtable_append_all_properties(
+                sd_bus *bus,
+                sd_bus_message *reply,
+                const char *path,
+                struct node_vtable *c,
+                void *userdata,
+                sd_bus_error *error) {
+
+        const sd_bus_vtable *v;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(path);
+        assert(c);
+
+        if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
+                return 1;
+
+        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+                if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+                        continue;
+
+                if (v->flags & SD_BUS_VTABLE_HIDDEN)
+                        continue;
+
+                r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        return 1;
+}
+
+static int property_get_all_callbacks_run(
+                sd_bus *bus,
+                sd_bus_message *m,
+                struct node_vtable *first,
+                bool require_fallback,
+                const char *iface,
+                bool *found_object) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        struct node_vtable *c;
+        bool found_interface;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(found_object);
+
+        r = sd_bus_message_new_method_return(m, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "{sv}");
+        if (r < 0)
+                return r;
+
+        found_interface = !iface ||
+                streq(iface, "org.freedesktop.DBus.Properties") ||
+                streq(iface, "org.freedesktop.DBus.Peer") ||
+                streq(iface, "org.freedesktop.DBus.Introspectable");
+
+        LIST_FOREACH(vtables, c, first) {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                void *u;
+
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
+                if (r < 0)
+                        return bus_maybe_reply_error(m, r, &error);
+                if (bus->nodes_modified)
+                        return 0;
+                if (r == 0)
+                        continue;
+
+                *found_object = true;
+
+                if (iface && !streq(c->interface, iface))
+                        continue;
+                found_interface = true;
+
+                r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
+                if (r < 0)
+                        return bus_maybe_reply_error(m, r, &error);
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        if (!found_interface) {
+                r = sd_bus_reply_method_errorf(
+                                m,
+                                SD_BUS_ERROR_UNKNOWN_INTERFACE,
+                                "Unknown interface '%s'.", iface);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_send(bus, reply, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
+        assert(bus);
+        assert(n);
+
+        if (n->object_manager)
+                return true;
+
+        if (n->parent)
+                return bus_node_with_object_manager(bus, n->parent);
+
+        return false;
+}
+
+static bool bus_node_exists(
+                sd_bus *bus,
+                struct node *n,
+                const char *path,
+                bool require_fallback) {
+
+        struct node_vtable *c;
+        struct node_callback *k;
+
+        assert(bus);
+        assert(n);
+        assert(path);
+
+        /* Tests if there's anything attached directly to this node
+         * for the specified path */
+
+        LIST_FOREACH(callbacks, k, n->callbacks) {
+                if (require_fallback && !k->is_fallback)
+                        continue;
+
+                return true;
+        }
+
+        LIST_FOREACH(vtables, c, n->vtables) {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                if (node_vtable_get_userdata(bus, path, c, NULL, &error) > 0)
+                        return true;
+                if (bus->nodes_modified)
+                        return false;
+        }
+
+        return !require_fallback && (n->enumerators || n->object_manager);
+}
+
+static int process_introspect(
+                sd_bus *bus,
+                sd_bus_message *m,
+                struct node *n,
+                bool require_fallback,
+                bool *found_object) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_set_free_free_ Set *s = NULL;
+        const char *previous_interface = NULL;
+        struct introspect intro;
+        struct node_vtable *c;
+        bool empty;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(n);
+        assert(found_object);
+
+        r = get_child_nodes(bus, m->path, n, &s, &error);
+        if (r < 0)
+                return bus_maybe_reply_error(m, r, &error);
+        if (bus->nodes_modified)
+                return 0;
+
+        r = introspect_begin(&intro, bus->trusted);
+        if (r < 0)
+                return r;
+
+        r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
+        if (r < 0)
+                return r;
+
+        empty = set_isempty(s);
+
+        LIST_FOREACH(vtables, c, n->vtables) {
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
+                if (r < 0) {
+                        r = bus_maybe_reply_error(m, r, &error);
+                        goto finish;
+                }
+                if (bus->nodes_modified) {
+                        r = 0;
+                        goto finish;
+                }
+                if (r == 0)
+                        continue;
+
+                empty = false;
+
+                if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
+                        continue;
+
+                if (!streq_ptr(previous_interface, c->interface)) {
+
+                        if (previous_interface)
+                                fputs(" </interface>\n", intro.f);
+
+                        fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
+                }
+
+                r = introspect_write_interface(&intro, c->vtable);
+                if (r < 0)
+                        goto finish;
+
+                previous_interface = c->interface;
+        }
+
+        if (previous_interface)
+                fputs(" </interface>\n", intro.f);
+
+        if (empty) {
+                /* Nothing?, let's see if we exist at all, and if not
+                 * refuse to do anything */
+                r = bus_node_exists(bus, n, m->path, require_fallback);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+                if (r == 0)
+                        goto finish;
+        }
+
+        *found_object = true;
+
+        r = introspect_write_child_nodes(&intro, s, m->path);
+        if (r < 0)
+                goto finish;
+
+        r = introspect_finish(&intro, bus, m, &reply);
+        if (r < 0)
+                goto finish;
+
+        r = sd_bus_send(bus, reply, NULL);
+        if (r < 0)
+                goto finish;
+
+        r = 1;
+
+finish:
+        introspect_free(&intro);
+        return r;
+}
+
+static int object_manager_serialize_path(
+                sd_bus *bus,
+                sd_bus_message *reply,
+                const char *prefix,
+                const char *path,
+                bool require_fallback,
+                sd_bus_error *error) {
+
+        const char *previous_interface = NULL;
+        bool found_something = false;
+        struct node_vtable *i;
+        struct node *n;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(prefix);
+        assert(path);
+        assert(error);
+
+        n = hashmap_get(bus->nodes, prefix);
+        if (!n)
+                return 0;
+
+        LIST_FOREACH(vtables, i, n->vtables) {
+                void *u;
+
+                if (require_fallback && !i->is_fallback)
+                        continue;
+
+                r = node_vtable_get_userdata(bus, path, i, &u, error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+                if (r == 0)
+                        continue;
+
+                if (!found_something) {
+
+                        /* Open the object part */
+
+                        r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_append(reply, "o", path);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
+                        if (r < 0)
+                                return r;
+
+                        found_something = true;
+                }
+
+                if (!streq_ptr(previous_interface, i->interface)) {
+
+                        /* Maybe close the previous interface part */
+
+                        if (previous_interface) {
+                                r = sd_bus_message_close_container(reply);
+                                if (r < 0)
+                                        return r;
+
+                                r = sd_bus_message_close_container(reply);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        /* Open the new interface part */
+
+                        r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_append(reply, "s", i->interface);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_open_container(reply, 'a', "{sv}");
+                        if (r < 0)
+                                return r;
+                }
+
+                r = vtable_append_all_properties(bus, reply, path, i, u, error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+
+                previous_interface = i->interface;
+        }
+
+        if (previous_interface) {
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
+        }
+
+        if (found_something) {
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
+        }
+
+        return 1;
+}
+
+static int object_manager_serialize_path_and_fallbacks(
+                sd_bus *bus,
+                sd_bus_message *reply,
+                const char *path,
+                sd_bus_error *error) {
+
+        char *prefix;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(path);
+        assert(error);
+
+        /* First, add all vtables registered for this path */
+        r = object_manager_serialize_path(bus, reply, path, path, false, error);
+        if (r < 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        /* Second, add fallback vtables registered for any of the prefixes */
+        prefix = alloca(strlen(path) + 1);
+        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        return 0;
+}
+
+static int process_get_managed_objects(
+                sd_bus *bus,
+                sd_bus_message *m,
+                struct node *n,
+                bool require_fallback,
+                bool *found_object) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_set_free_free_ Set *s = NULL;
+        bool empty;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(n);
+        assert(found_object);
+
+        if (!bus_node_with_object_manager(bus, n))
+                return 0;
+
+        r = get_child_nodes(bus, m->path, n, &s, &error);
+        if (r < 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        r = sd_bus_message_new_method_return(m, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
+        if (r < 0)
+                return r;
+
+        empty = set_isempty(s);
+        if (empty) {
+                struct node_vtable *c;
+
+                /* Hmm, so we have no children? Then let's check
+                 * whether we exist at all, i.e. whether at least one
+                 * vtable exists. */
+
+                LIST_FOREACH(vtables, c, n->vtables) {
+
+                        if (require_fallback && !c->is_fallback)
+                                continue;
+
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                continue;
+
+                        empty = false;
+                        break;
+                }
+
+                if (empty)
+                        return 0;
+        } else {
+                Iterator i;
+                char *path;
+
+                SET_FOREACH(path, s, i) {
+                        r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
+                        if (r < 0)
+                                return r;
+
+                        if (bus->nodes_modified)
+                                return 0;
+                }
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_send(bus, reply, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int object_find_and_run(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *p,
+                bool require_fallback,
+                bool *found_object) {
+
+        struct node *n;
+        struct vtable_member vtable_key, *v;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(p);
+        assert(found_object);
+
+        n = hashmap_get(bus->nodes, p);
+        if (!n)
+                return 0;
+
+        /* First, try object callbacks */
+        r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
+        if (r != 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        if (!m->interface || !m->member)
+                return 0;
+
+        /* Then, look for a known method */
+        vtable_key.path = (char*) p;
+        vtable_key.interface = m->interface;
+        vtable_key.member = m->member;
+
+        v = hashmap_get(bus->vtable_methods, &vtable_key);
+        if (v) {
+                r = method_callbacks_run(bus, m, v, require_fallback, found_object);
+                if (r != 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        /* Then, look for a known property */
+        if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
+                bool get = false;
+
+                get = streq(m->member, "Get");
+
+                if (get || streq(m->member, "Set")) {
+
+                        r = sd_bus_message_rewind(m, true);
+                        if (r < 0)
+                                return r;
+
+                        vtable_key.path = (char*) p;
+
+                        r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
+                        if (r < 0)
+                                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
+
+                        v = hashmap_get(bus->vtable_properties, &vtable_key);
+                        if (v) {
+                                r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
+                                if (r != 0)
+                                        return r;
+                        }
+
+                } else if (streq(m->member, "GetAll")) {
+                        const char *iface;
+
+                        r = sd_bus_message_rewind(m, true);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_read(m, "s", &iface);
+                        if (r < 0)
+                                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
+
+                        if (iface[0] == 0)
+                                iface = NULL;
+
+                        r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
+                        if (r != 0)
+                                return r;
+                }
+
+        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+
+                if (!isempty(sd_bus_message_get_signature(m, true)))
+                        return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
+
+                r = process_introspect(bus, m, n, require_fallback, found_object);
+                if (r != 0)
+                        return r;
+
+        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
+
+                if (!isempty(sd_bus_message_get_signature(m, true)))
+                        return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
+
+                r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
+                if (r != 0)
+                        return r;
+        }
+
+        if (bus->nodes_modified)
+                return 0;
+
+        if (!*found_object) {
+                r = bus_node_exists(bus, n, m->path, require_fallback);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        *found_object = true;
+        }
+
+        return 0;
+}
+
+int bus_process_object(sd_bus *bus, sd_bus_message *m) {
+        int r;
+        size_t pl;
+        bool found_object = false;
+
+        assert(bus);
+        assert(m);
+
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
+                return 0;
+
+        if (hashmap_isempty(bus->nodes))
+                return 0;
+
+        /* Never respond to broadcast messages */
+        if (bus->bus_client && !m->destination)
+                return 0;
+
+        assert(m->path);
+        assert(m->member);
+
+        pl = strlen(m->path);
+        do {
+                char prefix[pl+1];
+
+                bus->nodes_modified = false;
+
+                r = object_find_and_run(bus, m, m->path, false, &found_object);
+                if (r != 0)
+                        return r;
+
+                /* Look for fallback prefixes */
+                OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
+
+                        if (bus->nodes_modified)
+                                break;
+
+                        r = object_find_and_run(bus, m, prefix, true, &found_object);
+                        if (r != 0)
+                                return r;
+                }
+
+        } while (bus->nodes_modified);
+
+        if (!found_object)
+                return 0;
+
+        if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
+            sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
+                r = sd_bus_reply_method_errorf(
+                                m,
+                                SD_BUS_ERROR_UNKNOWN_PROPERTY,
+                                "Unknown property or interface.");
+        else
+                r = sd_bus_reply_method_errorf(
+                                m,
+                                SD_BUS_ERROR_UNKNOWN_METHOD,
+                                "Unknown method '%s' or interface '%s'.", m->member, m->interface);
+
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
+        struct node *n, *parent;
+        const char *e;
+        _cleanup_free_ char *s = NULL;
+        char *p;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(path[0] == '/');
+
+        n = hashmap_get(bus->nodes, path);
+        if (n)
+                return n;
+
+        r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func);
+        if (r < 0)
+                return NULL;
+
+        s = strdup(path);
+        if (!s)
+                return NULL;
+
+        if (streq(path, "/"))
+                parent = NULL;
+        else {
+                e = strrchr(path, '/');
+                assert(e);
+
+                p = strndupa(path, MAX(1, path - e));
+
+                parent = bus_node_allocate(bus, p);
+                if (!parent)
+                        return NULL;
+        }
+
+        n = new0(struct node, 1);
+        if (!n)
+                return NULL;
+
+        n->parent = parent;
+        n->path = s;
+        s = NULL; /* do not free */
+
+        r = hashmap_put(bus->nodes, n->path, n);
+        if (r < 0) {
+                free(n->path);
+                free(n);
+                return NULL;
+        }
+
+        if (parent)
+                LIST_PREPEND(siblings, parent->child, n);
+
+        return n;
+}
+
+static void bus_node_gc(sd_bus *b, struct node *n) {
+        assert(b);
+
+        if (!n)
+                return;
+
+        if (n->child ||
+            n->callbacks ||
+            n->vtables ||
+            n->enumerators ||
+            n->object_manager)
+                return;
+
+        assert(hashmap_remove(b->nodes, n->path) == n);
+
+        if (n->parent)
+                LIST_REMOVE(siblings, n->parent->child, n);
+
+        free(n->path);
+        bus_node_gc(b, n->parent);
+        free(n);
+}
+
+static int bus_add_object(
+                sd_bus *bus,
+                bool fallback,
+                const char *path,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
+
+        struct node_callback *c;
+        struct node *n;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = bus_node_allocate(bus, path);
+        if (!n)
+                return -ENOMEM;
+
+        c = new0(struct node_callback, 1);
+        if (!c) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        c->node = n;
+        c->callback = callback;
+        c->userdata = userdata;
+        c->is_fallback = fallback;
+
+        LIST_PREPEND(callbacks, n->callbacks, c);
+        bus->nodes_modified = true;
+
+        return 0;
+
+fail:
+        free(c);
+        bus_node_gc(bus, n);
+        return r;
+}
+
+static int bus_remove_object(
+                sd_bus *bus,
+                bool fallback,
+                const char *path,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
+
+        struct node_callback *c;
+        struct node *n;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = hashmap_get(bus->nodes, path);
+        if (!n)
+                return 0;
+
+        LIST_FOREACH(callbacks, c, n->callbacks)
+                if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
+                        break;
+        if (!c)
+                return 0;
+
+        LIST_REMOVE(callbacks, n->callbacks, c);
+        free(c);
+
+        bus_node_gc(bus, n);
+        bus->nodes_modified = true;
+
+        return 1;
+}
+
+_public_ int sd_bus_add_object(sd_bus *bus,
+                               const char *path,
+                               sd_bus_message_handler_t callback,
+                               void *userdata) {
+
+        return bus_add_object(bus, false, path, callback, userdata);
+}
+
+_public_ int sd_bus_remove_object(sd_bus *bus,
+                                  const char *path,
+                                  sd_bus_message_handler_t callback,
+                                  void *userdata) {
+
+        return bus_remove_object(bus, false, path, callback, userdata);
+}
+
+_public_ int sd_bus_add_fallback(sd_bus *bus,
+                                 const char *prefix,
+                                 sd_bus_message_handler_t callback,
+                                 void *userdata) {
+
+        return bus_add_object(bus, true, prefix, callback, userdata);
+}
+
+_public_ int sd_bus_remove_fallback(sd_bus *bus,
+                                    const char *prefix,
+                                    sd_bus_message_handler_t callback,
+                                    void *userdata) {
+
+        return bus_remove_object(bus, true, prefix, callback, userdata);
+}
+
+static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
+        assert(bus);
+
+        if (!w)
+                return;
+
+        if (w->interface && w->node && w->vtable) {
+                const sd_bus_vtable *v;
+
+                for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
+                        struct vtable_member *x = NULL;
+
+                        switch (v->type) {
+
+                        case _SD_BUS_VTABLE_METHOD: {
+                                struct vtable_member key;
+
+                                key.path = w->node->path;
+                                key.interface = w->interface;
+                                key.member = v->x.method.member;
+
+                                x = hashmap_remove(bus->vtable_methods, &key);
+                                break;
+                        }
+
+                        case _SD_BUS_VTABLE_PROPERTY:
+                        case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
+                                struct vtable_member key;
+
+                                key.path = w->node->path;
+                                key.interface = w->interface;
+                                key.member = v->x.property.member;
+                                x = hashmap_remove(bus->vtable_properties, &key);
+                                break;
+                        }}
+
+                        free(x);
+                }
+        }
+
+        free(w->interface);
+        free(w);
+}
+
+static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
+        const struct vtable_member *m = a;
+        uint8_t hash_key2[HASH_KEY_SIZE];
+        unsigned long ret;
+
+        assert(m);
+
+        ret = string_hash_func(m->path, hash_key);
+
+        /* Use a slightly different hash key for the interface */
+        memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
+        hash_key2[0]++;
+        ret ^= string_hash_func(m->interface, hash_key2);
+
+        /* And an even different one for the  member */
+        hash_key2[0]++;
+        ret ^= string_hash_func(m->member, hash_key2);
+
+        return ret;
+}
+
+static int vtable_member_compare_func(const void *a, const void *b) {
+        const struct vtable_member *x = a, *y = b;
+        int r;
+
+        assert(x);
+        assert(y);
+
+        r = strcmp(x->path, y->path);
+        if (r != 0)
+                return r;
+
+        r = strcmp(x->interface, y->interface);
+        if (r != 0)
+                return r;
+
+        return strcmp(x->member, y->member);
+}
+
+static int add_object_vtable_internal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const sd_bus_vtable *vtable,
+                bool fallback,
+                sd_bus_object_find_t find,
+                void *userdata) {
+
+        struct node_vtable *c = NULL, *i, *existing = NULL;
+        const sd_bus_vtable *v;
+        struct node *n;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(interface_name_is_valid(interface), -EINVAL);
+        assert_return(vtable, -EINVAL);
+        assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
+        assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
+                      !streq(interface, "org.freedesktop.DBus.Introspectable") &&
+                      !streq(interface, "org.freedesktop.DBus.Peer") &&
+                      !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
+
+        r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
+        if (r < 0)
+                return r;
+
+        r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func);
+        if (r < 0)
+                return r;
+
+        n = bus_node_allocate(bus, path);
+        if (!n)
+                return -ENOMEM;
+
+        LIST_FOREACH(vtables, i, n->vtables) {
+                if (i->is_fallback != fallback) {
+                        r = -EPROTOTYPE;
+                        goto fail;
+                }
+
+                if (streq(i->interface, interface)) {
+
+                        if (i->vtable == vtable) {
+                                r = -EEXIST;
+                                goto fail;
+                        }
+
+                        existing = i;
+                }
+        }
+
+        c = new0(struct node_vtable, 1);
+        if (!c) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        c->node = n;
+        c->is_fallback = fallback;
+        c->vtable = vtable;
+        c->userdata = userdata;
+        c->find = find;
+
+        c->interface = strdup(interface);
+        if (!c->interface) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+
+                switch (v->type) {
+
+                case _SD_BUS_VTABLE_METHOD: {
+                        struct vtable_member *m;
+
+                        if (!member_name_is_valid(v->x.method.member) ||
+                            !signature_is_valid(strempty(v->x.method.signature), false) ||
+                            !signature_is_valid(strempty(v->x.method.result), false) ||
+                            !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
+                            v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
+                                r = -EINVAL;
+                                goto fail;
+                        }
+
+                        m = new0(struct vtable_member, 1);
+                        if (!m) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        m->parent = c;
+                        m->path = n->path;
+                        m->interface = c->interface;
+                        m->member = v->x.method.member;
+                        m->vtable = v;
+
+                        r = hashmap_put(bus->vtable_methods, m, m);
+                        if (r < 0) {
+                                free(m);
+                                goto fail;
+                        }
+
+                        break;
+                }
+
+                case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
+
+                        if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
+                                r = -EINVAL;
+                                goto fail;
+                        }
+
+                        /* Fall through */
+
+                case _SD_BUS_VTABLE_PROPERTY: {
+                        struct vtable_member *m;
+
+                        if (!member_name_is_valid(v->x.property.member) ||
+                            !signature_is_single(v->x.property.signature, false) ||
+                            !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
+                            v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
+                            (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
+                            (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
+                                r = -EINVAL;
+                                goto fail;
+                        }
+
+                        m = new0(struct vtable_member, 1);
+                        if (!m) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        m->parent = c;
+                        m->path = n->path;
+                        m->interface = c->interface;
+                        m->member = v->x.property.member;
+                        m->vtable = v;
+
+                        r = hashmap_put(bus->vtable_properties, m, m);
+                        if (r < 0) {
+                                free(m);
+                                goto fail;
+                        }
+
+                        break;
+                }
+
+                case _SD_BUS_VTABLE_SIGNAL:
+
+                        if (!member_name_is_valid(v->x.signal.member) ||
+                            !signature_is_valid(strempty(v->x.signal.signature), false) ||
+                            v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
+                                r = -EINVAL;
+                                goto fail;
+                        }
+
+                        break;
+
+                default:
+                        r = -EINVAL;
+                        goto fail;
+                }
+        }
+
+        LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
+        bus->nodes_modified = true;
+
+        return 0;
+
+fail:
+        if (c)
+                free_node_vtable(bus, c);
+
+        bus_node_gc(bus, n);
+        return r;
+}
+
+static int remove_object_vtable_internal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const sd_bus_vtable *vtable,
+                bool fallback,
+                sd_bus_object_find_t find,
+                void *userdata) {
+
+        struct node_vtable *c;
+        struct node *n;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(interface_name_is_valid(interface), -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = hashmap_get(bus->nodes, path);
+        if (!n)
+                return 0;
+
+        LIST_FOREACH(vtables, c, n->vtables)
+                if (streq(c->interface, interface) &&
+                    c->is_fallback == fallback &&
+                    c->vtable == vtable &&
+                    c->find == find &&
+                    c->userdata == userdata)
+                        break;
+
+        if (!c)
+                return 0;
+
+        LIST_REMOVE(vtables, n->vtables, c);
+
+        free_node_vtable(bus, c);
+        bus_node_gc(bus, n);
+
+        bus->nodes_modified = true;
+
+        return 1;
+}
+
+_public_ int sd_bus_add_object_vtable(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const sd_bus_vtable *vtable,
+                void *userdata) {
+
+        return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
+}
+
+_public_ int sd_bus_remove_object_vtable(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const sd_bus_vtable *vtable,
+                void *userdata) {
+
+        return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
+}
+
+_public_ int sd_bus_add_fallback_vtable(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const sd_bus_vtable *vtable,
+                sd_bus_object_find_t find,
+                void *userdata) {
+
+        return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
+}
+
+_public_ int sd_bus_remove_fallback_vtable(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const sd_bus_vtable *vtable,
+                sd_bus_object_find_t find,
+                void *userdata) {
+
+        return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
+}
+
+_public_ int sd_bus_add_node_enumerator(
+                sd_bus *bus,
+                const char *path,
+                sd_bus_node_enumerator_t callback,
+                void *userdata) {
+
+        struct node_enumerator *c;
+        struct node *n;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = bus_node_allocate(bus, path);
+        if (!n)
+                return -ENOMEM;
+
+        c = new0(struct node_enumerator, 1);
+        if (!c) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        c->node = n;
+        c->callback = callback;
+        c->userdata = userdata;
+
+        LIST_PREPEND(enumerators, n->enumerators, c);
+
+        bus->nodes_modified = true;
+
+        return 0;
+
+fail:
+        free(c);
+        bus_node_gc(bus, n);
+        return r;
+}
+
+_public_ int sd_bus_remove_node_enumerator(
+                sd_bus *bus,
+                const char *path,
+                sd_bus_node_enumerator_t callback,
+                void *userdata) {
+
+        struct node_enumerator *c;
+        struct node *n;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = hashmap_get(bus->nodes, path);
+        if (!n)
+                return 0;
+
+        LIST_FOREACH(enumerators, c, n->enumerators)
+                if (c->callback == callback && c->userdata == userdata)
+                        break;
+
+        if (!c)
+                return 0;
+
+        LIST_REMOVE(enumerators, n->enumerators, c);
+        free(c);
+
+        bus_node_gc(bus, n);
+
+        bus->nodes_modified = true;
+
+        return 1;
+}
+
+static int emit_properties_changed_on_interface(
+                sd_bus *bus,
+                const char *prefix,
+                const char *path,
+                const char *interface,
+                bool require_fallback,
+                bool *found_interface,
+                char **names) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        bool has_invalidating = false, has_changing = false;
+        struct vtable_member key = {};
+        struct node_vtable *c;
+        struct node *n;
+        char **property;
+        void *u = NULL;
+        int r;
+
+        assert(bus);
+        assert(prefix);
+        assert(path);
+        assert(interface);
+        assert(found_interface);
+
+        n = hashmap_get(bus->nodes, prefix);
+        if (!n)
+                return 0;
+
+        r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(m, "s", interface);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(m, 'a', "{sv}");
+        if (r < 0)
+                return r;
+
+        key.path = prefix;
+        key.interface = interface;
+
+        LIST_FOREACH(vtables, c, n->vtables) {
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                if (!streq(c->interface, interface))
+                        continue;
+
+                r = node_vtable_get_userdata(bus, path, c, &u, &error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+                if (r == 0)
+                        continue;
+
+                *found_interface = true;
+
+                if (names) {
+                        /* If the caller specified a list of
+                         * properties we include exactly those in the
+                         * PropertiesChanged message */
+
+                        STRV_FOREACH(property, names) {
+                                struct vtable_member *v;
+
+                                assert_return(member_name_is_valid(*property), -EINVAL);
+
+                                key.member = *property;
+                                v = hashmap_get(bus->vtable_properties, &key);
+                                if (!v)
+                                        return -ENOENT;
+
+                                /* If there are two vtables for the same
+                                 * interface, let's handle this property when
+                                 * we come to that vtable. */
+                                if (c != v->parent)
+                                        continue;
+
+                                assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
+                                              v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
+
+                                assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
+
+                                if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
+                                        has_invalidating = true;
+                                        continue;
+                                }
+
+                                has_changing = true;
+
+                                r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
+                                if (r < 0)
+                                        return r;
+                                if (bus->nodes_modified)
+                                        return 0;
+                        }
+                } else {
+                        const sd_bus_vtable *v;
+
+                        /* If the caller specified no properties list
+                         * we include all properties that are marked
+                         * as changing in the message. */
+
+                        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+                                if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+                                        continue;
+
+                                if (v->flags & SD_BUS_VTABLE_HIDDEN)
+                                        continue;
+
+                                if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
+                                        has_invalidating = true;
+                                        continue;
+                                }
+
+                                if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
+                                        continue;
+
+                                has_changing = true;
+
+                                r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
+                                if (r < 0)
+                                        return r;
+                                if (bus->nodes_modified)
+                                        return 0;
+                        }
+                }
+        }
+
+        if (!has_invalidating && !has_changing)
+                return 0;
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(m, 'a', "s");
+        if (r < 0)
+                return r;
+
+        if (has_invalidating) {
+                LIST_FOREACH(vtables, c, n->vtables) {
+                        if (require_fallback && !c->is_fallback)
+                                continue;
+
+                        if (!streq(c->interface, interface))
+                                continue;
+
+                        r = node_vtable_get_userdata(bus, path, c, &u, &error);
+                        if (r < 0)
+                                return r;
+                        if (bus->nodes_modified)
+                                return 0;
+                        if (r == 0)
+                                continue;
+
+                        if (names) {
+                                STRV_FOREACH(property, names) {
+                                        struct vtable_member *v;
+
+                                        key.member = *property;
+                                        assert_se(v = hashmap_get(bus->vtable_properties, &key));
+                                        assert(c == v->parent);
+
+                                        if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
+                                                continue;
+
+                                        r = sd_bus_message_append(m, "s", *property);
+                                        if (r < 0)
+                                                return r;
+                                }
+                        } else {
+                                const sd_bus_vtable *v;
+
+                                for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+                                        if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+                                                continue;
+
+                                        if (v->flags & SD_BUS_VTABLE_HIDDEN)
+                                                continue;
+
+                                        if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
+                                                continue;
+
+                                        r = sd_bus_message_append(m, "s", v->x.property.member);
+                                        if (r < 0)
+                                                return r;
+                                }
+                        }
+                }
+        }
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_send(bus, m, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+_public_ int sd_bus_emit_properties_changed_strv(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                char **names) {
+
+        BUS_DONT_DESTROY(bus);
+        bool found_interface = false;
+        char *prefix;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(interface_name_is_valid(interface), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+
+        /* A non-NULL but empty names list means nothing needs to be
+           generated. A NULL list OTOH indicates that all properties
+           that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
+           included in the PropertiesChanged message. */
+        if (names && names[0] == NULL)
+                return 0;
+
+        do {
+                bus->nodes_modified = false;
+
+                r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
+                if (r != 0)
+                        return r;
+                if (bus->nodes_modified)
+                        continue;
+
+                prefix = alloca(strlen(path) + 1);
+                OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                        r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
+                        if (r != 0)
+                                return r;
+                        if (bus->nodes_modified)
+                                break;
+                }
+
+        } while (bus->nodes_modified);
+
+        return found_interface ? 0 : -ENOENT;
+}
+
+_public_ int sd_bus_emit_properties_changed(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *name, ...)  {
+
+        char **names;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(interface_name_is_valid(interface), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (!name)
+                return 0;
+
+        names = strv_from_stdarg_alloca(name);
+
+        return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
+}
+
+static int interfaces_added_append_one_prefix(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *prefix,
+                const char *path,
+                const char *interface,
+                bool require_fallback) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        bool found_interface = false;
+        struct node_vtable *c;
+        struct node *n;
+        void *u = NULL;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(prefix);
+        assert(path);
+        assert(interface);
+
+        n = hashmap_get(bus->nodes, prefix);
+        if (!n)
+                return 0;
+
+        LIST_FOREACH(vtables, c, n->vtables) {
+                if (require_fallback && !c->is_fallback)
+                        continue;
+
+                if (!streq(c->interface, interface))
+                        continue;
+
+                r = node_vtable_get_userdata(bus, path, c, &u, &error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+                if (r == 0)
+                        continue;
+
+                if (!found_interface) {
+                        r = sd_bus_message_append_basic(m, 's', interface);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_open_container(m, 'a', "{sv}");
+                        if (r < 0)
+                                return r;
+
+                        found_interface = true;
+                }
+
+                r = vtable_append_all_properties(bus, m, path, c, u, &error);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        if (found_interface) {
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return r;
+        }
+
+        return found_interface;
+}
+
+static int interfaces_added_append_one(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *path,
+                const char *interface) {
+
+        char *prefix;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(path);
+        assert(interface);
+
+        r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
+        if (r != 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        prefix = alloca(strlen(path) + 1);
+        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
+                if (r != 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }
+
+        return -ENOENT;
+}
+
+_public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
+        BUS_DONT_DESTROY(bus);
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        char **i;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (strv_isempty(interfaces))
+                return 0;
+
+        do {
+                bus->nodes_modified = false;
+
+                if (m)
+                        m = sd_bus_message_unref(m);
+
+                r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", &m);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append_basic(m, 'o', path);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
+                if (r < 0)
+                        return r;
+
+                STRV_FOREACH(i, interfaces) {
+                        assert_return(interface_name_is_valid(*i), -EINVAL);
+
+                        r = sd_bus_message_open_container(m, 'e', "sa{sv}");
+                        if (r < 0)
+                                return r;
+
+                        r = interfaces_added_append_one(bus, m, path, *i);
+                        if (r < 0)
+                                return r;
+
+                        if (bus->nodes_modified)
+                                break;
+
+                        r = sd_bus_message_close_container(m);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (bus->nodes_modified)
+                        continue;
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return r;
+
+        } while (bus->nodes_modified);
+
+        return sd_bus_send(bus, m, NULL);
+}
+
+_public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
+        char **interfaces;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        interfaces = strv_from_stdarg_alloca(interface);
+
+        return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
+}
+
+_public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (strv_isempty(interfaces))
+                return 0;
+
+        r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append_basic(m, 'o', path);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append_strv(m, interfaces);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(bus, m, NULL);
+}
+
+_public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
+        char **interfaces;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        interfaces = strv_from_stdarg_alloca(interface);
+
+        return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
+}
+
+_public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
+        struct node *n;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = bus_node_allocate(bus, path);
+        if (!n)
+                return -ENOMEM;
+
+        n->object_manager = true;
+        bus->nodes_modified = true;
+        return 0;
+}
+
+_public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
+        struct node *n;
+
+        assert_return(bus, -EINVAL);
+        assert_return(object_path_is_valid(path), -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        n = hashmap_get(bus->nodes, path);
+        if (!n)
+                return 0;
+
+        if (!n->object_manager)
+                return 0;
+
+        n->object_manager = false;
+        bus->nodes_modified = true;
+        bus_node_gc(bus, n);
+
+        return 1;
+}
diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h
new file mode 100644
index 0000000..420edd9
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-objects.h
@@ -0,0 +1,26 @@
+/*-*- 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 "bus-internal.h"
+
+int bus_process_object(sd_bus *bus, sd_bus_message *m);
diff --git a/src/libsystemd/sd-bus/bus-protocol.h b/src/libsystemd/sd-bus/bus-protocol.h
new file mode 100644
index 0000000..5046d17
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-protocol.h
@@ -0,0 +1,147 @@
+/*-*- 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/>.
+***/
+
+
+/* Endianness */
+
+enum {
+        _BUS_INVALID_ENDIAN = 0,
+        BUS_LITTLE_ENDIAN   = 'l',
+        BUS_BIG_ENDIAN      = 'B',
+#if __BYTE_ORDER == __BIG_ENDIAN
+        BUS_NATIVE_ENDIAN   = BUS_BIG_ENDIAN,
+        BUS_REVERSE_ENDIAN  = BUS_LITTLE_ENDIAN
+#else
+        BUS_NATIVE_ENDIAN   = BUS_LITTLE_ENDIAN,
+        BUS_REVERSE_ENDIAN  = BUS_BIG_ENDIAN
+#endif
+};
+
+/* Flags */
+
+enum {
+        BUS_MESSAGE_NO_REPLY_EXPECTED = 1,
+        BUS_MESSAGE_NO_AUTO_START = 2
+};
+
+/* Header fields */
+
+enum {
+        _BUS_MESSAGE_HEADER_INVALID = 0,
+        BUS_MESSAGE_HEADER_PATH,
+        BUS_MESSAGE_HEADER_INTERFACE,
+        BUS_MESSAGE_HEADER_MEMBER,
+        BUS_MESSAGE_HEADER_ERROR_NAME,
+        BUS_MESSAGE_HEADER_REPLY_SERIAL,
+        BUS_MESSAGE_HEADER_DESTINATION,
+        BUS_MESSAGE_HEADER_SENDER,
+        BUS_MESSAGE_HEADER_SIGNATURE,
+        BUS_MESSAGE_HEADER_UNIX_FDS,
+        _BUS_MESSAGE_HEADER_MAX
+};
+
+/* RequestName parameters */
+
+enum  {
+        BUS_NAME_ALLOW_REPLACEMENT = 1,
+        BUS_NAME_REPLACE_EXISTING = 2,
+        BUS_NAME_DO_NOT_QUEUE = 4
+};
+
+/* RequestName returns */
+enum  {
+        BUS_NAME_PRIMARY_OWNER = 1,
+        BUS_NAME_IN_QUEUE = 2,
+        BUS_NAME_EXISTS = 3,
+        BUS_NAME_ALREADY_OWNER = 4
+};
+
+/* ReleaseName returns */
+enum {
+        BUS_NAME_RELEASED = 1,
+        BUS_NAME_NON_EXISTENT = 2,
+        BUS_NAME_NOT_OWNER = 3,
+};
+
+/* StartServiceByName returns */
+enum {
+        BUS_START_REPLY_SUCCESS = 1,
+        BUS_START_REPLY_ALREADY_RUNNING = 2,
+};
+
+#define 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"
+
+#define BUS_INTROSPECT_INTERFACE_PEER                                \
+        " <interface name=\"org.freedesktop.DBus.Peer\">\n"             \
+        "  <method name=\"Ping\"/>\n"                                   \
+        "  <method name=\"GetMachineId\">\n"                            \
+        "   <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE                      \
+        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"   \
+        "  <method name=\"Introspect\">\n"                              \
+        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_PROPERTIES                          \
+        " <interface name=\"org.freedesktop.DBus.Properties\">\n"       \
+        "  <method name=\"Get\">\n"                                     \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
+        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetAll\">\n"                                  \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"Set\">\n"                                     \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
+        "   <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <signal name=\"PropertiesChanged\">\n"                       \
+        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
+        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
+        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
+        "  </signal>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER                      \
+        " <interface name=\"org.freedesktop.DBus.ObjectManager\">\n"    \
+        "  <method name=\"GetManagedObjects\">\n"                       \
+        "   <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <signal name=\"InterfacesAdded\">\n"                         \
+        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
+        "   <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"InterfacesRemoved\">\n"                       \
+        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
+        "   <arg type=\"as\" name=\"interfaces\"/>\n"                   \
+        "  </signal>\n"                                                 \
+        " </interface>\n"
diff --git a/src/libsystemd/sd-bus/bus-signature.c b/src/libsystemd/sd-bus/bus-signature.c
new file mode 100644
index 0000000..1e5bf48
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-signature.c
@@ -0,0 +1,160 @@
+/*-*- 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 <util.h>
+
+#include "bus-signature.h"
+#include "bus-type.h"
+
+static int signature_element_length_internal(
+                const char *s,
+                bool allow_dict_entry,
+                unsigned array_depth,
+                unsigned struct_depth,
+                size_t *l) {
+
+        int r;
+
+        if (!s)
+                return -EINVAL;
+
+        assert(l);
+
+        if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
+                *l = 1;
+                return 0;
+        }
+
+        if (*s == SD_BUS_TYPE_ARRAY) {
+                size_t t;
+
+                if (array_depth >= 32)
+                        return -EINVAL;
+
+                r = signature_element_length_internal(s + 1, true, array_depth+1, struct_depth, &t);
+                if (r < 0)
+                        return r;
+
+                *l = t + 1;
+                return 0;
+        }
+
+        if (*s == SD_BUS_TYPE_STRUCT_BEGIN) {
+                const char *p = s + 1;
+
+                if (struct_depth >= 32)
+                        return -EINVAL;
+
+                while (*p != SD_BUS_TYPE_STRUCT_END) {
+                        size_t t;
+
+                        r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
+                        if (r < 0)
+                                return r;
+
+                        p += t;
+                }
+
+                *l = p - s + 1;
+                return 0;
+        }
+
+        if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) {
+                const char *p = s + 1;
+                unsigned n = 0;
+
+                if (struct_depth >= 32)
+                        return -EINVAL;
+
+                while (*p != SD_BUS_TYPE_DICT_ENTRY_END) {
+                        size_t t;
+
+                        if (n == 0 && !bus_type_is_basic(*p))
+                                return -EINVAL;
+
+                        r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
+                        if (r < 0)
+                                return r;
+
+                        p += t;
+                        n++;
+                }
+
+                if (n != 2)
+                        return -EINVAL;
+
+                *l = p - s + 1;
+                return 0;
+        }
+
+        return -EINVAL;
+}
+
+
+int signature_element_length(const char *s, size_t *l) {
+        return signature_element_length_internal(s, true, 0, 0, l);
+}
+
+bool signature_is_single(const char *s, bool allow_dict_entry) {
+        int r;
+        size_t t;
+
+        if (!s)
+                return false;
+
+        r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t);
+        if (r < 0)
+                return false;
+
+        return s[t] == 0;
+}
+
+bool signature_is_pair(const char *s) {
+
+        if (!s)
+                return false;
+
+        if (!bus_type_is_basic(*s))
+                return false;
+
+        return signature_is_single(s + 1, false);
+}
+
+bool signature_is_valid(const char *s, bool allow_dict_entry) {
+        const char *p;
+        int r;
+
+        if (!s)
+                return false;
+
+        p = s;
+        while (*p) {
+                size_t t;
+
+                r = signature_element_length_internal(p, allow_dict_entry, 0, 0, &t);
+                if (r < 0)
+                        return false;
+
+                p += t;
+        }
+
+        return p - s <= 255;
+}
diff --git a/src/libsystemd/sd-bus/bus-signature.h b/src/libsystemd/sd-bus/bus-signature.h
new file mode 100644
index 0000000..2e06e30
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-signature.h
@@ -0,0 +1,31 @@
+/*-*- 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 <stdbool.h>
+#include <sys/types.h>
+
+bool signature_is_single(const char *s, bool allow_dict_entry);
+bool signature_is_pair(const char *s);
+bool signature_is_valid(const char *s, bool allow_dict_entry);
+
+int signature_element_length(const char *s, size_t *l);
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
new file mode 100644
index 0000000..0c4b6af
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -0,0 +1,1105 @@
+/*-*- 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 <endian.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <byteswap.h>
+
+#include "util.h"
+#include "macro.h"
+#include "missing.h"
+#include "strv.h"
+#include "utf8.h"
+#include "sd-daemon.h"
+
+#include "sd-bus.h"
+#include "bus-socket.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+
+#define SNDBUF_SIZE (8*1024*1024)
+
+static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) {
+
+        while (size > 0) {
+                struct iovec *i = iov + *idx;
+
+                if (i->iov_len > size) {
+                        i->iov_base = (uint8_t*) i->iov_base + size;
+                        i->iov_len -= size;
+                        return;
+                }
+
+                size -= i->iov_len;
+
+                i->iov_base = NULL;
+                i->iov_len = 0;
+
+                (*idx) ++;
+        }
+}
+
+static int append_iovec(sd_bus_message *m, const void *p, size_t sz) {
+        assert(m);
+        assert(p);
+        assert(sz > 0);
+
+        m->iovec[m->n_iovec].iov_base = (void*) p;
+        m->iovec[m->n_iovec].iov_len = sz;
+        m->n_iovec++;
+
+        return 0;
+}
+
+static int bus_message_setup_iovec(sd_bus_message *m) {
+        struct bus_body_part *part;
+        unsigned n, i;
+        int r;
+
+        assert(m);
+        assert(m->sealed);
+
+        if (m->n_iovec > 0)
+                return 0;
+
+        assert(!m->iovec);
+
+        n = 1 + m->n_body_parts;
+        if (n < ELEMENTSOF(m->iovec_fixed))
+                m->iovec = m->iovec_fixed;
+        else {
+                m->iovec = new(struct iovec, n);
+                if (!m->iovec) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        r = append_iovec(m, m->header, BUS_MESSAGE_BODY_BEGIN(m));
+        if (r < 0)
+                goto fail;
+
+        MESSAGE_FOREACH_PART(part, i, m)  {
+                r = bus_body_part_map(part);
+                if (r < 0)
+                        goto fail;
+
+                r = append_iovec(m, part->data, part->size);
+                if (r < 0)
+                        goto fail;
+        }
+
+        assert(n == m->n_iovec);
+
+        return 0;
+
+fail:
+        m->poisoned = true;
+        return r;
+}
+
+bool bus_socket_auth_needs_write(sd_bus *b) {
+
+        unsigned i;
+
+        if (b->auth_index >= ELEMENTSOF(b->auth_iovec))
+                return false;
+
+        for (i = b->auth_index; i < ELEMENTSOF(b->auth_iovec); i++) {
+                struct iovec *j = b->auth_iovec + i;
+
+                if (j->iov_len > 0)
+                        return true;
+        }
+
+        return false;
+}
+
+static int bus_socket_write_auth(sd_bus *b) {
+        ssize_t k;
+
+        assert(b);
+        assert(b->state == BUS_AUTHENTICATING);
+
+        if (!bus_socket_auth_needs_write(b))
+                return 0;
+
+        if (b->prefer_writev)
+                k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
+        else {
+                struct msghdr mh;
+                zero(mh);
+
+                mh.msg_iov = b->auth_iovec + b->auth_index;
+                mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index;
+
+                k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
+                if (k < 0 && errno == ENOTSOCK) {
+                        b->prefer_writev = true;
+                        k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
+                }
+        }
+
+        if (k < 0)
+                return errno == EAGAIN ? 0 : -errno;
+
+        iovec_advance(b->auth_iovec, &b->auth_index, (size_t) k);
+        return 1;
+}
+
+static int bus_socket_auth_verify_client(sd_bus *b) {
+        char *e, *f, *start;
+        sd_id128_t peer;
+        unsigned i;
+        int r;
+
+        assert(b);
+
+        /* We expect two response lines: "OK" and possibly
+         * "AGREE_UNIX_FD" */
+
+        e = memmem(b->rbuffer, b->rbuffer_size, "\r\n", 2);
+        if (!e)
+                return 0;
+
+        if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) {
+                f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2);
+                if (!f)
+                        return 0;
+
+                start = f + 2;
+        } else {
+                f = NULL;
+                start = e + 2;
+        }
+
+        /* Nice! We got all the lines we need. First check the OK
+         * line */
+
+        if (e - (char*) b->rbuffer != 3 + 32)
+                return -EPERM;
+
+        if (memcmp(b->rbuffer, "OK ", 3))
+                return -EPERM;
+
+        b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL;
+
+        for (i = 0; i < 32; i += 2) {
+                int x, y;
+
+                x = unhexchar(((char*) b->rbuffer)[3 + i]);
+                y = unhexchar(((char*) b->rbuffer)[3 + i + 1]);
+
+                if (x < 0 || y < 0)
+                        return -EINVAL;
+
+                peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y);
+        }
+
+        if (!sd_id128_equal(b->server_id, SD_ID128_NULL) &&
+            !sd_id128_equal(b->server_id, peer))
+                return -EPERM;
+
+        b->server_id = peer;
+
+        /* And possibly check the second line, too */
+
+        if (f)
+                b->can_fds =
+                        (f - e == sizeof("\r\nAGREE_UNIX_FD") - 1) &&
+                        memcmp(e + 2, "AGREE_UNIX_FD", sizeof("AGREE_UNIX_FD") - 1) == 0;
+
+        b->rbuffer_size -= (start - (char*) b->rbuffer);
+        memmove(b->rbuffer, start, b->rbuffer_size);
+
+        r = bus_start_running(b);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static bool line_equals(const char *s, size_t m, const char *line) {
+        size_t l;
+
+        l = strlen(line);
+        if (l != m)
+                return false;
+
+        return memcmp(s, line, l) == 0;
+}
+
+static bool line_begins(const char *s, size_t m, const char *word) {
+        size_t l;
+
+        l = strlen(word);
+        if (m < l)
+                return false;
+
+        if (memcmp(s, word, l) != 0)
+                return false;
+
+        return m == l || (m > l && s[l] == ' ');
+}
+
+static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
+        _cleanup_free_ char *token = NULL;
+
+        if (!b->anonymous_auth)
+                return 0;
+
+        if (l <= 0)
+                return 1;
+
+        assert(p[0] == ' ');
+        p++; l--;
+
+        if (l % 2 != 0)
+                return 0;
+        token = unhexmem(p, l);
+        if (!token)
+                return -ENOMEM;
+
+        if (memchr(token, 0, l/2))
+                return 0;
+
+        return !!utf8_is_valid(token);
+}
+
+static int verify_external_token(sd_bus *b, const char *p, size_t l) {
+        _cleanup_free_ char *token = NULL;
+        uid_t u;
+        int r;
+
+        /* We don't do any real authentication here. Instead, we if
+         * the owner of this bus wanted authentication he should have
+         * checked SO_PEERCRED before even creating the bus object. */
+
+        if (!b->anonymous_auth && !b->ucred_valid)
+                return 0;
+
+        if (l <= 0)
+                return 1;
+
+        assert(p[0] == ' ');
+        p++; l--;
+
+        if (l % 2 != 0)
+                return 0;
+
+        token = unhexmem(p, l);
+        if (!token)
+                return -ENOMEM;
+
+        if (memchr(token, 0, l/2))
+                return 0;
+
+        r = parse_uid(token, &u);
+        if (r < 0)
+                return 0;
+
+        /* We ignore the passed value if anonymous authentication is
+         * on anyway. */
+        if (!b->anonymous_auth && u != b->ucred.uid)
+                return 0;
+
+        return 1;
+}
+
+static int bus_socket_auth_write(sd_bus *b, const char *t) {
+        char *p;
+        size_t l;
+
+        assert(b);
+        assert(t);
+
+        /* We only make use of the first iovec */
+        assert(b->auth_index == 0 || b->auth_index == 1);
+
+        l = strlen(t);
+        p = malloc(b->auth_iovec[0].iov_len + l);
+        if (!p)
+                return -ENOMEM;
+
+        memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len);
+        memcpy(p + b->auth_iovec[0].iov_len, t, l);
+
+        b->auth_iovec[0].iov_base = p;
+        b->auth_iovec[0].iov_len += l;
+
+        free(b->auth_buffer);
+        b->auth_buffer = p;
+        b->auth_index = 0;
+        return 0;
+}
+
+static int bus_socket_auth_write_ok(sd_bus *b) {
+        char t[3 + 32 + 2 + 1];
+
+        assert(b);
+
+        snprintf(t, sizeof(t), "OK " SD_ID128_FORMAT_STR "\r\n", SD_ID128_FORMAT_VAL(b->server_id));
+        char_array_0(t);
+
+        return bus_socket_auth_write(b, t);
+}
+
+static int bus_socket_auth_verify_server(sd_bus *b) {
+        char *e;
+        const char *line;
+        size_t l;
+        bool processed = false;
+        int r;
+
+        assert(b);
+
+        if (b->rbuffer_size < 1)
+                return 0;
+
+        /* First char must be a NUL byte */
+        if (*(char*) b->rbuffer != 0)
+                return -EIO;
+
+        if (b->rbuffer_size < 3)
+                return 0;
+
+        /* Begin with the first line */
+        if (b->auth_rbegin <= 0)
+                b->auth_rbegin = 1;
+
+        for (;;) {
+                /* Check if line is complete */
+                line = (char*) b->rbuffer + b->auth_rbegin;
+                e = memmem(line, b->rbuffer_size - b->auth_rbegin, "\r\n", 2);
+                if (!e)
+                        return processed;
+
+                l = e - line;
+
+                if (line_begins(line, l, "AUTH ANONYMOUS")) {
+
+                        r = verify_anonymous_token(b, line + 14, l - 14);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                r = bus_socket_auth_write(b, "REJECTED\r\n");
+                        else {
+                                b->auth = BUS_AUTH_ANONYMOUS;
+                                r = bus_socket_auth_write_ok(b);
+                        }
+
+                } else if (line_begins(line, l, "AUTH EXTERNAL")) {
+
+                        r = verify_external_token(b, line + 13, l - 13);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                r = bus_socket_auth_write(b, "REJECTED\r\n");
+                        else {
+                                b->auth = BUS_AUTH_EXTERNAL;
+                                r = bus_socket_auth_write_ok(b);
+                        }
+
+                } else if (line_begins(line, l, "AUTH"))
+                        r = bus_socket_auth_write(b, "REJECTED EXTERNAL ANONYMOUS\r\n");
+                else if (line_equals(line, l, "CANCEL") ||
+                         line_begins(line, l, "ERROR")) {
+
+                        b->auth = _BUS_AUTH_INVALID;
+                        r = bus_socket_auth_write(b, "REJECTED\r\n");
+
+                } else if (line_equals(line, l, "BEGIN")) {
+
+                        if (b->auth == _BUS_AUTH_INVALID)
+                                r = bus_socket_auth_write(b, "ERROR\r\n");
+                        else {
+                                /* We can't leave from the auth phase
+                                 * before we haven't written
+                                 * everything queued, so let's check
+                                 * that */
+
+                                if (bus_socket_auth_needs_write(b))
+                                        return 1;
+
+                                b->rbuffer_size -= (e + 2 - (char*) b->rbuffer);
+                                memmove(b->rbuffer, e + 2, b->rbuffer_size);
+                                return bus_start_running(b);
+                        }
+
+                } else if (line_begins(line, l, "DATA")) {
+
+                        if (b->auth == _BUS_AUTH_INVALID)
+                                r = bus_socket_auth_write(b, "ERROR\r\n");
+                        else {
+                                if (b->auth == BUS_AUTH_ANONYMOUS)
+                                        r = verify_anonymous_token(b, line + 4, l - 4);
+                                else
+                                        r = verify_external_token(b, line + 4, l - 4);
+
+                                if (r < 0)
+                                        return r;
+                                if (r == 0) {
+                                        b->auth = _BUS_AUTH_INVALID;
+                                        r = bus_socket_auth_write(b, "REJECTED\r\n");
+                                } else
+                                        r = bus_socket_auth_write_ok(b);
+                        }
+                } else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) {
+                        if (b->auth == _BUS_AUTH_INVALID || !(b->hello_flags & KDBUS_HELLO_ACCEPT_FD))
+                                r = bus_socket_auth_write(b, "ERROR\r\n");
+                        else {
+                                b->can_fds = true;
+                                r = bus_socket_auth_write(b, "AGREE_UNIX_FD\r\n");
+                        }
+                } else
+                        r = bus_socket_auth_write(b, "ERROR\r\n");
+
+                if (r < 0)
+                        return r;
+
+                b->auth_rbegin = e + 2 - (char*) b->rbuffer;
+
+                processed = true;
+        }
+}
+
+static int bus_socket_auth_verify(sd_bus *b) {
+        assert(b);
+
+        if (b->is_server)
+                return bus_socket_auth_verify_server(b);
+        else
+                return bus_socket_auth_verify_client(b);
+}
+
+static int bus_socket_read_auth(sd_bus *b) {
+        struct msghdr mh;
+        struct iovec iov;
+        size_t n;
+        ssize_t k;
+        int r;
+        void *p;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) +
+                            CMSG_SPACE(sizeof(struct ucred)) +
+                            CMSG_SPACE(NAME_MAX)]; /*selinux label */
+        } control;
+        struct cmsghdr *cmsg;
+        bool handle_cmsg = false;
+
+        assert(b);
+        assert(b->state == BUS_AUTHENTICATING);
+
+        r = bus_socket_auth_verify(b);
+        if (r != 0)
+                return r;
+
+        n = MAX(256u, b->rbuffer_size * 2);
+
+        if (n > BUS_AUTH_SIZE_MAX)
+                n = BUS_AUTH_SIZE_MAX;
+
+        if (b->rbuffer_size >= n)
+                return -ENOBUFS;
+
+        p = realloc(b->rbuffer, n);
+        if (!p)
+                return -ENOMEM;
+
+        b->rbuffer = p;
+
+        zero(iov);
+        iov.iov_base = (uint8_t*) b->rbuffer + b->rbuffer_size;
+        iov.iov_len = n - b->rbuffer_size;
+
+        if (b->prefer_readv)
+                k = readv(b->input_fd, &iov, 1);
+        else {
+                zero(mh);
+                mh.msg_iov = &iov;
+                mh.msg_iovlen = 1;
+                mh.msg_control = &control;
+                mh.msg_controllen = sizeof(control);
+
+                k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
+                if (k < 0 && errno == ENOTSOCK) {
+                        b->prefer_readv = true;
+                        k = readv(b->input_fd, &iov, 1);
+                } else
+                        handle_cmsg = true;
+        }
+        if (k < 0)
+                return errno == EAGAIN ? 0 : -errno;
+        if (k == 0)
+                return -ECONNRESET;
+
+        b->rbuffer_size += k;
+
+        if (handle_cmsg) {
+                for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
+                        if (cmsg->cmsg_level == SOL_SOCKET &&
+                            cmsg->cmsg_type == SCM_RIGHTS) {
+                                int j;
+
+                                /* Whut? We received fds during the auth
+                                 * protocol? Somebody is playing games with
+                                 * us. Close them all, and fail */
+                                j = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+                                close_many((int*) CMSG_DATA(cmsg), j);
+                                return -EIO;
+
+                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                                   cmsg->cmsg_type == SCM_CREDENTIALS &&
+                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+
+                                /* Ignore bogus data, which we might
+                                 * get on socketpair() sockets */
+                                if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) {
+                                        memcpy(&b->ucred, CMSG_DATA(cmsg), sizeof(struct ucred));
+                                        b->ucred_valid = true;
+                                }
+
+                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                                   cmsg->cmsg_type == SCM_SECURITY) {
+
+                                size_t l;
+
+                                l = cmsg->cmsg_len - CMSG_LEN(0);
+                                if (l > 0) {
+                                        memcpy(&b->label, CMSG_DATA(cmsg), l);
+                                        b->label[l] = 0;
+                                }
+                        }
+                }
+        }
+
+        r = bus_socket_auth_verify(b);
+        if (r != 0)
+                return r;
+
+        return 1;
+}
+
+void bus_socket_setup(sd_bus *b) {
+        int enable;
+
+        assert(b);
+
+        /* Enable SO_PASSCRED + SO_PASSEC. We try this on any
+         * socket, just in case. */
+        enable = !b->bus_client;
+        setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
+
+        enable = !b->bus_client && (b->attach_flags & KDBUS_ATTACH_SECLABEL);
+        setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable));
+
+        /* Increase the buffers to 8 MB */
+        fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
+        fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
+
+        b->is_kernel = false;
+        b->message_version = 1;
+        b->message_endian = 0;
+}
+
+static void bus_get_peercred(sd_bus *b) {
+        assert(b);
+
+        /* Get the peer for socketpair() sockets */
+        b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;
+}
+
+static int bus_socket_start_auth_client(sd_bus *b) {
+        size_t l;
+        const char *auth_suffix, *auth_prefix;
+
+        assert(b);
+
+        if (b->anonymous_auth) {
+                auth_prefix = "\0AUTH ANONYMOUS ";
+
+                /* For ANONYMOUS auth we send some arbitrary "trace" string */
+                l = 9;
+                b->auth_buffer = hexmem("anonymous", l);
+        } else {
+                char text[20 + 1]; /* enough space for a 64bit integer plus NUL */
+
+                auth_prefix = "\0AUTH EXTERNAL ";
+
+                snprintf(text, sizeof(text), "%lu", (unsigned long) geteuid());
+                char_array_0(text);
+
+                l = strlen(text);
+                b->auth_buffer = hexmem(text, l);
+        }
+
+        if (!b->auth_buffer)
+                return -ENOMEM;
+
+        if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD)
+                auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
+        else
+                auth_suffix = "\r\nBEGIN\r\n";
+
+        b->auth_iovec[0].iov_base = (void*) auth_prefix;
+        b->auth_iovec[0].iov_len = 1 + strlen(auth_prefix + 1);
+        b->auth_iovec[1].iov_base = (void*) b->auth_buffer;
+        b->auth_iovec[1].iov_len = l * 2;
+        b->auth_iovec[2].iov_base = (void*) auth_suffix;
+        b->auth_iovec[2].iov_len = strlen(auth_suffix);
+
+        return bus_socket_write_auth(b);
+}
+
+int bus_socket_start_auth(sd_bus *b) {
+        assert(b);
+
+        bus_get_peercred(b);
+
+        b->state = BUS_AUTHENTICATING;
+        b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT;
+
+        if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0)
+                b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
+
+        if (b->output_fd != b->input_fd)
+                if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0)
+                        b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
+
+        if (b->is_server)
+                return bus_socket_read_auth(b);
+        else
+                return bus_socket_start_auth_client(b);
+}
+
+int bus_socket_connect(sd_bus *b) {
+        int r;
+
+        assert(b);
+        assert(b->input_fd < 0);
+        assert(b->output_fd < 0);
+        assert(b->sockaddr.sa.sa_family != AF_UNSPEC);
+
+        b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (b->input_fd < 0)
+                return -errno;
+
+        b->output_fd = b->input_fd;
+
+        bus_socket_setup(b);
+
+        r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
+        if (r < 0) {
+                if (errno == EINPROGRESS)
+                        return 1;
+
+                return -errno;
+        }
+
+        return bus_socket_start_auth(b);
+}
+
+int bus_socket_exec(sd_bus *b) {
+        int s[2], r;
+        pid_t pid;
+
+        assert(b);
+        assert(b->input_fd < 0);
+        assert(b->output_fd < 0);
+        assert(b->exec_path);
+
+        r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s);
+        if (r < 0)
+                return -errno;
+
+        pid = fork();
+        if (pid < 0) {
+                close_pipe(s);
+                return -errno;
+        }
+        if (pid == 0) {
+                /* Child */
+
+                reset_all_signal_handlers();
+
+                close_all_fds(s+1, 1);
+
+                assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
+                assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
+
+                if (s[1] != STDIN_FILENO && s[1] != STDOUT_FILENO)
+                        close_nointr_nofail(s[1]);
+
+                fd_cloexec(STDIN_FILENO, false);
+                fd_cloexec(STDOUT_FILENO, false);
+                fd_nonblock(STDIN_FILENO, false);
+                fd_nonblock(STDOUT_FILENO, false);
+
+                if (b->exec_argv)
+                        execvp(b->exec_path, b->exec_argv);
+                else {
+                        const char *argv[] = { b->exec_path, NULL };
+                        execvp(b->exec_path, (char**) argv);
+                }
+
+                _exit(EXIT_FAILURE);
+        }
+
+        close_nointr_nofail(s[1]);
+        b->output_fd = b->input_fd = s[0];
+
+        bus_socket_setup(b);
+
+        return bus_socket_start_auth(b);
+}
+
+int bus_socket_take_fd(sd_bus *b) {
+        assert(b);
+
+        bus_socket_setup(b);
+
+        return bus_socket_start_auth(b);
+}
+
+int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
+        struct iovec *iov;
+        ssize_t k;
+        size_t n;
+        unsigned j;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(idx);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        if (*idx >= BUS_MESSAGE_SIZE(m))
+                return 0;
+
+        r = bus_message_setup_iovec(m);
+        if (r < 0)
+                return r;
+
+        n = m->n_iovec * sizeof(struct iovec);
+        iov = alloca(n);
+        memcpy(iov, m->iovec, n);
+
+        j = 0;
+        iovec_advance(iov, &j, *idx);
+
+        if (bus->prefer_writev)
+                k = writev(bus->output_fd, iov, m->n_iovec);
+        else {
+                struct msghdr mh;
+                zero(mh);
+
+                if (m->n_fds > 0) {
+                        struct cmsghdr *control;
+                        control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
+
+                        mh.msg_control = control;
+                        control->cmsg_level = SOL_SOCKET;
+                        control->cmsg_type = SCM_RIGHTS;
+                        mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
+                        memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds);
+                }
+
+                mh.msg_iov = iov;
+                mh.msg_iovlen = m->n_iovec;
+
+                k = sendmsg(bus->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
+                if (k < 0 && errno == ENOTSOCK) {
+                        bus->prefer_writev = true;
+                        k = writev(bus->output_fd, iov, m->n_iovec);
+                }
+        }
+
+        if (k < 0)
+                return errno == EAGAIN ? 0 : -errno;
+
+        *idx += (size_t) k;
+        return 1;
+}
+
+static int bus_socket_read_message_need(sd_bus *bus, size_t *need) {
+        uint32_t a, b;
+        uint8_t e;
+        uint64_t sum;
+
+        assert(bus);
+        assert(need);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        if (bus->rbuffer_size < sizeof(struct bus_header)) {
+                *need = sizeof(struct bus_header) + 8;
+
+                /* Minimum message size:
+                 *
+                 * Header +
+                 *
+                 *  Method Call: +2 string headers
+                 *       Signal: +3 string headers
+                 * Method Error: +1 string headers
+                 *               +1 uint32 headers
+                 * Method Reply: +1 uint32 headers
+                 *
+                 * A string header is at least 9 bytes
+                 * A uint32 header is at least 8 bytes
+                 *
+                 * Hence the minimum message size of a valid message
+                 * is header + 8 bytes */
+
+                return 0;
+        }
+
+        a = ((const uint32_t*) bus->rbuffer)[1];
+        b = ((const uint32_t*) bus->rbuffer)[3];
+
+        e = ((const uint8_t*) bus->rbuffer)[0];
+        if (e == BUS_LITTLE_ENDIAN) {
+                a = le32toh(a);
+                b = le32toh(b);
+        } else if (e == BUS_BIG_ENDIAN) {
+                a = be32toh(a);
+                b = be32toh(b);
+        } else
+                return -EBADMSG;
+
+        sum = (uint64_t) sizeof(struct bus_header) + (uint64_t) ALIGN_TO(b, 8) + (uint64_t) a;
+        if (sum >= BUS_MESSAGE_SIZE_MAX)
+                return -ENOBUFS;
+
+        *need = (size_t) sum;
+        return 0;
+}
+
+static int bus_socket_make_message(sd_bus *bus, size_t size) {
+        sd_bus_message *t;
+        void *b;
+        int r;
+
+        assert(bus);
+        assert(bus->rbuffer_size >= size);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        r = bus_rqueue_make_room(bus);
+        if (r < 0)
+                return r;
+
+        if (bus->rbuffer_size > size) {
+                b = memdup((const uint8_t*) bus->rbuffer + size,
+                           bus->rbuffer_size - size);
+                if (!b)
+                        return -ENOMEM;
+        } else
+                b = NULL;
+
+        r = bus_message_from_malloc(bus,
+                                    bus->rbuffer, size,
+                                    bus->fds, bus->n_fds,
+                                    !bus->bus_client && bus->ucred_valid ? &bus->ucred : NULL,
+                                    !bus->bus_client && bus->label[0] ? bus->label : NULL,
+                                    &t);
+        if (r < 0) {
+                free(b);
+                return r;
+        }
+
+        bus->rbuffer = b;
+        bus->rbuffer_size -= size;
+
+        bus->fds = NULL;
+        bus->n_fds = 0;
+
+        bus->rqueue[bus->rqueue_size++] = t;
+
+        return 1;
+}
+
+int bus_socket_read_message(sd_bus *bus) {
+        struct msghdr mh;
+        struct iovec iov;
+        ssize_t k;
+        size_t need;
+        int r;
+        void *b;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) +
+                            CMSG_SPACE(sizeof(struct ucred)) +
+                            CMSG_SPACE(NAME_MAX)]; /*selinux label */
+        } control;
+        struct cmsghdr *cmsg;
+        bool handle_cmsg = false;
+
+        assert(bus);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        r = bus_socket_read_message_need(bus, &need);
+        if (r < 0)
+                return r;
+
+        if (bus->rbuffer_size >= need)
+                return bus_socket_make_message(bus, need);
+
+        b = realloc(bus->rbuffer, need);
+        if (!b)
+                return -ENOMEM;
+
+        bus->rbuffer = b;
+
+        zero(iov);
+        iov.iov_base = (uint8_t*) bus->rbuffer + bus->rbuffer_size;
+        iov.iov_len = need - bus->rbuffer_size;
+
+        if (bus->prefer_readv)
+                k = readv(bus->input_fd, &iov, 1);
+        else {
+                zero(mh);
+                mh.msg_iov = &iov;
+                mh.msg_iovlen = 1;
+                mh.msg_control = &control;
+                mh.msg_controllen = sizeof(control);
+
+                k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
+                if (k < 0 && errno == ENOTSOCK) {
+                        bus->prefer_readv = true;
+                        k = readv(bus->input_fd, &iov, 1);
+                } else
+                        handle_cmsg = true;
+        }
+        if (k < 0)
+                return errno == EAGAIN ? 0 : -errno;
+        if (k == 0)
+                return -ECONNRESET;
+
+        bus->rbuffer_size += k;
+
+        if (handle_cmsg) {
+                for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
+                        if (cmsg->cmsg_level == SOL_SOCKET &&
+                            cmsg->cmsg_type == SCM_RIGHTS) {
+                                int n, *f;
+
+                                n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+                                if (!bus->can_fds) {
+                                        /* Whut? We received fds but this
+                                         * isn't actually enabled? Close them,
+                                         * and fail */
+
+                                        close_many((int*) CMSG_DATA(cmsg), n);
+                                        return -EIO;
+                                }
+
+                                f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n));
+                                if (!f) {
+                                        close_many((int*) CMSG_DATA(cmsg), n);
+                                        return -ENOMEM;
+                                }
+
+                                memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int));
+                                bus->fds = f;
+                                bus->n_fds += n;
+                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                                   cmsg->cmsg_type == SCM_CREDENTIALS &&
+                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+
+                                /* Ignore bogus data, which we might
+                                 * get on socketpair() sockets */
+                                if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) {
+                                        memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred));
+                                        bus->ucred_valid = true;
+                                }
+
+                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                                   cmsg->cmsg_type == SCM_SECURITY) {
+
+                                size_t l;
+                                l = cmsg->cmsg_len - CMSG_LEN(0);
+                                if (l > 0) {
+                                        memcpy(&bus->label, CMSG_DATA(cmsg), l);
+                                        bus->label[l] = 0;
+                                }
+                        }
+                }
+        }
+
+        r = bus_socket_read_message_need(bus, &need);
+        if (r < 0)
+                return r;
+
+        if (bus->rbuffer_size >= need)
+                return bus_socket_make_message(bus, need);
+
+        return 1;
+}
+
+int bus_socket_process_opening(sd_bus *b) {
+        int error = 0;
+        socklen_t slen = sizeof(error);
+        struct pollfd p = {
+                .fd = b->output_fd,
+                .events = POLLOUT,
+        };
+        int r;
+
+        assert(b->state == BUS_OPENING);
+
+        r = poll(&p, 1, 0);
+        if (r < 0)
+                return -errno;
+
+        if (!(p.revents & (POLLOUT|POLLERR|POLLHUP)))
+                return 0;
+
+        r = getsockopt(b->output_fd, SOL_SOCKET, SO_ERROR, &error, &slen);
+        if (r < 0)
+                b->last_connect_error = errno;
+        else if (error != 0)
+                b->last_connect_error = error;
+        else if (p.revents & (POLLERR|POLLHUP))
+                b->last_connect_error = ECONNREFUSED;
+        else
+                return bus_socket_start_auth(b);
+
+        return bus_next_address(b);
+}
+
+int bus_socket_process_authenticating(sd_bus *b) {
+        int r;
+
+        assert(b);
+        assert(b->state == BUS_AUTHENTICATING);
+
+        if (now(CLOCK_MONOTONIC) >= b->auth_timeout)
+                return -ETIMEDOUT;
+
+        r = bus_socket_write_auth(b);
+        if (r != 0)
+                return r;
+
+        return bus_socket_read_auth(b);
+}
diff --git a/src/libsystemd/sd-bus/bus-socket.h b/src/libsystemd/sd-bus/bus-socket.h
new file mode 100644
index 0000000..5a1c7d4
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-socket.h
@@ -0,0 +1,39 @@
+/*-*- 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-bus.h"
+
+void bus_socket_setup(sd_bus *b);
+
+int bus_socket_connect(sd_bus *b);
+int bus_socket_exec(sd_bus *b);
+int bus_socket_take_fd(sd_bus *b);
+int bus_socket_start_auth(sd_bus *b);
+
+int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx);
+int bus_socket_read_message(sd_bus *bus);
+
+int bus_socket_process_opening(sd_bus *b);
+int bus_socket_process_authenticating(sd_bus *b);
+
+bool bus_socket_auth_needs_write(sd_bus *b);
diff --git a/src/libsystemd/sd-bus/bus-type.c b/src/libsystemd/sd-bus/bus-type.c
new file mode 100644
index 0000000..b7914d1
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-type.c
@@ -0,0 +1,179 @@
+/*-*- 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 "util.h"
+#include "bus-type.h"
+
+bool bus_type_is_valid(char c) {
+        static const char valid[] = {
+                SD_BUS_TYPE_BYTE,
+                SD_BUS_TYPE_BOOLEAN,
+                SD_BUS_TYPE_INT16,
+                SD_BUS_TYPE_UINT16,
+                SD_BUS_TYPE_INT32,
+                SD_BUS_TYPE_UINT32,
+                SD_BUS_TYPE_INT64,
+                SD_BUS_TYPE_UINT64,
+                SD_BUS_TYPE_DOUBLE,
+                SD_BUS_TYPE_STRING,
+                SD_BUS_TYPE_OBJECT_PATH,
+                SD_BUS_TYPE_SIGNATURE,
+                SD_BUS_TYPE_ARRAY,
+                SD_BUS_TYPE_VARIANT,
+                SD_BUS_TYPE_STRUCT,
+                SD_BUS_TYPE_DICT_ENTRY,
+                SD_BUS_TYPE_UNIX_FD
+        };
+
+        return !!memchr(valid, c, sizeof(valid));
+}
+
+bool bus_type_is_valid_in_signature(char c) {
+        static const char valid[] = {
+                SD_BUS_TYPE_BYTE,
+                SD_BUS_TYPE_BOOLEAN,
+                SD_BUS_TYPE_INT16,
+                SD_BUS_TYPE_UINT16,
+                SD_BUS_TYPE_INT32,
+                SD_BUS_TYPE_UINT32,
+                SD_BUS_TYPE_INT64,
+                SD_BUS_TYPE_UINT64,
+                SD_BUS_TYPE_DOUBLE,
+                SD_BUS_TYPE_STRING,
+                SD_BUS_TYPE_OBJECT_PATH,
+                SD_BUS_TYPE_SIGNATURE,
+                SD_BUS_TYPE_ARRAY,
+                SD_BUS_TYPE_VARIANT,
+                SD_BUS_TYPE_STRUCT_BEGIN,
+                SD_BUS_TYPE_STRUCT_END,
+                SD_BUS_TYPE_DICT_ENTRY_BEGIN,
+                SD_BUS_TYPE_DICT_ENTRY_END,
+                SD_BUS_TYPE_UNIX_FD
+        };
+
+        return !!memchr(valid, c, sizeof(valid));
+}
+
+bool bus_type_is_basic(char c) {
+        static const char valid[] = {
+                SD_BUS_TYPE_BYTE,
+                SD_BUS_TYPE_BOOLEAN,
+                SD_BUS_TYPE_INT16,
+                SD_BUS_TYPE_UINT16,
+                SD_BUS_TYPE_INT32,
+                SD_BUS_TYPE_UINT32,
+                SD_BUS_TYPE_INT64,
+                SD_BUS_TYPE_UINT64,
+                SD_BUS_TYPE_DOUBLE,
+                SD_BUS_TYPE_STRING,
+                SD_BUS_TYPE_OBJECT_PATH,
+                SD_BUS_TYPE_SIGNATURE,
+                SD_BUS_TYPE_UNIX_FD
+        };
+
+        return !!memchr(valid, c, sizeof(valid));
+}
+
+bool bus_type_is_trivial(char c) {
+        static const char valid[] = {
+                SD_BUS_TYPE_BYTE,
+                SD_BUS_TYPE_BOOLEAN,
+                SD_BUS_TYPE_INT16,
+                SD_BUS_TYPE_UINT16,
+                SD_BUS_TYPE_INT32,
+                SD_BUS_TYPE_UINT32,
+                SD_BUS_TYPE_INT64,
+                SD_BUS_TYPE_UINT64,
+                SD_BUS_TYPE_DOUBLE
+        };
+
+        return !!memchr(valid, c, sizeof(valid));
+}
+
+bool bus_type_is_container(char c) {
+        static const char valid[] = {
+                SD_BUS_TYPE_ARRAY,
+                SD_BUS_TYPE_VARIANT,
+                SD_BUS_TYPE_STRUCT,
+                SD_BUS_TYPE_DICT_ENTRY
+        };
+
+        return !!memchr(valid, c, sizeof(valid));
+}
+
+int bus_type_get_alignment(char c) {
+
+        switch (c) {
+        case SD_BUS_TYPE_BYTE:
+        case SD_BUS_TYPE_SIGNATURE:
+        case SD_BUS_TYPE_VARIANT:
+                return 1;
+
+        case SD_BUS_TYPE_INT16:
+        case SD_BUS_TYPE_UINT16:
+                return 2;
+
+        case SD_BUS_TYPE_BOOLEAN:
+        case SD_BUS_TYPE_INT32:
+        case SD_BUS_TYPE_UINT32:
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_OBJECT_PATH:
+        case SD_BUS_TYPE_ARRAY:
+        case SD_BUS_TYPE_UNIX_FD:
+                return 4;
+
+        case SD_BUS_TYPE_INT64:
+        case SD_BUS_TYPE_UINT64:
+        case SD_BUS_TYPE_DOUBLE:
+        case SD_BUS_TYPE_STRUCT:
+        case SD_BUS_TYPE_STRUCT_BEGIN:
+        case SD_BUS_TYPE_DICT_ENTRY:
+        case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
+                return 8;
+        }
+
+        return -EINVAL;
+}
+
+int bus_type_get_size(char c) {
+
+        switch (c) {
+        case SD_BUS_TYPE_BYTE:
+                return 1;
+
+        case SD_BUS_TYPE_INT16:
+        case SD_BUS_TYPE_UINT16:
+                return 2;
+
+        case SD_BUS_TYPE_BOOLEAN:
+        case SD_BUS_TYPE_INT32:
+        case SD_BUS_TYPE_UINT32:
+        case SD_BUS_TYPE_UNIX_FD:
+                return 4;
+
+        case SD_BUS_TYPE_INT64:
+        case SD_BUS_TYPE_UINT64:
+        case SD_BUS_TYPE_DOUBLE:
+                return 8;
+        }
+
+        return -EINVAL;
+}
diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h
new file mode 100644
index 0000000..2e423bb
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-type.h
@@ -0,0 +1,36 @@
+/*-*- 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 <stdbool.h>
+
+#include "sd-bus.h"
+#include "sd-bus-protocol.h"
+
+bool bus_type_is_valid(char c) _const_;
+bool bus_type_is_valid_in_signature(char c) _const_;
+bool bus_type_is_basic(char c) _const_;
+bool bus_type_is_trivial(char c) _const_;
+bool bus_type_is_container(char c) _const_;
+
+int bus_type_get_alignment(char c) _const_;
+int bus_type_get_size(char c) _const_;
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
new file mode 100644
index 0000000..a468bca
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -0,0 +1,1232 @@
+/*-*- 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 <sys/socket.h>
+#include <sys/capability.h>
+
+#include "util.h"
+#include "strv.h"
+#include "macro.h"
+#include "def.h"
+#include "missing.h"
+
+#include "sd-event.h"
+#include "sd-bus.h"
+#include "bus-error.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "bus-internal.h"
+
+static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        sd_event *e = userdata;
+
+        assert(bus);
+        assert(m);
+        assert(e);
+
+        sd_event_exit(e, 0);
+        return 1;
+}
+
+int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
+        _cleanup_free_ char *match = NULL;
+        const char *unique;
+        int r;
+
+        assert(e);
+        assert(bus);
+        assert(name);
+
+        /* We unregister the name here and then wait for the
+         * NameOwnerChanged signal for this event to arrive before we
+         * quit. We do this in order to make sure that any queued
+         * requests are still processed before we really exit. */
+
+        r = sd_bus_get_unique_name(bus, &unique);
+        if (r < 0)
+                return r;
+
+        r = asprintf(&match,
+                     "sender='org.freedesktop.DBus',"
+                     "type='signal',"
+                     "interface='org.freedesktop.DBus',"
+                     "member='NameOwnerChanged',"
+                     "path='/org/freedesktop/DBus',"
+                     "arg0='%s',"
+                     "arg1='%s',"
+                     "arg2=''", name, unique);
+        if (r < 0)
+                return -ENOMEM;
+
+        r = sd_bus_add_match(bus, match, name_owner_change_callback, e);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_release_name(bus, name);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int bus_event_loop_with_idle(
+                sd_event *e,
+                sd_bus *bus,
+                const char *name,
+                usec_t timeout,
+                check_idle_t check_idle,
+                void *userdata) {
+        bool exiting = false;
+        int r, code;
+
+        assert(e);
+        assert(bus);
+        assert(name);
+
+        for (;;) {
+                bool idle;
+
+                r = sd_event_get_state(e);
+                if (r < 0)
+                        return r;
+                if (r == SD_EVENT_FINISHED)
+                        break;
+
+                if (check_idle)
+                        idle = check_idle(userdata);
+                else
+                        idle = true;
+
+                r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
+                if (r < 0)
+                        return r;
+
+                if (r == 0 && !exiting) {
+                        r = bus_async_unregister_and_exit(e, bus, name);
+                        if (r < 0)
+                                return r;
+
+                        exiting = true;
+                }
+        }
+
+        r = sd_event_get_exit_code(e, &code);
+        if (r < 0)
+                return r;
+
+        return code;
+}
+
+int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
+        _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
+        int r, has_owner = 0;
+
+        assert(c);
+        assert(name);
+
+        r = sd_bus_call_method(c,
+                               "org.freedesktop.DBus",
+                               "/org/freedesktop/dbus",
+                               "org.freedesktop.DBus",
+                               "NameHasOwner",
+                               error,
+                               &rep,
+                               "s",
+                               name);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_basic(rep, 'b', &has_owner);
+        if (r < 0)
+                return sd_bus_error_set_errno(error, r);
+
+        return has_owner;
+}
+
+int bus_verify_polkit(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *action,
+                bool interactive,
+                bool *_challenge,
+                sd_bus_error *e) {
+
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        uid_t uid;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(action);
+
+        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
+        if (r < 0)
+                return r;
+
+        if (uid == 0)
+                return 1;
+
+#ifdef ENABLE_POLKIT
+        else {
+                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+                int authorized = false, challenge = false;
+                const char *sender;
+
+                sender = sd_bus_message_get_sender(m);
+                if (!sender)
+                        return -EBADMSG;
+
+                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_enter_container(reply, 'r', "bba{ss}");
+                if (r < 0)
+                        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;
+        Hashmap *registry;
+} AsyncPolkitQuery;
+
+static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
+
+        if (!q)
+                return;
+
+        if (q->serial > 0 && b)
+                sd_bus_call_async_cancel(b, q->serial);
+
+        if (q->registry && q->request)
+                hashmap_remove(q->registry, q->request);
+
+        sd_bus_message_unref(q->request);
+        sd_bus_message_unref(q->reply);
+
+        free(q);
+}
+
+static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        AsyncPolkitQuery *q = userdata;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(q);
+
+        q->reply = sd_bus_message_ref(reply);
+        q->serial = 0;
+
+        r = sd_bus_message_rewind(q->request, true);
+        if (r < 0) {
+                r = sd_bus_reply_method_errno(q->request, r, NULL);
+                goto finish;
+        }
+
+        r = q->callback(bus, q->request, q->userdata, &error_buffer);
+        r = bus_maybe_reply_error(q->request, r, &error_buffer);
+
+finish:
+        async_polkit_query_free(bus, q);
+        return r;
+}
+
+#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;
+        const char *sender;
+#endif
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        uid_t uid;
+        int r;
+
+        assert(bus);
+        assert(registry);
+        assert(m);
+        assert(action);
+
+#ifdef ENABLE_POLKIT
+        q = hashmap_get(*registry, m);
+        if (q) {
+                int 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;
+
+                        /* Copy error from polkit reply */
+                        e = sd_bus_message_get_error(q->reply);
+                        sd_bus_error_copy(error, e);
+
+                        /* Treat no PK available as access denied */
+                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
+                                return -EACCES;
+
+                        return -sd_bus_error_get_errno(e);
+                }
+
+                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
+                if (r >= 0)
+                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
+
+                if (r < 0)
+                        return r;
+
+                if (authorized)
+                        return 1;
+
+                return -EACCES;
+        }
+#endif
+
+        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
+        if (r < 0)
+                return r;
+
+        if (uid == 0)
+                return 1;
+
+#ifdef ENABLE_POLKIT
+        sender = sd_bus_message_get_sender(m);
+        if (!sender)
+                return -EBADMSG;
+
+        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,
+                        NULL);
+        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;
+        }
+
+        q->registry = *registry;
+
+        r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
+        if (r < 0) {
+                async_polkit_query_free(bus, q);
+                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
+}
+
+int bus_check_peercred(sd_bus *c) {
+        struct ucred ucred;
+        socklen_t l;
+        int fd;
+
+        assert(c);
+
+        fd = sd_bus_get_fd(c);
+        if (fd < 0)
+                return fd;
+
+        l = sizeof(struct ucred);
+        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
+                return -errno;
+
+        if (l != sizeof(struct ucred))
+                return -E2BIG;
+
+        if (ucred.uid != 0 && ucred.uid != geteuid())
+                return -EPERM;
+
+        return 1;
+}
+
+int bus_open_system_systemd(sd_bus **_bus) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        int r;
+
+        assert(_bus);
+
+        if (geteuid() != 0)
+                return sd_bus_open_system(_bus);
+
+        /* If we are root and kdbus is not available, then let's talk
+         * directly to the system instance, instead of going via the
+         * bus */
+
+#ifdef ENABLE_KDBUS
+        r = sd_bus_new(&bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH);
+        if (r < 0)
+                return r;
+
+        bus->bus_client = true;
+
+        r = sd_bus_start(bus);
+        if (r >= 0) {
+                *_bus = bus;
+                bus = NULL;
+                return 0;
+        }
+
+        bus = sd_bus_unref(bus);
+#endif
+
+        r = sd_bus_new(&bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_start(bus);
+        if (r < 0)
+                return sd_bus_open_system(_bus);
+
+        r = bus_check_peercred(bus);
+        if (r < 0)
+                return r;
+
+        *_bus = bus;
+        bus = NULL;
+
+        return 0;
+}
+
+int bus_open_user_systemd(sd_bus **_bus) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        _cleanup_free_ char *ee = NULL;
+        const char *e;
+        int r;
+
+        /* Try via kdbus first, and then directly */
+
+        assert(_bus);
+
+#ifdef ENABLE_KDBUS
+        r = sd_bus_new(&bus);
+        if (r < 0)
+                return r;
+
+        if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid()) < 0)
+                return -ENOMEM;
+
+        bus->bus_client = true;
+
+        r = sd_bus_start(bus);
+        if (r >= 0) {
+                *_bus = bus;
+                bus = NULL;
+                return 0;
+        }
+
+        bus = sd_bus_unref(bus);
+#endif
+
+        e = secure_getenv("XDG_RUNTIME_DIR");
+        if (!e)
+                return sd_bus_open_user(_bus);
+
+        ee = bus_address_escape(e);
+        if (!ee)
+                return -ENOMEM;
+
+        r = sd_bus_new(&bus);
+        if (r < 0)
+                return r;
+
+        bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL);
+        if (!bus->address)
+                return -ENOMEM;
+
+        r = sd_bus_start(bus);
+        if (r < 0)
+                return sd_bus_open_user(_bus);
+
+        r = bus_check_peercred(bus);
+        if (r < 0)
+                return r;
+
+        *_bus = bus;
+        bus = NULL;
+
+        return 0;
+}
+
+int bus_print_property(const char *name, sd_bus_message *property, bool all) {
+        char type;
+        const char *contents;
+        int r;
+
+        assert(name);
+        assert(property);
+
+        r = sd_bus_message_peek_type(property, &type, &contents);
+        if (r < 0)
+                return r;
+
+        switch (type) {
+
+        case SD_BUS_TYPE_STRING: {
+                const char *s;
+
+                r = sd_bus_message_read_basic(property, type, &s);
+                if (r < 0)
+                        return r;
+
+                if (all || !isempty(s))
+                        printf("%s=%s\n", name, s);
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_BOOLEAN: {
+                bool b;
+
+                r = sd_bus_message_read_basic(property, type, &b);
+                if (r < 0)
+                        return r;
+
+                printf("%s=%s\n", name, yes_no(b));
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_UINT64: {
+                uint64_t u;
+
+                r = sd_bus_message_read_basic(property, type, &u);
+                if (r < 0)
+                        return r;
+
+                /* Yes, heuristics! But we can change this check
+                 * should it turn out to not be sufficient */
+
+                if (endswith(name, "Timestamp")) {
+                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
+
+                        t = format_timestamp(timestamp, sizeof(timestamp), u);
+                        if (t || all)
+                                printf("%s=%s\n", name, strempty(t));
+
+                } else if (strstr(name, "USec")) {
+                        char timespan[FORMAT_TIMESPAN_MAX];
+
+                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
+                } else
+                        printf("%s=%llu\n", name, (unsigned long long) u);
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_UINT32: {
+                uint32_t u;
+
+                r = sd_bus_message_read_basic(property, type, &u);
+                if (r < 0)
+                        return r;
+
+                if (strstr(name, "UMask") || strstr(name, "Mode"))
+                        printf("%s=%04o\n", name, u);
+                else
+                        printf("%s=%u\n", name, (unsigned) u);
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_INT32: {
+                int32_t i;
+
+                r = sd_bus_message_read_basic(property, type, &i);
+                if (r < 0)
+                        return r;
+
+                printf("%s=%i\n", name, (int) i);
+                return 1;
+        }
+
+        case SD_BUS_TYPE_DOUBLE: {
+                double d;
+
+                r = sd_bus_message_read_basic(property, type, &d);
+                if (r < 0)
+                        return r;
+
+                printf("%s=%g\n", name, d);
+                return 1;
+        }
+
+        case SD_BUS_TYPE_ARRAY:
+                if (streq(contents, "s")) {
+                        bool first = true;
+                        const char *str;
+
+                        r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
+                        if (r < 0)
+                                return r;
+
+                        while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
+                                if (first)
+                                        printf("%s=", name);
+
+                                printf("%s%s", first ? "" : " ", str);
+
+                                first = false;
+                        }
+                        if (r < 0)
+                                return r;
+
+                        if (first && all)
+                                printf("%s=", name);
+                        if (!first || all)
+                                puts("");
+
+                        r = sd_bus_message_exit_container(property);
+                        if (r < 0)
+                                return r;
+
+                        return 1;
+
+                } else if (streq(contents, "y")) {
+                        const uint8_t *u;
+                        size_t n;
+
+                        r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
+                        if (r < 0)
+                                return r;
+
+                        if (all || n > 0) {
+                                unsigned int i;
+
+                                printf("%s=", name);
+
+                                for (i = 0; i < n; i++)
+                                        printf("%02x", u[i]);
+
+                                puts("");
+                        }
+
+                        return 1;
+
+                } else if (streq(contents, "u")) {
+                        uint32_t *u;
+                        size_t n;
+
+                        r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
+                        if (r < 0)
+                                return r;
+
+                        if (all || n > 0) {
+                                unsigned int i;
+
+                                printf("%s=", name);
+
+                                for (i = 0; i < n; i++)
+                                        printf("%08x", u[i]);
+
+                                puts("");
+                        }
+
+                        return 1;
+                }
+
+                break;
+        }
+
+        return 0;
+}
+
+int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(bus);
+        assert(path);
+
+        r = sd_bus_call_method(bus,
+                        dest,
+                        path,
+                        "org.freedesktop.DBus.Properties",
+                        "GetAll",
+                        &error,
+                        &reply,
+                        "s", "");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
+        if (r < 0)
+                return r;
+
+        while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+                const char *name;
+                const char *contents;
+
+                r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
+                if (r < 0)
+                        return r;
+
+                if (!filter || strv_find(filter, name)) {
+                        r = sd_bus_message_peek_type(reply, NULL, &contents);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
+                        if (r < 0)
+                                return r;
+
+                        r = bus_print_property(name, reply, all);
+                        if (r < 0)
+                                return r;
+                        if (r == 0) {
+                                if (all)
+                                        printf("%s=[unprintable]\n", name);
+                                /* skip what we didn't read */
+                                r = sd_bus_message_skip(reply, contents);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        r = sd_bus_message_exit_container(reply);
+                        if (r < 0)
+                                return r;
+                } else {
+                        r = sd_bus_message_skip(reply, "v");
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_exit_container(reply);
+                if (r < 0)
+                        return r;
+        }
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        sd_id128_t *p = userdata;
+        const void *v;
+        size_t n;
+        int r;
+
+        r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
+        if (r < 0)
+                return r;
+
+        if (n == 0)
+                *p = SD_ID128_NULL;
+        else if (n == 16)
+                memcpy((*p).bytes, v, n);
+        else
+                return -EINVAL;
+
+        return 0;
+}
+
+static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+        char type;
+        int r;
+
+        r = sd_bus_message_peek_type(m, &type, NULL);
+        if (r < 0)
+                return r;
+
+        switch (type) {
+        case SD_BUS_TYPE_STRING: {
+                const char *s;
+                char *str;
+                char **p = userdata;
+
+                r = sd_bus_message_read_basic(m, type, &s);
+                if (r < 0)
+                        break;
+
+                if (isempty(s))
+                        break;
+
+                str = strdup(s);
+                if (!str) {
+                        r = -ENOMEM;
+                        break;
+                }
+                free(*p);
+                *p = str;
+
+                break;
+        }
+
+        case SD_BUS_TYPE_ARRAY: {
+               _cleanup_strv_free_ char **l = NULL;
+               char ***p = userdata;
+
+                r = bus_message_read_strv_extend(m, &l);
+                if (r < 0)
+                        break;
+
+                strv_free(*p);
+                *p = l;
+                l = NULL;
+
+                break;
+        }
+
+        case SD_BUS_TYPE_BOOLEAN: {
+                unsigned b;
+                bool *p = userdata;
+
+                r = sd_bus_message_read_basic(m, type, &b);
+                if (r < 0)
+                        break;
+
+                *p = b;
+
+                break;
+        }
+
+        case SD_BUS_TYPE_UINT32: {
+                uint64_t u;
+                uint32_t *p = userdata;
+
+                r = sd_bus_message_read_basic(m, type, &u);
+                if (r < 0)
+                        break;
+
+                *p = u;
+
+                break;
+        }
+
+        case SD_BUS_TYPE_UINT64: {
+                uint64_t t;
+                uint64_t *p = userdata;
+
+                r = sd_bus_message_read_basic(m, type, &t);
+                if (r < 0)
+                        break;
+
+                *p = t;
+
+                break;
+        }
+
+        default:
+                break;
+        }
+
+        return r;
+}
+
+int bus_map_all_properties(sd_bus *bus,
+                           const char *destination,
+                           const char *path,
+                           const struct bus_properties_map *map,
+                           void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(bus);
+        assert(destination);
+        assert(path);
+        assert(map);
+
+        r = sd_bus_call_method(
+                        bus,
+                        destination,
+                        path,
+                        "org.freedesktop.DBus.Properties",
+                        "GetAll",
+                        &error,
+                        &m,
+                        "s", "");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
+        if (r < 0)
+                return r;
+
+        while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+                const struct bus_properties_map *prop;
+                const char *member;
+                const char *contents;
+                void *v;
+                unsigned i;
+
+                r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
+                if (r < 0)
+                        return r;
+
+                for (i = 0, prop = NULL; map[i].member; i++)
+                        if (streq(map[i].member, member)) {
+                                prop = &map[i];
+                                break;
+                        }
+
+                if (prop) {
+                        r = sd_bus_message_peek_type(m, NULL, &contents);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
+                        if (r < 0)
+                                return r;
+
+                        v = (uint8_t *)userdata + prop->offset;
+                        if (map[i].set)
+                                r = prop->set(bus, member, m, &error, v);
+                        else
+                                r = map_basic(bus, member, m, &error, v);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return r;
+                } else {
+                        r = sd_bus_message_skip(m, "v");
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_exit_container(m);
+                if (r < 0)
+                        return r;
+        }
+
+        return r;
+}
+
+int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+        int r;
+
+        assert(transport >= 0);
+        assert(transport < _BUS_TRANSPORT_MAX);
+        assert(bus);
+
+        assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
+        assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
+
+        switch (transport) {
+
+        case BUS_TRANSPORT_LOCAL:
+                if (user)
+                        r = sd_bus_default_user(bus);
+                else
+                        r = sd_bus_default_system(bus);
+
+                break;
+
+        case BUS_TRANSPORT_REMOTE:
+                r = sd_bus_open_system_remote(host, bus);
+                break;
+
+        case BUS_TRANSPORT_CONTAINER:
+                r = sd_bus_open_system_container(host, bus);
+                break;
+
+        default:
+                assert_not_reached("Hmm, unknown transport type.");
+        }
+
+        return r;
+}
+
+int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+        int r;
+
+        assert(transport >= 0);
+        assert(transport < _BUS_TRANSPORT_MAX);
+        assert(bus);
+
+        assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
+        assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
+
+        switch (transport) {
+
+        case BUS_TRANSPORT_LOCAL:
+                if (user)
+                        r = bus_open_user_systemd(bus);
+                else
+                        r = bus_open_system_systemd(bus);
+
+                break;
+
+        case BUS_TRANSPORT_REMOTE:
+                r = sd_bus_open_system_remote(host, bus);
+                break;
+
+        case BUS_TRANSPORT_CONTAINER:
+                r = sd_bus_open_system_container(host, bus);
+                break;
+
+        default:
+                assert_not_reached("Hmm, unknown transport type.");
+        }
+
+        return r;
+}
+
+int bus_property_get_tristate(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        int *tristate = userdata;
+
+        return sd_bus_message_append(reply, "b", *tristate > 0);
+}
+
+int bus_property_get_bool(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        int b = *(bool*) userdata;
+
+        return sd_bus_message_append_basic(reply, 'b', &b);
+}
+
+#if __SIZEOF_SIZE_T__ != 8
+int bus_property_get_size(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        uint64_t sz = *(size_t*) userdata;
+
+        return sd_bus_message_append_basic(reply, 't', &sz);
+}
+#endif
+
+#if __SIZEOF_LONG__ != 8
+int bus_property_get_long(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        int64_t l = *(long*) userdata;
+
+        return sd_bus_message_append_basic(reply, 'x', &l);
+}
+
+int bus_property_get_ulong(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        uint64_t ul = *(unsigned long*) userdata;
+
+        return sd_bus_message_append_basic(reply, 't', &ul);
+}
+#endif
+
+int bus_log_parse_error(int r) {
+        log_error("Failed to parse message: %s", strerror(-r));
+        return r;
+}
+
+int bus_log_create_error(int r) {
+        log_error("Failed to create message: %s", strerror(-r));
+        return r;
+}
+
+int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
+        assert(message);
+        assert(u);
+
+        return sd_bus_message_read(
+                        message,
+                        "(ssssssouso)",
+                        &u->id,
+                        &u->description,
+                        &u->load_state,
+                        &u->active_state,
+                        &u->sub_state,
+                        &u->following,
+                        &u->unit_path,
+                        &u->job_id,
+                        &u->job_type,
+                        &u->job_path);
+}
+
+int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
+        assert(m);
+
+        if (r < 0) {
+                if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+                        sd_bus_reply_method_errno(m, r, error);
+
+        } else if (sd_bus_error_is_set(error)) {
+                if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+                        sd_bus_reply_method_error(m, error);
+        } else
+                return r;
+
+        log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
+                  bus_message_type_to_string(m->header->type),
+                  strna(m->sender),
+                  strna(m->path),
+                  strna(m->interface),
+                  strna(m->member),
+                  strna(m->root_container.signature),
+                  bus_error_message(error, r));
+
+        return 1;
+}
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
new file mode 100644
index 0000000..51e1613
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -0,0 +1,180 @@
+/*-*- 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"
+
+typedef enum BusTransport {
+        BUS_TRANSPORT_LOCAL,
+        BUS_TRANSPORT_REMOTE,
+        BUS_TRANSPORT_CONTAINER,
+        _BUS_TRANSPORT_MAX,
+        _BUS_TRANSPORT_INVALID = -1
+} BusTransport;
+
+typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
+
+struct bus_properties_map {
+        const char *member;
+        const char *signature;
+        bus_property_set_t set;
+        size_t offset;
+};
+
+int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
+
+int bus_map_all_properties(sd_bus *bus,
+                           const char *destination,
+                           const char *path,
+                           const struct bus_properties_map *map,
+                           void *userdata);
+
+int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name);
+
+typedef bool (*check_idle_t)(void *userdata);
+
+int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout, check_idle_t check_idle, void *userdata);
+
+int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
+
+int bus_check_peercred(sd_bus *c);
+
+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);
+
+int bus_open_system_systemd(sd_bus **_bus);
+int bus_open_user_systemd(sd_bus **_bus);
+
+int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
+
+int bus_print_property(const char *name, sd_bus_message *property, bool all);
+int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
+
+int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+
+#define bus_property_get_usec ((sd_bus_property_get_t) NULL)
+#define bus_property_set_usec ((sd_bus_property_set_t) NULL)
+
+assert_cc(sizeof(int) == sizeof(int32_t));
+#define bus_property_get_int ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(unsigned) == sizeof(unsigned));
+#define bus_property_get_unsigned ((sd_bus_property_get_t) NULL)
+
+/* On 64bit machines we can use the default serializer for size_t and
+ * friends, otherwise we need to cast this manually */
+#if __SIZEOF_SIZE_T__ == 8
+#define bus_property_get_size ((sd_bus_property_get_t) NULL)
+#else
+int bus_property_get_size(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+#endif
+
+#if __SIZEOF_LONG__ == 8
+#define bus_property_get_long ((sd_bus_property_get_t) NULL)
+#define bus_property_get_ulong ((sd_bus_property_get_t) NULL)
+#else
+int bus_property_get_long(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+int bus_property_get_ulong(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+#endif
+
+/* uid_t and friends on Linux 32 bit. This means we can just use the
+ * default serializer for 32bit unsigned, for serializing it, and map
+ * it to NULL here */
+assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+#define bus_property_get_uid ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+#define bus_property_get_gid ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(pid_t) == sizeof(uint32_t));
+#define bus_property_get_pid ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(mode_t) == sizeof(uint32_t));
+#define bus_property_get_mode ((sd_bus_property_get_t) NULL)
+
+int bus_log_parse_error(int r);
+int bus_log_create_error(int r);
+
+typedef struct UnitInfo {
+        const char *id;
+        const char *description;
+        const char *load_state;
+        const char *active_state;
+        const char *sub_state;
+        const char *following;
+        const char *unit_path;
+        uint32_t job_id;
+        const char *job_type;
+        const char *job_path;
+} UnitInfo;
+
+int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref);
+
+#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
+#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
+#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp)
+#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
+
+#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type)              \
+        int function(sd_bus *bus,                                       \
+                     const char *path,                                  \
+                     const char *interface,                             \
+                     const char *property,                              \
+                     sd_bus_message *reply,                             \
+                     void *userdata,                                    \
+                     sd_bus_error *error) {                             \
+                                                                        \
+                const char *value;                                      \
+                type *field = userdata;                                 \
+                int r;                                                  \
+                                                                        \
+                assert(bus);                                            \
+                assert(reply);                                          \
+                assert(field);                                          \
+                                                                        \
+                value = strempty(name##_to_string(*field));             \
+                                                                        \
+                r = sd_bus_message_append_basic(reply, 's', value);     \
+                if (r < 0)                                              \
+                        return r;                                       \
+                                                                        \
+                return 1;                                               \
+        }                                                               \
+        struct __useless_struct_to_allow_trailing_semicolon__
+
+#define BUS_PROPERTY_DUAL_TIMESTAMP(name, offset, flags) \
+        SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \
+        SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags))
+
+int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
new file mode 100644
index 0000000..e962ba3
--- /dev/null
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -0,0 +1,514 @@
+/*-*- 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 <getopt.h>
+
+#include "strv.h"
+#include "util.h"
+#include "log.h"
+#include "build.h"
+#include "pager.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "bus-dump.h"
+
+static bool arg_no_pager = false;
+static char *arg_address = NULL;
+static bool arg_unique = false;
+static bool arg_acquired = false;
+static bool arg_activatable = false;
+static bool arg_show_machine = false;
+static char **arg_matches = NULL;
+static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
+static char *arg_host = NULL;
+static bool arg_user = false;
+
+static void pager_open_if_enabled(void) {
+
+        /* Cache result before we open the pager */
+        if (arg_no_pager)
+                return;
+
+        pager_open(false);
+}
+
+static int list_bus_names(sd_bus *bus, char **argv) {
+        _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
+        _cleanup_free_ char **merged = NULL;
+        _cleanup_hashmap_free_ Hashmap *names = NULL;
+        char **i;
+        int r;
+        size_t max_i = 0;
+        unsigned n = 0;
+        void *v;
+        char *k;
+        Iterator iterator;
+
+        assert(bus);
+
+        r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
+        if (r < 0) {
+                log_error("Failed to list names: %s", strerror(-r));
+                return r;
+        }
+
+        pager_open_if_enabled();
+
+        names = hashmap_new(string_hash_func, string_compare_func);
+        if (!names)
+                return log_oom();
+
+        STRV_FOREACH(i, acquired) {
+                max_i = MAX(max_i, strlen(*i));
+
+                r = hashmap_put(names, *i, INT_TO_PTR(1));
+                if (r < 0) {
+                        log_error("Failed to add to hashmap: %s", strerror(-r));
+                        return r;
+                }
+        }
+
+        STRV_FOREACH(i, activatable) {
+                max_i = MAX(max_i, strlen(*i));
+
+                r = hashmap_put(names, *i, INT_TO_PTR(2));
+                if (r < 0 && r != -EEXIST) {
+                        log_error("Failed to add to hashmap: %s", strerror(-r));
+                        return r;
+                }
+        }
+
+        merged = new(char*, hashmap_size(names) + 1);
+        HASHMAP_FOREACH_KEY(v, k, names, iterator)
+                merged[n++] = k;
+
+        merged[n] = NULL;
+        strv_sort(merged);
+
+        printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s",
+               (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION");
+
+        if (arg_show_machine)
+                puts(" MACHINE");
+        else
+                putchar('\n');
+
+        STRV_FOREACH(i, merged) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+                sd_id128_t mid;
+
+                if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
+                        /* Activatable */
+
+                        printf("%-*s", (int) max_i, *i);
+                        printf("          - -               -                (activatable) -                         -         ");
+                        if (arg_show_machine)
+                                puts(" -");
+                        else
+                                putchar('\n');
+                        continue;
+
+                }
+
+                if (!arg_unique && (*i)[0] == ':')
+                        continue;
+
+                if (!arg_acquired && (*i)[0] != ':')
+                        continue;
+
+                printf("%-*s", (int) max_i, *i);
+
+                r = sd_bus_get_owner(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION, &creds);
+                if (r >= 0) {
+                        const char *unique, *session, *unit;
+                        pid_t pid;
+                        uid_t uid;
+
+                        r = sd_bus_creds_get_pid(creds, &pid);
+                        if (r >= 0) {
+                                const char *comm = NULL;
+
+                                sd_bus_creds_get_comm(creds, &comm);
+
+                                printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
+                        } else
+                                fputs("          - -              ", stdout);
+
+                        r = sd_bus_creds_get_uid(creds, &uid);
+                        if (r >= 0) {
+                                _cleanup_free_ char *u = NULL;
+
+                                u = uid_to_name(uid);
+                                if (!u)
+                                        return log_oom();
+
+                                if (strlen(u) > 16)
+                                        u[16] = 0;
+
+                                printf(" %-16s", u);
+                        } else
+                                fputs(" -               ", stdout);
+
+                        r = sd_bus_creds_get_unique_name(creds, &unique);
+                        if (r >= 0)
+                                printf(" %-13s", unique);
+                        else
+                                fputs(" -            ", stdout);
+
+                        r = sd_bus_creds_get_unit(creds, &unit);
+                        if (r >= 0) {
+                                _cleanup_free_ char *e;
+
+                                e = ellipsize(unit, 25, 100);
+                                if (!e)
+                                        return log_oom();
+
+                                printf(" %-25s", e);
+                        } else
+                                fputs(" -                        ", stdout);
+
+                        r = sd_bus_creds_get_session(creds, &session);
+                        if (r >= 0)
+                                printf(" %-10s", session);
+                        else
+                                fputs(" -         ", stdout);
+
+                } else
+                        printf("          - -               -                -             -                         -         ");
+
+                if (arg_show_machine) {
+                        r = sd_bus_get_owner_machine_id(bus, *i, &mid);
+                        if (r >= 0) {
+                                char m[SD_ID128_STRING_MAX];
+                                printf(" %s\n", sd_id128_to_string(mid, m));
+                        } else
+                                puts(" -");
+                } else
+                        putchar('\n');
+        }
+
+        return 0;
+}
+
+static int monitor(sd_bus *bus, char *argv[]) {
+        bool added_something = false;
+        char **i;
+        int r;
+
+        STRV_FOREACH(i, argv+1) {
+                _cleanup_free_ char *m = NULL;
+
+                if (!service_name_is_valid(*i)) {
+                        log_error("Invalid service name '%s'", *i);
+                        return -EINVAL;
+                }
+
+                m = strjoin("sender='", *i, "'", NULL);
+                if (!m)
+                        return log_oom();
+
+                r = sd_bus_add_match(bus, m, NULL, NULL);
+                if (r < 0) {
+                        log_error("Failed to add match: %s", strerror(-r));
+                        return r;
+                }
+
+                added_something = true;
+        }
+
+        STRV_FOREACH(i, arg_matches) {
+                r = sd_bus_add_match(bus, *i, NULL, NULL);
+                if (r < 0) {
+                        log_error("Failed to add match: %s", strerror(-r));
+                        return r;
+                }
+
+                added_something = true;
+        }
+
+        if (!added_something) {
+                r = sd_bus_add_match(bus, "", NULL, NULL);
+                if (r < 0) {
+                        log_error("Failed to add match: %s", strerror(-r));
+                        return r;
+                }
+        }
+
+        for (;;) {
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+                r = sd_bus_process(bus, &m);
+                if (r < 0) {
+                        log_error("Failed to process bus: %s", strerror(-r));
+                        return r;
+                }
+
+                if (m) {
+                        bus_message_dump(m, stdout, true);
+                        continue;
+                }
+
+                if (r > 0)
+                        continue;
+
+                r = sd_bus_wait(bus, (uint64_t) -1);
+                if (r < 0) {
+                        log_error("Failed to wait for bus: %s", strerror(-r));
+                        return r;
+                }
+        }
+}
+
+static int status(sd_bus *bus, char *argv[]) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        pid_t pid;
+        int r;
+
+        assert(bus);
+
+        if (strv_length(argv) != 2) {
+                log_error("Expects one argument.");
+                return -EINVAL;
+        }
+
+        r = parse_pid(argv[1], &pid);
+        if (r < 0)
+                r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
+        else
+                r = sd_bus_creds_new_from_pid(pid, _SD_BUS_CREDS_ALL, &creds);
+
+        if (r < 0) {
+                log_error("Failed to get credentials: %s", strerror(-r));
+                return r;
+        }
+
+        bus_creds_dump(creds, NULL);
+        return 0;
+}
+
+static int help(void) {
+
+        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+               "Introspect the bus.\n\n"
+               "  -h --help               Show this help\n"
+               "     --version            Show package version\n"
+               "     --no-pager           Do not pipe output into a pager\n"
+               "     --system             Connect to system bus\n"
+               "     --user               Connect to user bus\n"
+               "  -H --host=[USER@]HOST   Operate on remote host\n"
+               "  -M --machine=CONTAINER  Operate on local container\n"
+               "     --address=ADDRESS    Connect to bus specified by address\n"
+               "     --show-machine       Show machine ID column in list\n"
+               "     --unique             Only show unique names\n"
+               "     --acquired           Only show acquired names\n"
+               "     --activatable        Only show activatable names\n"
+               "     --match=MATCH        Only show matching messages\n\n"
+               "Commands:\n"
+               "  list                    List bus names\n"
+               "  monitor [SERVICE...]    Show bus traffic\n"
+               "  status NAME             Show name status\n"
+               "  help                    Show this help\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_NO_PAGER,
+                ARG_SYSTEM,
+                ARG_USER,
+                ARG_ADDRESS,
+                ARG_MATCH,
+                ARG_SHOW_MACHINE,
+                ARG_UNIQUE,
+                ARG_ACQUIRED,
+                ARG_ACTIVATABLE
+        };
+
+        static const struct option options[] = {
+                { "help",         no_argument,       NULL, 'h'              },
+                { "version",      no_argument,       NULL, ARG_VERSION      },
+                { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
+                { "system",       no_argument,       NULL, ARG_SYSTEM       },
+                { "user",         no_argument,       NULL, ARG_USER         },
+                { "address",      required_argument, NULL, ARG_ADDRESS      },
+                { "show-machine", no_argument,       NULL, ARG_SHOW_MACHINE },
+                { "unique",       no_argument,       NULL, ARG_UNIQUE       },
+                { "acquired",     no_argument,       NULL, ARG_ACQUIRED     },
+                { "activatable",  no_argument,       NULL, ARG_ACTIVATABLE  },
+                { "match",        required_argument, NULL, ARG_MATCH        },
+                { "host",         required_argument, NULL, 'H'              },
+                { "machine",      required_argument, NULL, 'M'              },
+                {},
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        return help();
+
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(SYSTEMD_FEATURES);
+                        return 0;
+
+                case ARG_NO_PAGER:
+                        arg_no_pager = true;
+                        break;
+
+                case ARG_USER:
+                        arg_user = true;
+                        break;
+
+                case ARG_SYSTEM:
+                        arg_user = false;
+                        break;
+
+                case ARG_ADDRESS:
+                        arg_address = optarg;
+                        break;
+
+                case ARG_SHOW_MACHINE:
+                        arg_show_machine = true;
+                        break;
+
+                case ARG_UNIQUE:
+                        arg_unique = true;
+                        break;
+
+                case ARG_ACQUIRED:
+                        arg_acquired = true;
+                        break;
+
+                case ARG_ACTIVATABLE:
+                        arg_activatable = true;
+                        break;
+
+                case ARG_MATCH:
+                        if (strv_extend(&arg_matches, optarg) < 0)
+                                return log_oom();
+                        break;
+
+                case 'H':
+                        arg_transport = BUS_TRANSPORT_REMOTE;
+                        arg_host = optarg;
+                        break;
+
+                case 'M':
+                        arg_transport = BUS_TRANSPORT_CONTAINER;
+                        arg_host = optarg;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+        }
+
+        if (!arg_unique && !arg_acquired && !arg_activatable)
+                arg_unique = arg_acquired = arg_activatable = true;
+
+        return 1;
+}
+
+static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
+        assert(bus);
+
+        if (optind >= argc ||
+            streq(argv[optind], "list"))
+                return list_bus_names(bus, argv + optind);
+
+        if (streq(argv[optind], "monitor"))
+                return monitor(bus, argv + optind);
+
+        if (streq(argv[optind], "status"))
+                return status(bus, argv + optind);
+
+        if (streq(argv[optind], "help"))
+                return help();
+
+        log_error("Unknown command '%s'", argv[optind]);
+        return -EINVAL;
+}
+
+int main(int argc, char *argv[]) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        int r;
+
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        if (arg_address) {
+                r = sd_bus_new(&bus);
+                if (r < 0) {
+                        log_error("Failed to allocate bus: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = sd_bus_set_address(bus, arg_address);
+                if (r < 0) {
+                        log_error("Failed to set address: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = sd_bus_set_bus_client(bus, true);
+                if (r < 0) {
+                        log_error("Failed to set bus client: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = sd_bus_start(bus);
+        } else
+                r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
+
+        if (r < 0) {
+                log_error("Failed to connect to bus: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = busctl_main(bus, argc, argv);
+
+finish:
+        pager_close();
+
+        strv_free(arg_matches);
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h
new file mode 100644
index 0000000..fe0bb48
--- /dev/null
+++ b/src/libsystemd/sd-bus/kdbus.h
@@ -0,0 +1,900 @@
+/*
+ * Copyright (C) 2013 Kay Sievers
+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh at linuxfoundation.org>
+ * Copyright (C) 2013 Linux Foundation
+ * Copyright (C) 2013 Lennart Poettering
+ * Copyright (C) 2013 Daniel Mack <daniel at zonque.org>
+ *
+ * kdbus 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.
+ *
+ * "Everything should be made as simple as possible, but not simpler."
+ *   -- Albert Einstein
+ */
+
+#ifndef _KDBUS_H_
+#define _KDBUS_H_
+
+#ifndef __KERNEL__
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#endif
+
+#define KDBUS_IOC_MAGIC			0x95
+#define KDBUS_SRC_ID_KERNEL		(0)
+#define KDBUS_DST_ID_NAME		(0)
+#define KDBUS_MATCH_ID_ANY		(~0ULL)
+#define KDBUS_DST_ID_BROADCAST		(~0ULL)
+
+/**
+ * struct kdbus_notify_id_change - name registry change message
+ * @id:			New or former owner of the name
+ * @flags:		flags field from KDBUS_HELLO_*
+ *
+ * Sent from kernel to userspace when the owner or activator of
+ * a well-known name changes.
+ *
+ * Attached to:
+ *   KDBUS_ITEM_ID_ADD
+ *   KDBUS_ITEM_ID_REMOVE
+ */
+struct kdbus_notify_id_change {
+	__u64 id;
+	__u64 flags;
+};
+
+/**
+ * struct kdbus_notify_name_change - name registry change message
+ * @old:		ID and flags of former owner of a name
+ * @new:		ID and flags of new owner of a name
+ * @name:		Well-known name
+ *
+ * Sent from kernel to userspace when the owner or activator of
+ * a well-known name changes.
+ *
+ * Attached to:
+ *   KDBUS_ITEM_NAME_ADD
+ *   KDBUS_ITEM_NAME_REMOVE
+ *   KDBUS_ITEM_NAME_CHANGE
+ */
+struct kdbus_notify_name_change {
+	struct kdbus_notify_id_change old;
+	struct kdbus_notify_id_change new;
+	char name[0];
+};
+
+/**
+ * struct kdbus_creds - process credentials
+ * @uid:		User ID
+ * @gid:		Group ID
+ * @pid:		Process ID
+ * @tid:		Thread ID
+ * @starttime:		Starttime of the process
+ *
+ * The starttime of the process PID. This is useful to detect PID overruns
+ * from the client side. i.e. if you use the PID to look something up in
+ * /proc/$PID/ you can afterwards check the starttime field of it, to ensure
+ * you didn't run into a PID overrun.
+ *
+ * Attached to:
+ *   KDBUS_ITEM_CREDS
+ */
+struct kdbus_creds {
+	__u64 uid;
+	__u64 gid;
+	__u64 pid;
+	__u64 tid;
+	__u64 starttime;
+};
+
+/**
+ * struct kdbus_audit - audit information
+ * @sessionid:		The audit session ID
+ * @loginuid:		The audit login uid
+ *
+ * Attached to:
+ *   KDBUS_ITEM_AUDIT
+ */
+struct kdbus_audit {
+	__u64 sessionid;
+	__u64 loginuid;
+};
+
+/**
+ * struct kdbus_timestamp
+ * @seqnum:		Global per-namespace message sequence number
+ * @monotonic_ns:	Monotonic timestamp, in nanoseconds
+ * @realtime_ns:	Realtime timestamp, in nanoseconds
+ *
+ * Attached to:
+ *   KDBUS_ITEM_TIMESTAMP
+ */
+struct kdbus_timestamp {
+	__u64 seqnum;
+	__u64 monotonic_ns;
+	__u64 realtime_ns;
+};
+
+/**
+ * struct kdbus_vec - I/O vector for kdbus payload items
+ * @size:		The size of the vector
+ * @address:		Memory address for memory addresses
+ * @offset:		Offset in the in-message payload memory,
+ *			relative to the message head
+ *
+ * Attached to:
+ *   KDBUS_ITEM_PAYLOAD_VEC
+ */
+struct kdbus_vec {
+	__u64 size;
+	union {
+		__u64 address;
+		__u64 offset;
+	};
+};
+
+/**
+ * struct kdbus_memfd - a kdbus memfd
+ * @size:		The memfd's size
+ * @fd:			The file descriptor number
+ * @__pad:		Padding to ensure proper alignement and size
+ *
+ * Attached to:
+ *   KDBUS_ITEM_PAYLOAD_MEMFD
+ */
+struct kdbus_memfd {
+	__u64 size;
+	int fd;
+	__u32 __pad;
+};
+
+/**
+ * struct kdbus_name - a registered well-known name with its flags
+ * @flags:		flags from KDBUS_NAME_*
+ * @name:		well-known name
+ *
+ * Attached to:
+ *   KDBUS_ITEM_NAME
+ */
+struct kdbus_name {
+	__u64 flags;
+	char name[0];
+};
+
+/**
+ * struct kdbus_policy_access - policy access item
+ * @type:		One of KDBUS_POLICY_ACCESS_* types
+ * @bits:		Access to grant. One of KDBUS_POLICY_*
+ * @id:			For KDBUS_POLICY_ACCESS_USER, the uid
+ *			For KDBUS_POLICY_ACCESS_GROUP, the gid
+ *
+ * Embedded in:
+ *   struct kdbus_policy
+ */
+struct kdbus_policy_access {
+	__u64 type;	/* USER, GROUP, WORLD */
+	__u64 bits;	/* RECV, SEND, OWN */
+	__u64 id;	/* uid, gid, 0 */
+};
+
+/**
+ * struct kdbus_policy - a policy item
+ * @access:		Policy access details
+ * @name:		Well-known name to grant access to
+ *
+ * Attached to:
+ *   KDBUS_POLICY_ACCESS
+ *   KDBUS_ITEM_POLICY_NAME
+ */
+struct kdbus_policy {
+	union {
+		struct kdbus_policy_access access;
+		char name[0];
+	};
+};
+
+/**
+ * enum kdbus_item_type - item types to chain data in a list
+ * @_KDBUS_ITEM_NULL:		Uninitialized/invalid
+ * @_KDBUS_ITEM_USER_BASE:	Start of user items
+ * @KDBUS_ITEM_PAYLOAD_VEC:	Vector to data
+ * @KDBUS_ITEM_PAYLOAD_OFF:	Data at returned offset to message head
+ * @KDBUS_ITEM_PAYLOAD_MEMFD:	Data as sealed memfd
+ * @KDBUS_ITEM_FDS:		Attached file descriptors
+ * @KDBUS_ITEM_BLOOM:		For broadcasts, carries bloom filter
+ * @KDBUS_ITEM_BLOOM_SIZE:	Desired bloom size, used by KDBUS_CMD_BUS_MAKE
+ * @KDBUS_ITEM_DST_NAME:	Destination's well-known name
+ * @KDBUS_ITEM_MAKE_NAME:	Name of namespace, bus, endpoint
+ * @KDBUS_ITEM_MEMFD_NAME:	The human readable name of a memfd (debugging)
+ * @_KDBUS_ITEM_POLICY_BASE:	Start of policy items
+ * @KDBUS_ITEM_POLICY_NAME:	Policy in struct kdbus_policy
+ * @KDBUS_ITEM_POLICY_ACCESS:	Policy in struct kdbus_policy
+ * @_KDBUS_ITEM_ATTACH_BASE:	Start of metadata attach items
+ * @KDBUS_ITEM_NAME:		Well-know name with flags
+ * @KDBUS_ITEM_ID:		Connection ID
+ * @KDBUS_ITEM_TIMESTAMP:	Timestamp
+ * @KDBUS_ITEM_CREDS:		Process credential
+ * @KDBUS_ITEM_PID_COMM:	Process ID "comm" identifier
+ * @KDBUS_ITEM_TID_COMM:	Thread ID "comm" identifier
+ * @KDBUS_ITEM_EXE:		The path of the executable
+ * @KDBUS_ITEM_CMDLINE:		The process command line
+ * @KDBUS_ITEM_CGROUP:		The croup membership
+ * @KDBUS_ITEM_CAPS:		The process capabilities
+ * @KDBUS_ITEM_SECLABEL:	The security label
+ * @KDBUS_ITEM_AUDIT:		The audit IDs
+ * @KDBUS_ITEM_CONN_NAME:	The connection's human-readable name (debugging)
+ * @_KDBUS_ITEM_KERNEL_BASE:	Start of kernel-generated message items
+ * @KDBUS_ITEM_NAME_ADD:	Notify in struct kdbus_notify_name_change
+ * @KDBUS_ITEM_NAME_REMOVE:	Notify in struct kdbus_notify_name_change
+ * @KDBUS_ITEM_NAME_CHANGE:	Notify in struct kdbus_notify_name_change
+ * @KDBUS_ITEM_ID_ADD:		Notify in struct kdbus_notify_id_change
+ * @KDBUS_ITEM_ID_REMOVE:	Notify in struct kdbus_notify_id_change
+ * @KDBUS_ITEM_REPLY_TIMEOUT:	Timeout has been reached
+ * @KDBUS_ITEM_REPLY_DEAD:	Destination died
+ */
+enum kdbus_item_type {
+	_KDBUS_ITEM_NULL,
+	_KDBUS_ITEM_USER_BASE,
+	KDBUS_ITEM_PAYLOAD_VEC	= _KDBUS_ITEM_USER_BASE,
+	KDBUS_ITEM_PAYLOAD_OFF,
+	KDBUS_ITEM_PAYLOAD_MEMFD,
+	KDBUS_ITEM_FDS,
+	KDBUS_ITEM_BLOOM,
+	KDBUS_ITEM_BLOOM_SIZE,
+	KDBUS_ITEM_DST_NAME,
+	KDBUS_ITEM_MAKE_NAME,
+	KDBUS_ITEM_MEMFD_NAME,
+
+	_KDBUS_ITEM_POLICY_BASE	= 0x1000,
+	KDBUS_ITEM_POLICY_NAME = _KDBUS_ITEM_POLICY_BASE,
+	KDBUS_ITEM_POLICY_ACCESS,
+
+	_KDBUS_ITEM_ATTACH_BASE	= 0x2000,
+	KDBUS_ITEM_NAME		= _KDBUS_ITEM_ATTACH_BASE,
+	KDBUS_ITEM_ID,
+	KDBUS_ITEM_TIMESTAMP,
+	KDBUS_ITEM_CREDS,
+	KDBUS_ITEM_PID_COMM,
+	KDBUS_ITEM_TID_COMM,
+	KDBUS_ITEM_EXE,
+	KDBUS_ITEM_CMDLINE,
+	KDBUS_ITEM_CGROUP,
+	KDBUS_ITEM_CAPS,
+	KDBUS_ITEM_SECLABEL,
+	KDBUS_ITEM_AUDIT,
+	KDBUS_ITEM_CONN_NAME,
+
+	_KDBUS_ITEM_KERNEL_BASE	= 0x3000,
+	KDBUS_ITEM_NAME_ADD	= _KDBUS_ITEM_KERNEL_BASE,
+	KDBUS_ITEM_NAME_REMOVE,
+	KDBUS_ITEM_NAME_CHANGE,
+	KDBUS_ITEM_ID_ADD,
+	KDBUS_ITEM_ID_REMOVE,
+	KDBUS_ITEM_REPLY_TIMEOUT,
+	KDBUS_ITEM_REPLY_DEAD,
+};
+
+/**
+ * struct kdbus_item - chain of data blocks
+ * @size:		Overall data record size
+ * @type:		Kdbus_item type of data
+ * @data:		Generic bytes
+ * @data32:		Generic 32 bit array
+ * @data64:		Generic 64 bit array
+ * @str:		Generic string
+ * @id:			Connection ID
+ * @vec:		KDBUS_ITEM_PAYLOAD_VEC
+ * @creds:		KDBUS_ITEM_CREDS
+ * @audit:		KDBUS_ITEM_AUDIT
+ * @timestamp:		KDBUS_ITEM_TIMESTAMP
+ * @name:		KDBUS_ITEM_NAME
+ * @memfd:		KDBUS_ITEM_PAYLOAD_MEMFD
+ * @name_change:	KDBUS_ITEM_NAME_ADD
+ *			KDBUS_ITEM_NAME_REMOVE
+ *			KDBUS_ITEM_NAME_CHANGE
+ * @id_change:		KDBUS_ITEM_ID_ADD
+ *			KDBUS_ITEM_ID_REMOVE
+ * @policy:		KDBUS_ITEM_POLICY_NAME
+ *			KDBUS_ITEM_POLICY_ACCESS
+ */
+struct kdbus_item {
+	__u64 size;
+	__u64 type;
+	union {
+		__u8 data[0];
+		__u32 data32[0];
+		__u64 data64[0];
+		char str[0];
+
+		__u64 id;
+		struct kdbus_vec vec;
+		struct kdbus_creds creds;
+		struct kdbus_audit audit;
+		struct kdbus_timestamp timestamp;
+		struct kdbus_name name;
+		struct kdbus_memfd memfd;
+		int fds[0];
+		struct kdbus_notify_name_change name_change;
+		struct kdbus_notify_id_change id_change;
+		struct kdbus_policy policy;
+	};
+};
+
+/**
+ * enum kdbus_msg_flags - type of message
+ * @KDBUS_MSG_FLAGS_EXPECT_REPLY:	Expect a reply message, used for
+ *					method calls. The userspace-supplied
+ *					cookie identifies the message and the
+ *					respective reply carries the cookie
+ *					in cookie_reply
+ * @KDBUS_MSG_FLAGS_SYNC_REPLY:		Wait for destination connection to
+ * 					reply to this message. The
+ * 					KDBUS_CMD_MSG_SEND ioctl() will block
+ * 					until the reply is received, and
+ * 					offset_reply in struct kdbus_msg will
+ * 					yield the offset in the sender's pool
+ * 					where the reply can be found.
+ * 					This flag is only valid if
+ * 					@KDBUS_MSG_FLAGS_EXPECT_REPLY is set as
+ * 					well.
+ * @KDBUS_MSG_FLAGS_NO_AUTO_START:	Do not start a service, if the addressed
+ *					name is not currently active
+ */
+enum kdbus_msg_flags {
+	KDBUS_MSG_FLAGS_EXPECT_REPLY	= 1 << 0,
+	KDBUS_MSG_FLAGS_SYNC_REPLY	= 1 << 1,
+	KDBUS_MSG_FLAGS_NO_AUTO_START	= 1 << 2,
+};
+
+/**
+ * enum kdbus_payload_type - type of payload carried by message
+ * @KDBUS_PAYLOAD_KERNEL:	Kernel-generated simple message
+ * @KDBUS_PAYLOAD_DBUS:		D-Bus marshalling "DBusDBus"
+ */
+enum kdbus_payload_type {
+	KDBUS_PAYLOAD_KERNEL,
+	KDBUS_PAYLOAD_DBUS	= 0x4442757344427573ULL,
+};
+
+/**
+ * struct kdbus_msg - the representation of a kdbus message
+ * @size:		Total size of the message
+ * @flags:		Message flags (KDBUS_MSG_FLAGS_*)
+ * @priority:		Message queue priority value
+ * @dst_id:		64-bit ID of the destination connection
+ * @src_id:		64-bit ID of the source connection
+ * @payload_type:	Payload type (KDBUS_PAYLOAD_*)
+ * @cookie:		Userspace-supplied cookie, for the connection
+ *			to identify its messages
+ * @timeout_ns:		The time to wait for a message reply from the peer.
+ *			If there is no reply, a kernel-generated message
+ *			with an attached KDBUS_ITEM_REPLY_TIMEOUT item
+ *			is sent to @src_id.
+ * @cookie_reply:	A reply to the requesting message with the same
+ *			cookie. The requesting connection can match its
+ *			request and the reply with this value
+ * @offset_reply:	If KDBUS_MSG_FLAGS_WAIT_FOR_REPLY, this field will
+ *			contain the offset in the sender's pool where the
+ *			reply is stored.
+ * @items:		A list of kdbus_items containing the message payload
+ */
+struct kdbus_msg {
+	__u64 size;
+	__u64 flags;
+	__s64 priority;
+	__u64 dst_id;
+	__u64 src_id;
+	__u64 payload_type;
+	__u64 cookie;
+	union {
+		__u64 timeout_ns;
+		__u64 cookie_reply;
+		__u64 offset_reply;
+	};
+	struct kdbus_item items[0];
+} __attribute__((aligned(8)));
+
+/**
+ * enum kdbus_recv_flags - flags for de-queuing messages
+ * @KDBUS_RECV_PEEK:		Return the next queued message without
+ *				actually de-queuing it, and without installing
+ *				any file descriptors or other resources. It is
+ *				usually used to determine the activating
+ *				connection of a bus name.
+ * @KDBUS_RECV_DROP:		Drop and free the next queued message and all
+ *				its resources without actually receiving it.
+ * @KDBUS_RECV_USE_PRIORITY:	Only de-queue messages with the specified or
+ * 				higher priority (lowest values); if not set,
+ * 				the priority value is ignored.
+ */
+enum kdbus_recv_flags {
+	KDBUS_RECV_PEEK		= 1 <<  0,
+	KDBUS_RECV_DROP		= 1 <<  1,
+	KDBUS_RECV_USE_PRIORITY	= 1 <<  2,
+};
+
+/**
+ * struct kdbus_cmd_recv - struct to de-queue a buffered message
+ * @flags:		KDBUS_RECV_* flags
+ * @priority:		Minimum priority of the messages to de-queue. Lowest
+ *			values have the highest priority.
+ * @offset:		Returned offset in the pool where the message is
+ * 			stored. The user must use KDBUS_CMD_FREE to free
+ * 			the allocated memory.
+ *
+ * This struct is used with the KDBUS_CMD_MSG_RECV ioctl.
+ */
+struct kdbus_cmd_recv {
+	__u64 flags;
+	__s64 priority;
+	__u64 offset;
+} __attribute__((aligned(8)));
+
+/**
+ * enum kdbus_policy_access_type - permissions of a policy record
+ * @_KDBUS_POLICY_ACCESS_NULL:	Uninitialized/invalid
+ * @KDBUS_POLICY_ACCESS_USER:	Grant access to a uid
+ * @KDBUS_POLICY_ACCESS_GROUP:	Grant access to gid
+ * @KDBUS_POLICY_ACCESS_WORLD:	World-accessible
+ */
+enum kdbus_policy_access_type {
+	_KDBUS_POLICY_ACCESS_NULL,
+	KDBUS_POLICY_ACCESS_USER,
+	KDBUS_POLICY_ACCESS_GROUP,
+	KDBUS_POLICY_ACCESS_WORLD,
+};
+
+/**
+ * enum kdbus_policy_access_flags - mode flags
+ * @KDBUS_POLICY_RECV:		Allow receive
+ * @KDBUS_POLICY_SEND:		Allow send
+ * @KDBUS_POLICY_OWN:		Allow to own a well-known name
+ */
+enum kdbus_policy_type {
+	KDBUS_POLICY_RECV		= 1 <<  2,
+	KDBUS_POLICY_SEND		= 1 <<  1,
+	KDBUS_POLICY_OWN		= 1 <<  0,
+};
+
+/**
+ * struct kdbus_cmd_policy - a series of policies to upload
+ * @size:		The total size of the structure
+ * @policies:		The policies to upload
+ *
+ * A KDBUS_POLICY_NAME must always preceeds a KDBUS_POLICY_ACCESS entry.
+ * A new KDBUS_POLICY_NAME can be added after KDBUS_POLICY_ACCESS for
+ * chaining multiple policies together.
+ */
+struct kdbus_cmd_policy {
+	__u64 size;
+	struct kdbus_item policies[0];
+} __attribute__((aligned(8)));
+
+/**
+ * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello
+ * @KDBUS_HELLO_ACCEPT_FD:	The connection allows the receiving of
+ *				any passed file descriptors
+ * @KDBUS_HELLO_ACTIVATOR:	Special-purpose connection which registers
+ *				a well-know name for a process to be started
+ *				when traffic arrives
+ * @KDBUS_HELLO_MONITOR:	Special-purpose connection to monitor
+ *				bus traffic
+ */
+enum kdbus_hello_flags {
+	KDBUS_HELLO_ACCEPT_FD		=  1 <<  0,
+	KDBUS_HELLO_ACTIVATOR		=  1 <<  1,
+	KDBUS_HELLO_MONITOR		=  1 <<  2,
+};
+
+/**
+ * enum kdbus_attach_flags - flags for metadata attachments
+ * @KDBUS_ATTACH_TIMESTAMP:	Timestamp
+ * @KDBUS_ATTACH_CREDS:		Credentials
+ * @KDBUS_ATTACH_NAMES:		Well-known names
+ * @KDBUS_ATTACH_COMM:		The "comm" process identifier
+ * @KDBUS_ATTACH_EXE:		The path of the executable
+ * @KDBUS_ATTACH_CMDLINE:	The process command line
+ * @KDBUS_ATTACH_CGROUP:	The croup membership
+ * @KDBUS_ATTACH_CAPS:		The process capabilities
+ * @KDBUS_ATTACH_SECLABEL:	The security label
+ * @KDBUS_ATTACH_AUDIT:		The audit IDs
+ * @KDBUS_ATTACH_CONN_NAME:	The human-readable connection name
+ */
+enum kdbus_attach_flags {
+	KDBUS_ATTACH_TIMESTAMP		=  1 <<  0,
+	KDBUS_ATTACH_CREDS		=  1 <<  1,
+	KDBUS_ATTACH_NAMES		=  1 <<  2,
+	KDBUS_ATTACH_COMM		=  1 <<  3,
+	KDBUS_ATTACH_EXE		=  1 <<  4,
+	KDBUS_ATTACH_CMDLINE		=  1 <<  5,
+	KDBUS_ATTACH_CGROUP		=  1 <<  6,
+	KDBUS_ATTACH_CAPS		=  1 <<  7,
+	KDBUS_ATTACH_SECLABEL		=  1 <<  8,
+	KDBUS_ATTACH_AUDIT		=  1 <<  9,
+	KDBUS_ATTACH_CONN_NAME		=  1 << 10,
+};
+
+/**
+ * struct kdbus_cmd_hello - struct to say hello to kdbus
+ * @size:		The total size of the structure
+ * @conn_flags:		Connection flags (KDBUS_HELLO_*). The kernel will
+ *			return its capabilities in that field.
+ * @attach_flags:	Mask of metadata to attach to each message sent
+ *			(KDBUS_ATTACH_*)
+ * @bus_flags:		The flags field copied verbatim from the original
+ *			KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful
+ *			to do negotiation of features of the payload that is
+ *			transferred (kernel → userspace)
+ * @id:			The ID of this connection (kernel → userspace)
+ * @bloom_size:		The bloom filter size chosen by the owner
+ *			(kernel → userspace)
+ * @pool_size:		Size of the connection's buffer where the received
+ *			messages are placed
+ * @id128:		Unique 128-bit ID of the bus (kernel → userspace)
+ * @items:		A list of items
+ *
+ * This struct is used with the KDBUS_CMD_HELLO ioctl.
+ */
+struct kdbus_cmd_hello {
+	__u64 size;
+	__u64 conn_flags;
+	__u64 attach_flags;
+	__u64 bus_flags;
+	__u64 id;
+	__u64 bloom_size;
+	__u64 pool_size;
+	__u8 id128[16];
+	struct kdbus_item items[0];
+} __attribute__((aligned(8)));
+
+/* Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE */
+enum kdbus_make_flags {
+	KDBUS_MAKE_ACCESS_GROUP		= 1 <<  0,
+	KDBUS_MAKE_ACCESS_WORLD		= 1 <<  1,
+	KDBUS_MAKE_POLICY_OPEN		= 1 <<  2,
+};
+
+/**
+ * struct kdbus_cmd_make - struct to make a bus, an endpoint or a namespace
+ * @size:		The total size of the struct
+ * @flags:		Properties for the bus/ep/ns to create
+ * @items:		Items describing details
+ *
+ * This structure is used with the KDBUS_CMD_BUS_MAKE, KDBUS_CMD_EP_MAKE and
+ * KDBUS_CMD_NS_MAKE ioctls.
+ */
+struct kdbus_cmd_make {
+	__u64 size;
+	__u64 flags;
+	struct kdbus_item items[0];
+} __attribute__((aligned(8)));
+
+/**
+ * enum kdbus_name_flags - properties of a well-known name
+ * @KDBUS_NAME_REPLACE_EXISTING:	Try to replace name of other connections
+ * @KDBUS_NAME_ALLOW_REPLACEMENT:	Allow the replacement of the name
+ * @KDBUS_NAME_QUEUE:			Name should be queued if busy
+ * @KDBUS_NAME_IN_QUEUE:		Name is queued
+ * @KDBUS_NAME_ACTIVATOR:		Name is owned by a activator connection
+ */
+enum kdbus_name_flags {
+	KDBUS_NAME_REPLACE_EXISTING	= 1 <<  0,
+	KDBUS_NAME_ALLOW_REPLACEMENT	= 1 <<  1,
+	KDBUS_NAME_QUEUE		= 1 <<  2,
+	KDBUS_NAME_IN_QUEUE		= 1 <<  3,
+	KDBUS_NAME_ACTIVATOR		= 1 <<  4,
+};
+
+/**
+ * struct kdbus_cmd_name - struct to describe a well-known name
+ * @size:		The total size of the struct
+ * @flags:		Flags for a name entry (KDBUS_NAME_*)
+ * @owner_id:		The current owner of the name. For requests,
+ *			privileged users may set this field to
+ *			(de)register names on behalf of other connections.
+ * @conn_flags:		The flags of the owning connection (KDBUS_HELLO_*)
+ * @name:		The well-known name
+ *
+ * This structure is used with the KDBUS_CMD_NAME_ACQUIRE ioctl.
+ */
+struct kdbus_cmd_name {
+	__u64 size;
+	__u64 flags;
+	__u64 owner_id;
+	__u64 conn_flags;
+	char name[0];
+} __attribute__((aligned(8)));
+
+/**
+ * enum kdbus_name_list_flags - what to include into the returned list
+ * @KDBUS_NAME_LIST_UNIQUE:	All active connections
+ * @KDBUS_NAME_LIST_NAMES:	All known well-known names
+ * @KDBUS_NAME_LIST_ACTIVATORS:	All activator connections
+ * @KDBUS_NAME_LIST_QUEUED:	All queued-up names
+ */
+enum kdbus_name_list_flags {
+	KDBUS_NAME_LIST_UNIQUE		= 1 <<  0,
+	KDBUS_NAME_LIST_NAMES		= 1 <<  1,
+	KDBUS_NAME_LIST_ACTIVATORS	= 1 <<  2,
+	KDBUS_NAME_LIST_QUEUED		= 1 <<  3,
+};
+
+/**
+ * struct kdbus_cmd_name_list - request a list of name entries
+ * @flags:		Flags for the query (KDBUS_NAME_LIST_*)
+ * @offset:		The returned offset in the caller's pool buffer.
+ *			The user must use KDBUS_CMD_FREE to free the
+ *			allocated memory.
+ *
+ * This structure is used with the KDBUS_CMD_NAME_LIST ioctl.
+ */
+struct kdbus_cmd_name_list {
+	__u64 flags;
+	__u64 offset;
+} __attribute__((aligned(8)));
+
+/**
+ * struct kdbus_name_list - information returned by KDBUS_CMD_NAME_LIST
+ * @size:		The total size of the structure
+ * @names:		A list of names
+ *
+ * Note that the user is responsible for freeing the allocated memory with
+ * the KDBUS_CMD_FREE ioctl.
+ */
+struct kdbus_name_list {
+	__u64 size;
+	struct kdbus_cmd_name names[0];
+};
+
+/**
+ * struct kdbus_cmd_conn_info - struct used for KDBUS_CMD_CONN_INFO ioctl
+ * @size:		The total size of the struct
+ * @flags:		KDBUS_ATTACH_* flags
+ * @id:			The 64-bit ID of the connection. If set to zero, passing
+ *			@name is required. kdbus will look up the name to
+ *			determine the ID in this case.
+ * @offset:		Returned offset in the caller's pool buffer where the
+ *			kdbus_conn_info struct result is stored. The user must
+ *			use KDBUS_CMD_FREE to free the allocated memory.
+ * @name:		The optional well-known name to look up. Only needed in
+ *			case @id is zero.
+ *
+ * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will
+ * tell the user the offset in the connection pool buffer at which to find the
+ * result in a struct kdbus_conn_info.
+ */
+struct kdbus_cmd_conn_info {
+	__u64 size;
+	__u64 flags;
+	__u64 id;
+	__u64 offset;
+	char name[0];
+} __attribute__((aligned(8)));
+
+/**
+ * struct kdbus_conn_info - information returned by KDBUS_CMD_CONN_INFO
+ * @size:		The total size of the struct
+ * @id:			The connection's 64-bit ID
+ * @flags:		The connection's flags
+ * @items:		A list of struct kdbus_item
+ *
+ * Note that the user is responsible for freeing the allocated memory with
+ * the KDBUS_CMD_FREE ioctl.
+ */
+struct kdbus_conn_info {
+	__u64 size;
+	__u64 id;
+	__u64 flags;
+	struct kdbus_item items[0];
+};
+
+/**
+ * struct kdbus_cmd_match - struct to add or remove matches
+ * @size:		The total size of the struct
+ * @owner_id:		Privileged users may (de)register matches on behalf
+ *			of other peers
+ * @cookie:		Userspace supplied cookie. When removing, the cookie
+ *			identifies the match to remove
+ * @items:		A list of items for additional information
+ *
+ * This structure is used with the KDBUS_CMD_ADD_MATCH and
+ * KDBUS_CMD_REMOVE_MATCH ioctl.
+ */
+struct kdbus_cmd_match {
+	__u64 size;
+	__u64 owner_id;
+	__u64 cookie;
+	struct kdbus_item items[0];
+} __attribute__((aligned(8)));
+
+/**
+ * struct kdbus_cmd_memfd_make - create a kdbus memfd
+ * @size:		The total size of the struct
+ * @file_size:		The initial file size
+ * @fd:			The returned file descriptor number
+ * @__pad:		Padding to ensure proper alignement
+ * @items:		A list of items for additional information
+ *
+ * This structure is used with the KDBUS_CMD_MEMFD_NEW ioctl.
+ */
+struct kdbus_cmd_memfd_make {
+	__u64 size;
+	__u64 file_size;
+	int fd;
+	__u32 __pad;
+	struct kdbus_item items[0];
+} __attribute__((aligned(8)));
+
+/**
+ * enum kdbus_ioctl_type - Ioctl API
+ * @KDBUS_CMD_BUS_MAKE:		After opening the "control" device node, this
+ *				command creates a new bus with the specified
+ *				name. The bus is immediately shut down and
+ *				cleaned up when the opened "control" device node
+ *				is closed.
+ * @KDBUS_CMD_NS_MAKE:		Similar to KDBUS_CMD_BUS_MAKE, but it creates a
+ *				new kdbus namespace.
+ * @KDBUS_CMD_EP_MAKE:		Creates a new named special endpoint to talk to
+ *				the bus. Such endpoints usually carry a more
+ *				restrictive policy and grant restricted access
+ *				to specific applications.
+ * @KDBUS_CMD_HELLO:		By opening the bus device node a connection is
+ *				created. After a HELLO the opened connection
+ *				becomes an active peer on the bus.
+ * @KDBUS_CMD_BYEBYE:		Disconnect a connection. If the connection's
+ *				message list is empty, the calls succeeds, and
+ *				the handle is rendered unusable. Otherwise,
+ *				-EAGAIN is returned without any further side-
+ *				effects.
+ * @KDBUS_CMD_MSG_SEND:		Send a message and pass data from userspace to
+ *				the kernel.
+ * @KDBUS_CMD_MSG_RECV:		Receive a message from the kernel which is
+ *				placed in the receiver's pool.
+ * @KDBUS_CMD_FREE:		Release the allocated memory in the receiver's
+ *				pool.
+ * @KDBUS_CMD_NAME_ACQUIRE:	Request a well-known bus name to associate with
+ *				the connection. Well-known names are used to
+ *				address a peer on the bus.
+ * @KDBUS_CMD_NAME_RELEASE:	Release a well-known name the connection
+ *				currently owns.
+ * @KDBUS_CMD_NAME_LIST:	Retrieve the list of all currently registered
+ *				well-known and unique names.
+ * @KDBUS_CMD_CONN_INFO:	Retrieve credentials and properties of the
+ *				initial creator of the connection. The data was
+ *				stored at registration time and does not
+ *				necessarily represent the connected process or
+ *				the actual state of the process.
+ * @KDBUS_CMD_MATCH_ADD:	Install a match which broadcast messages should
+ *				be delivered to the connection.
+ * @KDBUS_CMD_MATCH_REMOVE:	Remove a current match for broadcast messages.
+ * @KDBUS_CMD_EP_POLICY_SET:	Set the policy of an endpoint. It is used to
+ *				restrict the access for endpoints created with
+ *				KDBUS_CMD_EP_MAKE.
+ * @KDBUS_CMD_MEMFD_NEW:	Return a new file descriptor which provides an
+ *				anonymous shared memory file and which can be
+ *				used to pass around larger chunks of data.
+ *				Kdbus memfd files can be sealed, which allows
+ *				the receiver to trust the data it has received.
+ *				Kdbus memfd files expose only very limited
+ *				operations, they can be mmap()ed, seek()ed,
+ *				(p)read(v)() and (p)write(v)(); most other
+ *				common file operations are not implemented.
+ *				Special caution needs to be taken with
+ *				read(v)()/write(v)() on a shared file; the
+ *				underlying file position is always shared
+ *				between all users of the file and race against
+ *				each other, pread(v)()/pwrite(v)() avoid these
+ *				issues.
+ * @KDBUS_CMD_MEMFD_SIZE_GET:	Return the size of the underlying file, which
+ *				changes with write().
+ * @KDBUS_CMD_MEMFD_SIZE_SET:	Truncate the underlying file to the specified
+ *				size.
+ * @KDBUS_CMD_MEMFD_SEAL_GET:	Return the state of the file sealing.
+ * @KDBUS_CMD_MEMFD_SEAL_SET:	Seal or break a seal of the file. Only files
+ *				which are not shared with other processes and
+ *				which are currently not mapped can be sealed.
+ *				The current process needs to be the one and
+ *				single owner of the file, the sealing cannot
+ *				be changed as long as the file is shared.
+ */
+enum kdbus_ioctl_type {
+	KDBUS_CMD_BUS_MAKE =		_IOW (KDBUS_IOC_MAGIC, 0x00, struct kdbus_cmd_make),
+	KDBUS_CMD_NS_MAKE =		_IOR (KDBUS_IOC_MAGIC, 0x10, struct kdbus_cmd_make),
+	KDBUS_CMD_EP_MAKE =		_IOW (KDBUS_IOC_MAGIC, 0x20, struct kdbus_cmd_make),
+
+	KDBUS_CMD_HELLO =		_IOWR(KDBUS_IOC_MAGIC, 0x30, struct kdbus_cmd_hello),
+	KDBUS_CMD_BYEBYE =		_IO  (KDBUS_IOC_MAGIC, 0x31),
+
+	KDBUS_CMD_MSG_SEND =		_IOW (KDBUS_IOC_MAGIC, 0x40, struct kdbus_msg),
+	KDBUS_CMD_MSG_RECV =		_IOWR(KDBUS_IOC_MAGIC, 0x41, struct kdbus_cmd_recv),
+	KDBUS_CMD_FREE =		_IOW (KDBUS_IOC_MAGIC, 0x42, __u64 *),
+
+	KDBUS_CMD_NAME_ACQUIRE =	_IOWR(KDBUS_IOC_MAGIC, 0x50, struct kdbus_cmd_name),
+	KDBUS_CMD_NAME_RELEASE =	_IOW (KDBUS_IOC_MAGIC, 0x51, struct kdbus_cmd_name),
+	KDBUS_CMD_NAME_LIST =		_IOWR(KDBUS_IOC_MAGIC, 0x52, struct kdbus_cmd_name_list),
+
+	KDBUS_CMD_CONN_INFO =		_IOWR(KDBUS_IOC_MAGIC, 0x60, struct kdbus_cmd_conn_info),
+
+	KDBUS_CMD_MATCH_ADD =		_IOW (KDBUS_IOC_MAGIC, 0x70, struct kdbus_cmd_match),
+	KDBUS_CMD_MATCH_REMOVE =	_IOW (KDBUS_IOC_MAGIC, 0x71, struct kdbus_cmd_match),
+
+	KDBUS_CMD_EP_POLICY_SET =	_IOW (KDBUS_IOC_MAGIC, 0x80, struct kdbus_cmd_policy),
+
+	KDBUS_CMD_MEMFD_NEW =		_IOWR(KDBUS_IOC_MAGIC, 0xc0, struct kdbus_cmd_memfd_make),
+	KDBUS_CMD_MEMFD_SIZE_GET =	_IOR (KDBUS_IOC_MAGIC, 0xc1, __u64 *),
+	KDBUS_CMD_MEMFD_SIZE_SET =	_IOW (KDBUS_IOC_MAGIC, 0xc2, __u64 *),
+	KDBUS_CMD_MEMFD_SEAL_GET =	_IOR (KDBUS_IOC_MAGIC, 0xc3, int *),
+	KDBUS_CMD_MEMFD_SEAL_SET =	_IO  (KDBUS_IOC_MAGIC, 0xc4),
+};
+
+/*
+ * errno - api error codes
+ * @E2BIG:		A message contains too many records or items.
+ * @EADDRINUSE:		A well-known bus name is already taken by another
+ *			connection.
+ * @EADDRNOTAVAIL:	A message flagged not to activate a service, addressed
+ *			a service which is not currently running.
+ * @EAGAIN:		No messages are queued at the moment.
+ * @EBADF:		File descriptors passed with the message are not valid.
+ * @EBADFD:		A bus connection is in a corrupted state.
+ * @EBADMSG:		Passed data contains a combination of conflicting or
+ *			inconsistent types.
+ * @EBUSY:		The user tried to say BYEBYE to a connection, but the
+ *			connection had a non-empty message list.
+ * @ECONNRESET:		A connection is shut down, no further operations are
+ *			possible.
+ * @ECOMM:		A peer does not accept the file descriptors addressed
+ *			to it.
+ * @EDESTADDRREQ:	The well-known bus name is required but missing.
+ * @EDOM:		The size of data does not match the expectations. Used
+ *			for the size of the bloom filter bit field.
+ * @EEXIST:		A requested namespace, bus or endpoint with the same
+ *			name already exists.  A specific data type, which is
+ *			only expected once, is provided multiple times.
+ * @EFAULT:		The supplied memory could not be accessed, or the data
+ *			is not properly aligned.
+ * @EINVAL:		The provided data does not match its type or other
+ *			expectations, like a string which is not NUL terminated,
+ *			or a string length that points behind the first
+ *			\0-byte in the string.
+ * @EMEDIUMTYPE:	A file descriptor which is not a kdbus memfd was
+ *			refused to send as KDBUS_MSG_PAYLOAD_MEMFD.
+ * @EMFILE:		Too many file descriptors have been supplied with a
+ *			message.
+ * @EMLINK:		Too many requests from this connection to other peers
+ *			are queued and waiting for a reply
+ * @EMSGSIZE:		The supplied data is larger than the allowed maximum
+ *			size.
+ * @ENAMETOOLONG:	The requested name is larger than the allowed maximum
+ *			size.
+ * @ENOBUFS:		There is no space left for the submitted data to fit
+ *			into the receiver's pool.
+ * @ENOENT:		The name to query information about is currently not on
+ *			the bus.
+ * @ENOMEM:		Out of memory.
+ * @ENOMSG:		The queue is not empty, but no message with a matching
+ * 			priority is currently queued.
+ * @ENOSYS:		The requested functionality is not available.
+ * @ENOTSUPP:		The feature negotiation failed, a not supported feature
+ *			was requested, or an unknown item type was received.
+ * @ENOTTY:		An unknown ioctl command was received.
+ * @ENOTUNIQ:		A specific data type was addressed to a broadcast
+ *			address, but only direct addresses support this kind of
+ *			data.
+ * @ENXIO:		A unique address does not exist, or an offset in the
+ *			receiver's pool does not represent a queued message.
+ * @EPERM:		The policy prevented an operation. The requested
+ *			resource is owned by another entity.
+ * @ESHUTDOWN:		A namespace or endpoint is currently shutting down;
+ *			no further operations will be possible.
+ * @ESRCH:		A requested well-known bus name is not found.
+ * @ETXTBSY:		A kdbus memfd file cannot be sealed or the seal removed,
+ *			because it is shared with other processes or still
+ *			mmap()ed.
+ * @EXFULL:		The size limits in the pool are reached, no data of
+ *			the size tried to submit can be queued.
+ */
+#endif
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
new file mode 100644
index 0000000..95d80db
--- /dev/null
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -0,0 +1,3032 @@
+/*-*- 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 <endian.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/poll.h>
+#include <byteswap.h>
+#include <sys/mman.h>
+#include <pthread.h>
+
+#include "util.h"
+#include "macro.h"
+#include "strv.h"
+#include "set.h"
+#include "missing.h"
+#include "def.h"
+
+#include "sd-bus.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-type.h"
+#include "bus-socket.h"
+#include "bus-kernel.h"
+#include "bus-control.h"
+#include "bus-introspect.h"
+#include "bus-signature.h"
+#include "bus-objects.h"
+#include "bus-util.h"
+#include "bus-container.h"
+#include "bus-protocol.h"
+
+static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
+static int attach_io_events(sd_bus *b);
+static void detach_io_events(sd_bus *b);
+
+static void bus_close_fds(sd_bus *b) {
+        assert(b);
+
+        detach_io_events(b);
+
+        if (b->input_fd >= 0)
+                close_nointr_nofail(b->input_fd);
+
+        if (b->output_fd >= 0 && b->output_fd != b->input_fd)
+                close_nointr_nofail(b->output_fd);
+
+        b->input_fd = b->output_fd = -1;
+}
+
+static void bus_node_destroy(sd_bus *b, struct node *n) {
+        struct node_callback *c;
+        struct node_vtable *v;
+        struct node_enumerator *e;
+
+        assert(b);
+
+        if (!n)
+                return;
+
+        while (n->child)
+                bus_node_destroy(b, n->child);
+
+        while ((c = n->callbacks)) {
+                LIST_REMOVE(callbacks, n->callbacks, c);
+                free(c);
+        }
+
+        while ((v = n->vtables)) {
+                LIST_REMOVE(vtables, n->vtables, v);
+                free(v->interface);
+                free(v);
+        }
+
+        while ((e = n->enumerators)) {
+                LIST_REMOVE(enumerators, n->enumerators, e);
+                free(e);
+        }
+
+        if (n->parent)
+                LIST_REMOVE(siblings, n->parent->child, n);
+
+        assert_se(hashmap_remove(b->nodes, n->path) == n);
+        free(n->path);
+        free(n);
+}
+
+static void bus_reset_queues(sd_bus *b) {
+        unsigned i;
+
+        assert(b);
+
+        for (i = 0; i < b->rqueue_size; i++)
+                sd_bus_message_unref(b->rqueue[i]);
+        free(b->rqueue);
+
+        for (i = 0; i < b->wqueue_size; i++)
+                sd_bus_message_unref(b->wqueue[i]);
+        free(b->wqueue);
+
+        b->rqueue = b->wqueue = NULL;
+        b->rqueue_allocated = b->wqueue_allocated = 0;
+        b->rqueue_size = b->wqueue_size = 0;
+}
+
+static void bus_free(sd_bus *b) {
+        struct filter_callback *f;
+        struct node *n;
+
+        assert(b);
+
+        sd_bus_detach_event(b);
+
+        bus_close_fds(b);
+
+        if (b->kdbus_buffer)
+                munmap(b->kdbus_buffer, KDBUS_POOL_SIZE);
+
+        free(b->rbuffer);
+        free(b->unique_name);
+        free(b->auth_buffer);
+        free(b->address);
+        free(b->kernel);
+        free(b->machine);
+        free(b->fake_label);
+        free(b->cgroup_root);
+
+        free(b->exec_path);
+        strv_free(b->exec_argv);
+
+        close_many(b->fds, b->n_fds);
+        free(b->fds);
+
+        bus_reset_queues(b);
+
+        hashmap_free_free(b->reply_callbacks);
+        prioq_free(b->reply_callbacks_prioq);
+
+        while ((f = b->filter_callbacks)) {
+                LIST_REMOVE(callbacks, b->filter_callbacks, f);
+                free(f);
+        }
+
+        bus_match_free(&b->match_callbacks);
+
+        hashmap_free_free(b->vtable_methods);
+        hashmap_free_free(b->vtable_properties);
+
+        while ((n = hashmap_first(b->nodes)))
+                bus_node_destroy(b, n);
+
+        hashmap_free(b->nodes);
+
+        bus_kernel_flush_memfd(b);
+
+        assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0);
+
+        free(b);
+}
+
+_public_ int sd_bus_new(sd_bus **ret) {
+        sd_bus *r;
+
+        assert_return(ret, -EINVAL);
+
+        r = new0(sd_bus, 1);
+        if (!r)
+                return -ENOMEM;
+
+        r->n_ref = REFCNT_INIT;
+        r->input_fd = r->output_fd = -1;
+        r->message_version = 1;
+        r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
+        r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
+        r->attach_flags |= KDBUS_ATTACH_NAMES;
+        r->original_pid = getpid();
+
+        assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0);
+
+        /* We guarantee that wqueue always has space for at least one
+         * entry */
+        if (!GREEDY_REALLOC(r->wqueue, r->wqueue_allocated, 1)) {
+                free(r);
+                return -ENOMEM;
+        }
+
+        *ret = r;
+        return 0;
+}
+
+_public_ int sd_bus_set_address(sd_bus *bus, const char *address) {
+        char *a;
+
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(address, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        a = strdup(address);
+        if (!a)
+                return -ENOMEM;
+
+        free(bus->address);
+        bus->address = a;
+
+        return 0;
+}
+
+_public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(input_fd >= 0, -EINVAL);
+        assert_return(output_fd >= 0, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        bus->input_fd = input_fd;
+        bus->output_fd = output_fd;
+        return 0;
+}
+
+_public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
+        char *p, **a;
+
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(path, -EINVAL);
+        assert_return(!strv_isempty(argv), -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        p = strdup(path);
+        if (!p)
+                return -ENOMEM;
+
+        a = strv_copy(argv);
+        if (!a) {
+                free(p);
+                return -ENOMEM;
+        }
+
+        free(bus->exec_path);
+        strv_free(bus->exec_argv);
+
+        bus->exec_path = p;
+        bus->exec_argv = a;
+
+        return 0;
+}
+
+_public_ int sd_bus_set_bus_client(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        bus->bus_client = !!b;
+        return 0;
+}
+
+_public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b);
+        return 0;
+}
+
+_public_ int sd_bus_negotiate_attach_timestamp(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        SET_FLAG(bus->attach_flags, KDBUS_ATTACH_TIMESTAMP, b);
+        return 0;
+}
+
+_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t mask) {
+        assert_return(bus, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        /* The well knowns we need unconditionally, so that matches can work */
+        bus->creds_mask = mask | SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
+
+        return kdbus_translate_attach_flags(bus->creds_mask, &bus->creds_mask);
+}
+
+_public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
+        assert_return(bus, -EINVAL);
+        assert_return(b || sd_id128_equal(server_id, SD_ID128_NULL), -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        bus->is_server = !!b;
+        bus->server_id = server_id;
+        return 0;
+}
+
+_public_ int sd_bus_set_anonymous(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        bus->anonymous_auth = !!b;
+        return 0;
+}
+
+_public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        bus->trusted = !!b;
+        return 0;
+}
+
+static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+        const char *s;
+        int r;
+
+        assert(bus);
+        assert(bus->state == BUS_HELLO || bus->state == BUS_CLOSING);
+        assert(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)
+                return r;
+
+        if (!service_name_is_valid(s) || s[0] != ':')
+                return -EBADMSG;
+
+        bus->unique_name = strdup(s);
+        if (!bus->unique_name)
+                return -ENOMEM;
+
+        if (bus->state == BUS_HELLO)
+                bus->state = BUS_RUNNING;
+
+        return 1;
+}
+
+static int bus_send_hello(sd_bus *bus) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert(bus);
+
+        if (!bus->bus_client || bus->is_kernel)
+                return 0;
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "Hello",
+                        &m);
+        if (r < 0)
+                return r;
+
+        return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_cookie);
+}
+
+int bus_start_running(sd_bus *bus) {
+        assert(bus);
+
+        if (bus->bus_client && !bus->is_kernel) {
+                bus->state = BUS_HELLO;
+                return 1;
+        }
+
+        bus->state = BUS_RUNNING;
+        return 1;
+}
+
+static int parse_address_key(const char **p, const char *key, char **value) {
+        size_t l, n = 0, allocated = 0;
+        const char *a;
+        char *r = NULL;
+
+        assert(p);
+        assert(*p);
+        assert(value);
+
+        if (key) {
+                l = strlen(key);
+                if (strncmp(*p, key, l) != 0)
+                        return 0;
+
+                if ((*p)[l] != '=')
+                        return 0;
+
+                if (*value)
+                        return -EINVAL;
+
+                a = *p + l + 1;
+        } else
+                a = *p;
+
+        while (*a != ';' && *a != ',' && *a != 0) {
+                char c;
+
+                if (*a == '%') {
+                        int x, y;
+
+                        x = unhexchar(a[1]);
+                        if (x < 0) {
+                                free(r);
+                                return x;
+                        }
+
+                        y = unhexchar(a[2]);
+                        if (y < 0) {
+                                free(r);
+                                return y;
+                        }
+
+                        c = (char) ((x << 4) | y);
+                        a += 3;
+                } else {
+                        c = *a;
+                        a++;
+                }
+
+                if (!GREEDY_REALLOC(r, allocated, n + 2))
+                        return -ENOMEM;
+
+                r[n++] = c;
+        }
+
+        if (!r) {
+                r = strdup("");
+                if (!r)
+                        return -ENOMEM;
+        } else
+                r[n] = 0;
+
+        if (*a == ',')
+                a++;
+
+        *p = a;
+
+        free(*value);
+        *value = r;
+
+        return 1;
+}
+
+static void skip_address_key(const char **p) {
+        assert(p);
+        assert(*p);
+
+        *p += strcspn(*p, ",");
+
+        if (**p == ',')
+                (*p) ++;
+}
+
+static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
+        _cleanup_free_ char *path = NULL, *abstract = NULL;
+        size_t l;
+        int r;
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "path", &path);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "abstract", &abstract);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                skip_address_key(p);
+        }
+
+        if (!path && !abstract)
+                return -EINVAL;
+
+        if (path && abstract)
+                return -EINVAL;
+
+        if (path) {
+                l = strlen(path);
+                if (l > sizeof(b->sockaddr.un.sun_path))
+                        return -E2BIG;
+
+                b->sockaddr.un.sun_family = AF_UNIX;
+                strncpy(b->sockaddr.un.sun_path, path, sizeof(b->sockaddr.un.sun_path));
+                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l;
+        } else if (abstract) {
+                l = strlen(abstract);
+                if (l > sizeof(b->sockaddr.un.sun_path) - 1)
+                        return -E2BIG;
+
+                b->sockaddr.un.sun_family = AF_UNIX;
+                b->sockaddr.un.sun_path[0] = 0;
+                strncpy(b->sockaddr.un.sun_path+1, abstract, sizeof(b->sockaddr.un.sun_path)-1);
+                b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
+        }
+
+        return 0;
+}
+
+static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
+        _cleanup_free_ char *host = NULL, *port = NULL, *family = NULL;
+        int r;
+        struct addrinfo *result, hints = {
+                .ai_socktype = SOCK_STREAM,
+                .ai_flags = AI_ADDRCONFIG,
+        };
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "host", &host);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "port", &port);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "family", &family);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                skip_address_key(p);
+        }
+
+        if (!host || !port)
+                return -EINVAL;
+
+        if (family) {
+                if (streq(family, "ipv4"))
+                        hints.ai_family = AF_INET;
+                else if (streq(family, "ipv6"))
+                        hints.ai_family = AF_INET6;
+                else
+                        return -EINVAL;
+        }
+
+        r = getaddrinfo(host, port, &hints, &result);
+        if (r == EAI_SYSTEM)
+                return -errno;
+        else if (r != 0)
+                return -EADDRNOTAVAIL;
+
+        memcpy(&b->sockaddr, result->ai_addr, result->ai_addrlen);
+        b->sockaddr_size = result->ai_addrlen;
+
+        freeaddrinfo(result);
+
+        return 0;
+}
+
+static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
+        char *path = NULL;
+        unsigned n_argv = 0, j;
+        char **argv = NULL;
+        size_t allocated = 0;
+        int r;
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        goto fail;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "path", &path);
+                if (r < 0)
+                        goto fail;
+                else if (r > 0)
+                        continue;
+
+                if (startswith(*p, "argv")) {
+                        unsigned ul;
+
+                        errno = 0;
+                        ul = strtoul(*p + 4, (char**) p, 10);
+                        if (errno > 0 || **p != '=' || ul > 256) {
+                                r = -EINVAL;
+                                goto fail;
+                        }
+
+                        (*p) ++;
+
+                        if (ul >= n_argv) {
+                                if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                n_argv = ul + 1;
+                        }
+
+                        r = parse_address_key(p, NULL, argv + ul);
+                        if (r < 0)
+                                goto fail;
+
+                        continue;
+                }
+
+                skip_address_key(p);
+        }
+
+        if (!path) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        /* Make sure there are no holes in the array, with the
+         * exception of argv[0] */
+        for (j = 1; j < n_argv; j++)
+                if (!argv[j]) {
+                        r = -EINVAL;
+                        goto fail;
+                }
+
+        if (argv && argv[0] == NULL) {
+                argv[0] = strdup(path);
+                if (!argv[0]) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        b->exec_path = path;
+        b->exec_argv = argv;
+        return 0;
+
+fail:
+        for (j = 0; j < n_argv; j++)
+                free(argv[j]);
+
+        free(argv);
+        free(path);
+        return r;
+}
+
+static int parse_kernel_address(sd_bus *b, const char **p, char **guid) {
+        _cleanup_free_ char *path = NULL;
+        int r;
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "path", &path);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                skip_address_key(p);
+        }
+
+        if (!path)
+                return -EINVAL;
+
+        free(b->kernel);
+        b->kernel = path;
+        path = NULL;
+
+        return 0;
+}
+
+static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) {
+        _cleanup_free_ char *machine = NULL;
+        int r;
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "machine", &machine);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                skip_address_key(p);
+        }
+
+        if (!machine)
+                return -EINVAL;
+
+        if (!filename_is_safe(machine))
+                return -EINVAL;
+
+        free(b->machine);
+        b->machine = machine;
+        machine = NULL;
+
+        b->sockaddr.un.sun_family = AF_UNIX;
+        strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
+        b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/var/run/dbus/system_bus_socket") - 1;
+
+        return 0;
+}
+
+static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) {
+        _cleanup_free_ char *machine = NULL;
+        int r;
+
+        assert(b);
+        assert(p);
+        assert(*p);
+        assert(guid);
+
+        while (**p != 0 && **p != ';') {
+                r = parse_address_key(p, "guid", guid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_address_key(p, "machine", &machine);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                skip_address_key(p);
+        }
+
+        if (!machine)
+                return -EINVAL;
+
+        if (!filename_is_safe(machine))
+                return -EINVAL;
+
+        free(b->machine);
+        b->machine = machine;
+        machine = NULL;
+
+        free(b->kernel);
+        b->kernel = strdup("/dev/kdbus/0-system/bus");
+        if (!b->kernel)
+                return -ENOMEM;
+
+        return 0;
+}
+
+static void bus_reset_parsed_address(sd_bus *b) {
+        assert(b);
+
+        zero(b->sockaddr);
+        b->sockaddr_size = 0;
+        strv_free(b->exec_argv);
+        free(b->exec_path);
+        b->exec_path = NULL;
+        b->exec_argv = NULL;
+        b->server_id = SD_ID128_NULL;
+        free(b->kernel);
+        b->kernel = NULL;
+        free(b->machine);
+        b->machine = NULL;
+}
+
+static int bus_parse_next_address(sd_bus *b) {
+        _cleanup_free_ char *guid = NULL;
+        const char *a;
+        int r;
+
+        assert(b);
+
+        if (!b->address)
+                return 0;
+        if (b->address[b->address_index] == 0)
+                return 0;
+
+        bus_reset_parsed_address(b);
+
+        a = b->address + b->address_index;
+
+        while (*a != 0) {
+
+                if (*a == ';') {
+                        a++;
+                        continue;
+                }
+
+                if (startswith(a, "unix:")) {
+                        a += 5;
+
+                        r = parse_unix_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+                        break;
+
+                } else if (startswith(a, "tcp:")) {
+
+                        a += 4;
+                        r = parse_tcp_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
+                } else if (startswith(a, "unixexec:")) {
+
+                        a += 9;
+                        r = parse_exec_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
+                } else if (startswith(a, "kernel:")) {
+
+                        a += 7;
+                        r = parse_kernel_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                } else if (startswith(a, "x-container-unix:")) {
+
+                        a += 17;
+                        r = parse_container_unix_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                } else if (startswith(a, "x-container-kernel:")) {
+
+                        a += 19;
+                        r = parse_container_kernel_address(b, &a, &guid);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                }
+
+                a = strchr(a, ';');
+                if (!a)
+                        return 0;
+        }
+
+        if (guid) {
+                r = sd_id128_from_string(guid, &b->server_id);
+                if (r < 0)
+                        return r;
+        }
+
+        b->address_index = a - b->address;
+        return 1;
+}
+
+static int bus_start_address(sd_bus *b) {
+        int r;
+
+        assert(b);
+
+        for (;;) {
+                bool skipped = false;
+
+                bus_close_fds(b);
+
+                if (b->exec_path)
+                        r = bus_socket_exec(b);
+                else if (b->machine && b->kernel)
+                        r = bus_container_connect_kernel(b);
+                else if (b->machine && b->sockaddr.sa.sa_family != AF_UNSPEC)
+                        r = bus_container_connect_socket(b);
+                else if (b->kernel)
+                        r = bus_kernel_connect(b);
+                else if (b->sockaddr.sa.sa_family != AF_UNSPEC)
+                        r = bus_socket_connect(b);
+                else
+                        skipped = true;
+
+                if (!skipped) {
+                        if (r >= 0) {
+                                r = attach_io_events(b);
+                                if (r >= 0)
+                                        return r;
+                        }
+
+                        b->last_connect_error = -r;
+                }
+
+                r = bus_parse_next_address(b);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED;
+        }
+}
+
+int bus_next_address(sd_bus *b) {
+        assert(b);
+
+        bus_reset_parsed_address(b);
+        return bus_start_address(b);
+}
+
+static int bus_start_fd(sd_bus *b) {
+        struct stat st;
+        int r;
+
+        assert(b);
+        assert(b->input_fd >= 0);
+        assert(b->output_fd >= 0);
+
+        r = fd_nonblock(b->input_fd, true);
+        if (r < 0)
+                return r;
+
+        r = fd_cloexec(b->input_fd, true);
+        if (r < 0)
+                return r;
+
+        if (b->input_fd != b->output_fd) {
+                r = fd_nonblock(b->output_fd, true);
+                if (r < 0)
+                        return r;
+
+                r = fd_cloexec(b->output_fd, true);
+                if (r < 0)
+                        return r;
+        }
+
+        if (fstat(b->input_fd, &st) < 0)
+                return -errno;
+
+        if (S_ISCHR(b->input_fd))
+                return bus_kernel_take_fd(b);
+        else
+                return bus_socket_take_fd(b);
+}
+
+_public_ int sd_bus_start(sd_bus *bus) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state == BUS_UNSET, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        bus->state = BUS_OPENING;
+
+        if (bus->is_server && bus->bus_client)
+                return -EINVAL;
+
+        if (bus->input_fd >= 0)
+                r = bus_start_fd(bus);
+        else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel || bus->machine)
+                r = bus_start_address(bus);
+        else
+                return -EINVAL;
+
+        if (r < 0)
+                return r;
+
+        return bus_send_hello(bus);
+}
+
+_public_ int sd_bus_open_system(sd_bus **ret) {
+        const char *e;
+        sd_bus *b;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        r = sd_bus_new(&b);
+        if (r < 0)
+                return r;
+
+        e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
+        if (e)
+                r = sd_bus_set_address(b, e);
+        else
+                r = sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_PATH);
+        if (r < 0)
+                goto fail;
+
+        b->bus_client = true;
+
+        /* Let's do per-method access control on the system bus. We
+         * need the caller's UID and capability set for that. */
+        b->trusted = false;
+        b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
+
+        r = sd_bus_start(b);
+        if (r < 0)
+                goto fail;
+
+        *ret = b;
+        return 0;
+
+fail:
+        bus_free(b);
+        return r;
+}
+
+_public_ int sd_bus_open_user(sd_bus **ret) {
+        const char *e;
+        sd_bus *b;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        r = sd_bus_new(&b);
+        if (r < 0)
+                return r;
+
+        e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
+        if (e) {
+                r = sd_bus_set_address(b, e);
+                if (r < 0)
+                        goto fail;
+        } else {
+                e = secure_getenv("XDG_RUNTIME_DIR");
+                if (e) {
+                        _cleanup_free_ char *ee = NULL;
+
+                        ee = bus_address_escape(e);
+                        if (!ee) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+#ifdef ENABLE_KDBUS
+                        asprintf(&b->address, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, (unsigned long) getuid(), ee);
+#else
+                        asprintf(&b->address, UNIX_USER_BUS_FMT, ee);
+#endif
+                } else {
+#ifdef ENABLE_KDBUS
+                        asprintf(&b->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid());
+#else
+                        return -ECONNREFUSED;
+#endif
+                }
+
+                if (!b->address) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        b->bus_client = true;
+
+        /* We don't do any per-method access control on the user
+         * bus. */
+        b->trusted = true;
+
+        r = sd_bus_start(b);
+        if (r < 0)
+                goto fail;
+
+        *ret = b;
+        return 0;
+
+fail:
+        bus_free(b);
+        return r;
+}
+
+_public_ int sd_bus_open_system_remote(const char *host, sd_bus **ret) {
+        _cleanup_free_ char *e = NULL;
+        char *p = NULL;
+        sd_bus *bus;
+        int r;
+
+        assert_return(host, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        e = bus_address_escape(host);
+        if (!e)
+                return -ENOMEM;
+
+        p = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL);
+        if (!p)
+                return -ENOMEM;
+
+        r = sd_bus_new(&bus);
+        if (r < 0) {
+                free(p);
+                return r;
+        }
+
+        bus->address = p;
+        bus->bus_client = true;
+
+        r = sd_bus_start(bus);
+        if (r < 0) {
+                bus_free(bus);
+                return r;
+        }
+
+        *ret = bus;
+        return 0;
+}
+
+_public_ int sd_bus_open_system_container(const char *machine, sd_bus **ret) {
+        _cleanup_free_ char *e = NULL;
+        sd_bus *bus;
+        char *p;
+        int r;
+
+        assert_return(machine, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(filename_is_safe(machine), -EINVAL);
+
+        e = bus_address_escape(machine);
+        if (!e)
+                return -ENOMEM;
+
+#ifdef ENABLE_KDBUS
+        p = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
+#else
+        p = strjoin("x-container-unix:machine=", e, NULL);
+#endif
+        if (!p)
+                return -ENOMEM;
+
+        r = sd_bus_new(&bus);
+        if (r < 0) {
+                free(p);
+                return r;
+        }
+
+        bus->address = p;
+        bus->bus_client = true;
+
+        r = sd_bus_start(bus);
+        if (r < 0) {
+                bus_free(bus);
+                return r;
+        }
+
+        *ret = bus;
+        return 0;
+}
+
+_public_ void sd_bus_close(sd_bus *bus) {
+
+        if (!bus)
+                return;
+        if (bus->state == BUS_CLOSED)
+                return;
+        if (bus_pid_changed(bus))
+                return;
+
+        bus->state = BUS_CLOSED;
+
+        sd_bus_detach_event(bus);
+
+        /* Drop all queued messages so that they drop references to
+         * the bus object and the bus may be freed */
+        bus_reset_queues(bus);
+
+        if (!bus->is_kernel)
+                bus_close_fds(bus);
+
+        /* We'll leave the fd open in case this is a kernel bus, since
+         * there might still be memblocks around that reference this
+         * bus, and they might need to invoke the KDBUS_CMD_FREE
+         * ioctl on the fd when they are freed. */
+}
+
+static void bus_enter_closing(sd_bus *bus) {
+        assert(bus);
+
+        if (bus->state != BUS_OPENING &&
+            bus->state != BUS_AUTHENTICATING &&
+            bus->state != BUS_HELLO &&
+            bus->state != BUS_RUNNING)
+                return;
+
+        bus->state = BUS_CLOSING;
+}
+
+_public_ sd_bus *sd_bus_ref(sd_bus *bus) {
+        assert_return(bus, NULL);
+
+        assert_se(REFCNT_INC(bus->n_ref) >= 2);
+
+        return bus;
+}
+
+_public_ sd_bus *sd_bus_unref(sd_bus *bus) {
+        unsigned i;
+
+        if (!bus)
+                return NULL;
+
+        i = REFCNT_DEC(bus->n_ref);
+        if (i != bus->rqueue_size + bus->wqueue_size)
+                return NULL;
+
+        for (i = 0; i < bus->rqueue_size; i++)
+                if (bus->rqueue[i]->n_ref > 1)
+                        return NULL;
+
+        for (i = 0; i < bus->wqueue_size; i++)
+                if (bus->wqueue[i]->n_ref > 1)
+                        return NULL;
+
+        /* we are the only holders on the messages */
+        bus_free(bus);
+
+        return NULL;
+}
+
+_public_ int sd_bus_is_open(sd_bus *bus) {
+
+        assert_return(bus, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        return BUS_IS_OPEN(bus->state);
+}
+
+_public_ int sd_bus_can_send(sd_bus *bus, char type) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (type == SD_BUS_TYPE_UNIX_FD) {
+                if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD))
+                        return 0;
+
+                r = bus_ensure_running(bus);
+                if (r < 0)
+                        return r;
+
+                return bus->can_fds;
+        }
+
+        return bus_type_is_valid(type);
+}
+
+_public_ int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(server_id, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = bus_ensure_running(bus);
+        if (r < 0)
+                return r;
+
+        *server_id = bus->server_id;
+        return 0;
+}
+
+static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
+        assert(b);
+        assert(m);
+
+        if (m->sealed) {
+                /* If we copy the same message to multiple
+                 * destinations, avoid using the same cookie
+                 * numbers. */
+                b->cookie = MAX(b->cookie, BUS_MESSAGE_COOKIE(m));
+                return 0;
+        }
+
+        if (timeout == 0)
+                timeout = BUS_DEFAULT_TIMEOUT;
+
+        return bus_message_seal(m, ++b->cookie, timeout);
+}
+
+static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
+        assert(b);
+
+        /* Do packet version and endianess already match? */
+        if ((b->message_version == 0 || b->message_version == (*m)->header->version) &&
+            (b->message_endian == 0 || b->message_endian == (*m)->header->endian))
+                return 0;
+
+        /* No? Then remarshal! */
+        return bus_message_remarshal(b, m);
+}
+
+int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
+        assert(b);
+        assert(m);
+
+        /* The bus specification says the serial number cannot be 0,
+         * hence let's fill something in for synthetic messages. Since
+         * synthetic messages might have a fake sender and we don't
+         * want to interfere with the real sender's serial numbers we
+         * pick a fixed, artifical one. We use (uint32_t) -1 rather
+         * than (uint64_t) -1 since dbus1 only had 32bit identifiers,
+         * even though kdbus can do 64bit. */
+
+        return bus_message_seal(m, 0xFFFFFFFFULL, 0);
+}
+
+static int bus_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
+        int r;
+
+        assert(bus);
+        assert(m);
+
+        if (bus->is_kernel)
+                r = bus_kernel_write_message(bus, m);
+        else
+                r = bus_socket_write_message(bus, m, idx);
+
+        if (r <= 0)
+                return r;
+
+        if (bus->is_kernel || *idx >= BUS_MESSAGE_SIZE(m))
+                log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s",
+                          bus_message_type_to_string(m->header->type),
+                          strna(sd_bus_message_get_sender(m)),
+                          strna(sd_bus_message_get_destination(m)),
+                          strna(sd_bus_message_get_path(m)),
+                          strna(sd_bus_message_get_interface(m)),
+                          strna(sd_bus_message_get_member(m)),
+                          (unsigned long) BUS_MESSAGE_COOKIE(m),
+                          (unsigned long) m->reply_cookie,
+                          strna(m->error.message));
+
+        return r;
+}
+
+static int dispatch_wqueue(sd_bus *bus) {
+        int r, ret = 0;
+
+        assert(bus);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        while (bus->wqueue_size > 0) {
+
+                r = bus_write_message(bus, bus->wqueue[0], &bus->windex);
+                if (r < 0)
+                        return r;
+                else if (r == 0)
+                        /* Didn't do anything this time */
+                        return ret;
+                else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
+                        /* Fully written. Let's drop the entry from
+                         * the queue.
+                         *
+                         * This isn't particularly optimized, but
+                         * well, this is supposed to be our worst-case
+                         * buffer only, and the socket buffer is
+                         * supposed to be our primary buffer, and if
+                         * it got full, then all bets are off
+                         * anyway. */
+
+                        bus->wqueue_size --;
+                        sd_bus_message_unref(bus->wqueue[0]);
+                        memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
+                        bus->windex = 0;
+
+                        ret = 1;
+                }
+        }
+
+        return ret;
+}
+
+static int bus_read_message(sd_bus *bus) {
+        assert(bus);
+
+        if (bus->is_kernel)
+                return bus_kernel_read_message(bus);
+        else
+                return bus_socket_read_message(bus);
+}
+
+int bus_rqueue_make_room(sd_bus *bus) {
+        assert(bus);
+
+        if (bus->rqueue_size >= BUS_RQUEUE_MAX)
+                return -ENOBUFS;
+
+        if (!GREEDY_REALLOC(bus->rqueue, bus->rqueue_allocated, bus->rqueue_size + 1))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
+        int r, ret = 0;
+
+        assert(bus);
+        assert(m);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        for (;;) {
+                if (bus->rqueue_size > 0) {
+                        /* Dispatch a queued message */
+
+                        *m = bus->rqueue[0];
+                        bus->rqueue_size --;
+                        memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
+                        return 1;
+                }
+
+                /* Try to read a new message */
+                r = bus_read_message(bus);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return ret;
+
+                ret = 1;
+        }
+}
+
+_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(m, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (m->n_fds > 0) {
+                r = sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -ENOTSUP;
+        }
+
+        /* If the cookie number isn't kept, then we know that no reply
+         * is expected */
+        if (!cookie && !m->sealed)
+                m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+
+        r = bus_seal_message(bus, m, 0);
+        if (r < 0)
+                return r;
+
+        /* Remarshall if we have to. This will possibly unref the
+         * message and place a replacement in m */
+        r = bus_remarshal_message(bus, &m);
+        if (r < 0)
+                return r;
+
+        /* If this is a reply and no reply was requested, then let's
+         * suppress this, if we can */
+        if (m->dont_send && !cookie)
+                return 1;
+
+        if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
+                size_t idx = 0;
+
+                r = bus_write_message(bus, m, &idx);
+                if (r < 0) {
+                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                                bus_enter_closing(bus);
+                                return -ECONNRESET;
+                        }
+
+                        return r;
+                } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m))  {
+                        /* Wasn't fully written. So let's remember how
+                         * much was written. Note that the first entry
+                         * of the wqueue array is always allocated so
+                         * that we always can remember how much was
+                         * written. */
+                        bus->wqueue[0] = sd_bus_message_ref(m);
+                        bus->wqueue_size = 1;
+                        bus->windex = idx;
+                }
+        } else {
+                /* Just append it to the queue. */
+
+                if (bus->wqueue_size >= BUS_WQUEUE_MAX)
+                        return -ENOBUFS;
+
+                if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
+                        return -ENOMEM;
+
+                bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m);
+        }
+
+        if (cookie)
+                *cookie = BUS_MESSAGE_COOKIE(m);
+
+        return 1;
+}
+
+_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(m, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (!streq_ptr(m->destination, destination)) {
+
+                if (!destination)
+                        return -EEXIST;
+
+                r = sd_bus_message_set_destination(m, destination);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_send(bus, m, cookie);
+}
+
+static usec_t calc_elapse(uint64_t usec) {
+        if (usec == (uint64_t) -1)
+                return 0;
+
+        return now(CLOCK_MONOTONIC) + usec;
+}
+
+static int timeout_compare(const void *a, const void *b) {
+        const struct reply_callback *x = a, *y = b;
+
+        if (x->timeout != 0 && y->timeout == 0)
+                return -1;
+
+        if (x->timeout == 0 && y->timeout != 0)
+                return 1;
+
+        if (x->timeout < y->timeout)
+                return -1;
+
+        if (x->timeout > y->timeout)
+                return 1;
+
+        return 0;
+}
+
+_public_ int sd_bus_call_async(
+                sd_bus *bus,
+                sd_bus_message *_m,
+                sd_bus_message_handler_t callback,
+                void *userdata,
+                uint64_t usec,
+                uint64_t *cookie) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
+        struct reply_callback *c;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(m, -EINVAL);
+        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func);
+        if (r < 0)
+                return r;
+
+        r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare);
+        if (r < 0)
+                return r;
+
+        r = bus_seal_message(bus, m, usec);
+        if (r < 0)
+                return r;
+
+        r = bus_remarshal_message(bus, &m);
+        if (r < 0)
+                return r;
+
+        c = new0(struct reply_callback, 1);
+        if (!c)
+                return -ENOMEM;
+
+        c->callback = callback;
+        c->userdata = userdata;
+        c->cookie = BUS_MESSAGE_COOKIE(m);
+        c->timeout = calc_elapse(m->timeout);
+
+        r = hashmap_put(bus->reply_callbacks, &c->cookie, c);
+        if (r < 0) {
+                free(c);
+                return r;
+        }
+
+        if (c->timeout != 0) {
+                r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                if (r < 0) {
+                        c->timeout = 0;
+                        sd_bus_call_async_cancel(bus, c->cookie);
+                        return r;
+                }
+        }
+
+        r = sd_bus_send(bus, m, cookie);
+        if (r < 0) {
+                sd_bus_call_async_cancel(bus, c->cookie);
+                return r;
+        }
+
+        return r;
+}
+
+_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie) {
+        struct reply_callback *c;
+
+        assert_return(bus, -EINVAL);
+        assert_return(cookie != 0, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        c = hashmap_remove(bus->reply_callbacks, &cookie);
+        if (!c)
+                return 0;
+
+        if (c->timeout != 0)
+                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+
+        free(c);
+        return 1;
+}
+
+int bus_ensure_running(sd_bus *bus) {
+        int r;
+
+        assert(bus);
+
+        if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING)
+                return -ENOTCONN;
+        if (bus->state == BUS_RUNNING)
+                return 1;
+
+        for (;;) {
+                r = sd_bus_process(bus, NULL);
+                if (r < 0)
+                        return r;
+                if (bus->state == BUS_RUNNING)
+                        return 1;
+                if (r > 0)
+                        continue;
+
+                r = sd_bus_wait(bus, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+_public_ int sd_bus_call(
+                sd_bus *bus,
+                sd_bus_message *_m,
+                uint64_t usec,
+                sd_bus_error *error,
+                sd_bus_message **reply) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
+        usec_t timeout;
+        uint64_t cookie;
+        unsigned i;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(m, -EINVAL);
+        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
+        assert_return(!bus_error_is_dirty(error), -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = bus_ensure_running(bus);
+        if (r < 0)
+                return r;
+
+        i = bus->rqueue_size;
+
+        r = bus_seal_message(bus, m, usec);
+        if (r < 0)
+                return r;
+
+        r = bus_remarshal_message(bus, &m);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_send(bus, m, &cookie);
+        if (r < 0)
+                return r;
+
+        timeout = calc_elapse(m->timeout);
+
+        for (;;) {
+                usec_t left;
+
+                while (i < bus->rqueue_size) {
+                        sd_bus_message *incoming = NULL;
+
+                        incoming = bus->rqueue[i];
+
+                        if (incoming->reply_cookie == cookie) {
+                                /* Found a match! */
+
+                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+                                bus->rqueue_size--;
+
+                                if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
+
+                                        if (reply)
+                                                *reply = incoming;
+                                        else
+                                                sd_bus_message_unref(incoming);
+
+                                        return 1;
+                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
+                                        r = sd_bus_error_copy(error, &incoming->error);
+                                else
+                                        r = -EIO;
+
+                                sd_bus_message_unref(incoming);
+                                return r;
+
+                        } else if (BUS_MESSAGE_COOKIE(incoming) == cookie &&
+                                   bus->unique_name &&
+                                   incoming->sender &&
+                                   streq(bus->unique_name, incoming->sender)) {
+
+                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+                                bus->rqueue_size--;
+
+                                /* Our own message? Somebody is trying
+                                 * to send its own client a message,
+                                 * let's not dead-lock, let's fail
+                                 * immediately. */
+
+                                sd_bus_message_unref(incoming);
+                                return -ELOOP;
+                        }
+
+                        /* Try to read more, right-away */
+                        i++;
+                }
+
+                r = bus_read_message(bus);
+                if (r < 0) {
+                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                                bus_enter_closing(bus);
+                                return -ECONNRESET;
+                        }
+
+                        return r;
+                }
+                if (r > 0)
+                        continue;
+
+                if (timeout > 0) {
+                        usec_t n;
+
+                        n = now(CLOCK_MONOTONIC);
+                        if (n >= timeout)
+                                return -ETIMEDOUT;
+
+                        left = timeout - n;
+                } else
+                        left = (uint64_t) -1;
+
+                r = bus_poll(bus, true, left);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -ETIMEDOUT;
+
+                r = dispatch_wqueue(bus);
+                if (r < 0) {
+                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                                bus_enter_closing(bus);
+                                return -ECONNRESET;
+                        }
+
+                        return r;
+                }
+        }
+}
+
+_public_ int sd_bus_get_fd(sd_bus *bus) {
+
+        assert_return(bus, -EINVAL);
+        assert_return(bus->input_fd == bus->output_fd, -EPERM);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        return bus->input_fd;
+}
+
+_public_ int sd_bus_get_events(sd_bus *bus) {
+        int flags = 0;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (bus->state == BUS_OPENING)
+                flags |= POLLOUT;
+        else if (bus->state == BUS_AUTHENTICATING) {
+
+                if (bus_socket_auth_needs_write(bus))
+                        flags |= POLLOUT;
+
+                flags |= POLLIN;
+
+        } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) {
+                if (bus->rqueue_size <= 0)
+                        flags |= POLLIN;
+                if (bus->wqueue_size > 0)
+                        flags |= POLLOUT;
+        }
+
+        return flags;
+}
+
+_public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
+        struct reply_callback *c;
+
+        assert_return(bus, -EINVAL);
+        assert_return(timeout_usec, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (bus->state == BUS_CLOSING) {
+                *timeout_usec = 0;
+                return 1;
+        }
+
+        if (bus->state == BUS_AUTHENTICATING) {
+                *timeout_usec = bus->auth_timeout;
+                return 1;
+        }
+
+        if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) {
+                *timeout_usec = (uint64_t) -1;
+                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;
+                return 0;
+        }
+
+        *timeout_usec = c->timeout;
+        return 1;
+}
+
+static int process_timeout(sd_bus *bus) {
+        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message* m = NULL;
+        struct reply_callback *c;
+        usec_t n;
+        int r;
+
+        assert(bus);
+
+        c = prioq_peek(bus->reply_callbacks_prioq);
+        if (!c)
+                return 0;
+
+        n = now(CLOCK_MONOTONIC);
+        if (c->timeout > n)
+                return 0;
+
+        r = bus_message_new_synthetic_error(
+                        bus,
+                        c->cookie,
+                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out"),
+                        &m);
+        if (r < 0)
+                return r;
+
+        m->sender = "org.freedesktop.DBus";
+
+        r = bus_seal_synthetic_message(bus, m);
+        if (r < 0)
+                return r;
+
+        assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
+        hashmap_remove(bus->reply_callbacks, &c->cookie);
+
+        bus->current = m;
+        bus->iteration_counter ++;
+
+        r = c->callback(bus, m, c->userdata, &error_buffer);
+        r = bus_maybe_reply_error(m, r, &error_buffer);
+        free(c);
+
+        bus->current = NULL;
+
+        return r;
+}
+
+static int process_hello(sd_bus *bus, sd_bus_message *m) {
+        assert(bus);
+        assert(m);
+
+        if (bus->state != BUS_HELLO)
+                return 0;
+
+        /* Let's make sure the first message on the bus is the HELLO
+         * reply. But note that we don't actually parse the message
+         * 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_METHOD_RETURN &&
+            m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
+                return -EIO;
+
+        if (m->reply_cookie != bus->hello_cookie)
+                return -EIO;
+
+        return 0;
+}
+
+static int process_reply(sd_bus *bus, sd_bus_message *m) {
+        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        struct reply_callback *c;
+        int r;
+
+        assert(bus);
+        assert(m);
+
+        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_cookie);
+        if (!c)
+                return 0;
+
+        if (c->timeout != 0)
+                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+
+        r = sd_bus_message_rewind(m, true);
+        if (r < 0)
+                return r;
+
+        r = c->callback(bus, m, c->userdata, &error_buffer);
+        r = bus_maybe_reply_error(m, r, &error_buffer);
+        free(c);
+
+        return r;
+}
+
+static int process_filter(sd_bus *bus, sd_bus_message *m) {
+        _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+        struct filter_callback *l;
+        int r;
+
+        assert(bus);
+        assert(m);
+
+        do {
+                bus->filter_callbacks_modified = false;
+
+                LIST_FOREACH(callbacks, l, bus->filter_callbacks) {
+
+                        if (bus->filter_callbacks_modified)
+                                break;
+
+                        /* Don't run this more than once per iteration */
+                        if (l->last_iteration == bus->iteration_counter)
+                                continue;
+
+                        l->last_iteration = bus->iteration_counter;
+
+                        r = sd_bus_message_rewind(m, true);
+                        if (r < 0)
+                                return r;
+
+                        r = l->callback(bus, m, l->userdata, &error_buffer);
+                        r = bus_maybe_reply_error(m, r, &error_buffer);
+                        if (r != 0)
+                                return r;
+
+                }
+
+        } while (bus->filter_callbacks_modified);
+
+        return 0;
+}
+
+static int process_match(sd_bus *bus, sd_bus_message *m) {
+        int r;
+
+        assert(bus);
+        assert(m);
+
+        do {
+                bus->match_callbacks_modified = false;
+
+                r = bus_match_run(bus, &bus->match_callbacks, m);
+                if (r != 0)
+                        return r;
+
+        } while (bus->match_callbacks_modified);
+
+        return 0;
+}
+
+static int process_builtin(sd_bus *bus, sd_bus_message *m) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        int r;
+
+        assert(bus);
+        assert(m);
+
+        if (bus->manual_peer_interface)
+                return 0;
+
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
+                return 0;
+
+        if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
+                return 0;
+
+        if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 1;
+
+        if (streq_ptr(m->member, "Ping"))
+                r = sd_bus_message_new_method_return(m, &reply);
+        else if (streq_ptr(m->member, "GetMachineId")) {
+                sd_id128_t id;
+                char sid[33];
+
+                r = sd_id128_get_machine(&id);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_new_method_return(m, &reply);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(reply, "s", sd_id128_to_string(id, sid));
+        } else {
+                r = sd_bus_message_new_method_errorf(
+                                m, &reply,
+                                SD_BUS_ERROR_UNKNOWN_METHOD,
+                                 "Unknown method '%s' on interface '%s'.", m->member, m->interface);
+        }
+
+        if (r < 0)
+                return r;
+
+        r = sd_bus_send(bus, reply, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int process_message(sd_bus *bus, sd_bus_message *m) {
+        int r;
+
+        assert(bus);
+        assert(m);
+
+        bus->current = m;
+        bus->iteration_counter++;
+
+        log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s",
+                  bus_message_type_to_string(m->header->type),
+                  strna(sd_bus_message_get_sender(m)),
+                  strna(sd_bus_message_get_destination(m)),
+                  strna(sd_bus_message_get_path(m)),
+                  strna(sd_bus_message_get_interface(m)),
+                  strna(sd_bus_message_get_member(m)),
+                  (unsigned long) BUS_MESSAGE_COOKIE(m),
+                  (unsigned long) m->reply_cookie,
+                  strna(m->error.message));
+
+        r = process_hello(bus, m);
+        if (r != 0)
+                goto finish;
+
+        r = process_reply(bus, m);
+        if (r != 0)
+                goto finish;
+
+        r = process_filter(bus, m);
+        if (r != 0)
+                goto finish;
+
+        r = process_match(bus, m);
+        if (r != 0)
+                goto finish;
+
+        r = process_builtin(bus, m);
+        if (r != 0)
+                goto finish;
+
+        r = bus_process_object(bus, m);
+
+finish:
+        bus->current = NULL;
+        return r;
+}
+
+static int process_running(sd_bus *bus, sd_bus_message **ret) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert(bus);
+        assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+        r = process_timeout(bus);
+        if (r != 0)
+                goto null_message;
+
+        r = dispatch_wqueue(bus);
+        if (r != 0)
+                goto null_message;
+
+        r = dispatch_rqueue(bus, &m);
+        if (r < 0)
+                return r;
+        if (!m)
+                goto null_message;
+
+        r = process_message(bus, m);
+        if (r != 0)
+                goto null_message;
+
+        if (ret) {
+                r = sd_bus_message_rewind(m, true);
+                if (r < 0)
+                        return r;
+
+                *ret = m;
+                m = NULL;
+                return 1;
+        }
+
+        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) {
+
+                log_debug("Unprocessed message call 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 = sd_bus_reply_method_errorf(
+                                m,
+                                SD_BUS_ERROR_UNKNOWN_OBJECT,
+                                "Unknown object '%s'.", m->path);
+                if (r < 0)
+                        return r;
+        }
+
+        return 1;
+
+null_message:
+        if (r >= 0 && ret)
+                *ret = NULL;
+
+        return r;
+}
+
+static int process_closing(sd_bus *bus, sd_bus_message **ret) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        struct reply_callback *c;
+        int r;
+
+        assert(bus);
+        assert(bus->state == BUS_CLOSING);
+
+        c = hashmap_first(bus->reply_callbacks);
+        if (c) {
+                _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+
+                /* First, fail all outstanding method calls */
+                r = bus_message_new_synthetic_error(
+                                bus,
+                                c->cookie,
+                                &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
+                                &m);
+                if (r < 0)
+                        return r;
+
+                r = bus_seal_synthetic_message(bus, m);
+                if (r < 0)
+                        return r;
+
+                if (c->timeout != 0)
+                        prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+
+                hashmap_remove(bus->reply_callbacks, &c->cookie);
+
+                bus->current = m;
+                bus->iteration_counter++;
+
+                r = c->callback(bus, m, c->userdata, &error_buffer);
+                r = bus_maybe_reply_error(m, r, &error_buffer);
+                free(c);
+
+                goto finish;
+        }
+
+        /* Then, synthesize a Disconnected message */
+        r = sd_bus_message_new_signal(
+                        bus,
+                        "/org/freedesktop/DBus/Local",
+                        "org.freedesktop.DBus.Local",
+                        "Disconnected",
+                        &m);
+        if (r < 0)
+                return r;
+
+        m->sender = "org.freedesktop.DBus.Local";
+
+        r = bus_seal_synthetic_message(bus, m);
+        if (r < 0)
+                return r;
+
+        sd_bus_close(bus);
+
+        bus->current = m;
+        bus->iteration_counter++;
+
+        r = process_filter(bus, m);
+        if (r != 0)
+                goto finish;
+
+        r = process_match(bus, m);
+        if (r != 0)
+                goto finish;
+
+        if (ret) {
+                *ret = m;
+                m = NULL;
+        }
+
+        r = 1;
+
+finish:
+        bus->current = NULL;
+        return r;
+}
+
+_public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
+        BUS_DONT_DESTROY(bus);
+        int r;
+
+        /* Returns 0 when we didn't do anything. This should cause the
+         * caller to invoke sd_bus_wait() before returning the next
+         * time. Returns > 0 when we did something, which possibly
+         * means *ret is filled in with an unprocessed message. */
+
+        assert_return(bus, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        /* We don't allow recursively invoking sd_bus_process(). */
+        assert_return(!bus->current, -EBUSY);
+
+        switch (bus->state) {
+
+        case BUS_UNSET:
+                return -ENOTCONN;
+
+        case BUS_CLOSED:
+                return -ECONNRESET;
+
+        case BUS_OPENING:
+                r = bus_socket_process_opening(bus);
+                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        bus_enter_closing(bus);
+                        r = 1;
+                } else if (r < 0)
+                        return r;
+                if (ret)
+                        *ret = NULL;
+                return r;
+
+        case BUS_AUTHENTICATING:
+                r = bus_socket_process_authenticating(bus);
+                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        bus_enter_closing(bus);
+                        r = 1;
+                } else if (r < 0)
+                        return r;
+
+                if (ret)
+                        *ret = NULL;
+
+                return r;
+
+        case BUS_RUNNING:
+        case BUS_HELLO:
+                r = process_running(bus, ret);
+                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        bus_enter_closing(bus);
+                        r = 1;
+
+                        if (ret)
+                                *ret = NULL;
+                }
+
+                return r;
+
+        case BUS_CLOSING:
+                return process_closing(bus, ret);
+        }
+
+        assert_not_reached("Unknown state");
+}
+
+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 m = (usec_t) -1;
+
+        assert(bus);
+
+        if (bus->state == BUS_CLOSING)
+                return 1;
+
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+
+        e = sd_bus_get_events(bus);
+        if (e < 0)
+                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;
+        else {
+                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))
+                m = timeout_usec;
+
+        p[0].fd = bus->input_fd;
+        if (bus->output_fd == bus->input_fd) {
+                p[0].events = e;
+                n = 1;
+        } else {
+                p[0].events = e & POLLIN;
+                p[1].fd = bus->output_fd;
+                p[1].events = e & POLLOUT;
+                n = 2;
+        }
+
+        r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
+        if (r < 0)
+                return -errno;
+
+        return r > 0 ? 1 : 0;
+}
+
+_public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
+
+        assert_return(bus, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (bus->state == BUS_CLOSING)
+                return 0;
+
+        assert_return(BUS_IS_OPEN(bus->state) , -ENOTCONN);
+
+        if (bus->rqueue_size > 0)
+                return 0;
+
+        return bus_poll(bus, false, timeout_usec);
+}
+
+_public_ int sd_bus_flush(sd_bus *bus) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (bus->state == BUS_CLOSING)
+                return 0;
+
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+
+        r = bus_ensure_running(bus);
+        if (r < 0)
+                return r;
+
+        if (bus->wqueue_size <= 0)
+                return 0;
+
+        for (;;) {
+                r = dispatch_wqueue(bus);
+                if (r < 0) {
+                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                                bus_enter_closing(bus);
+                                return -ECONNRESET;
+                        }
+
+                        return r;
+                }
+
+                if (bus->wqueue_size <= 0)
+                        return 0;
+
+                r = bus_poll(bus, false, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+_public_ int sd_bus_add_filter(sd_bus *bus,
+                               sd_bus_message_handler_t callback,
+                               void *userdata) {
+
+        struct filter_callback *f;
+
+        assert_return(bus, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        f = new0(struct filter_callback, 1);
+        if (!f)
+                return -ENOMEM;
+        f->callback = callback;
+        f->userdata = userdata;
+
+        bus->filter_callbacks_modified = true;
+        LIST_PREPEND(callbacks, bus->filter_callbacks, f);
+        return 0;
+}
+
+_public_ int sd_bus_remove_filter(sd_bus *bus,
+                                  sd_bus_message_handler_t callback,
+                                  void *userdata) {
+
+        struct filter_callback *f;
+
+        assert_return(bus, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        LIST_FOREACH(callbacks, f, bus->filter_callbacks) {
+                if (f->callback == callback && f->userdata == userdata) {
+                        bus->filter_callbacks_modified = true;
+                        LIST_REMOVE(callbacks, bus->filter_callbacks, f);
+                        free(f);
+                        return 1;
+                }
+        }
+
+        return 0;
+}
+
+_public_ int sd_bus_add_match(sd_bus *bus,
+                              const char *match,
+                              sd_bus_message_handler_t callback,
+                              void *userdata) {
+
+        struct bus_match_component *components = NULL;
+        unsigned n_components = 0;
+        uint64_t cookie = 0;
+        int r = 0;
+
+        assert_return(bus, -EINVAL);
+        assert_return(match, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = bus_match_parse(match, &components, &n_components);
+        if (r < 0)
+                goto finish;
+
+        if (bus->bus_client) {
+                cookie = ++bus->match_cookie;
+
+                r = bus_add_match_internal(bus, match, components, n_components, cookie);
+                if (r < 0)
+                        goto finish;
+        }
+
+        bus->match_callbacks_modified = true;
+        r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL);
+        if (r < 0) {
+                if (bus->bus_client)
+                        bus_remove_match_internal(bus, match, cookie);
+        }
+
+finish:
+        bus_match_parse_free(components, n_components);
+        return r;
+}
+
+_public_ int sd_bus_remove_match(sd_bus *bus,
+                                 const char *match,
+                                 sd_bus_message_handler_t callback,
+                                 void *userdata) {
+
+        struct bus_match_component *components = NULL;
+        unsigned n_components = 0;
+        int r = 0, q = 0;
+        uint64_t cookie = 0;
+
+        assert_return(bus, -EINVAL);
+        assert_return(match, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = bus_match_parse(match, &components, &n_components);
+        if (r < 0)
+                return r;
+
+        bus->match_callbacks_modified = true;
+        r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie);
+
+        if (bus->bus_client)
+                q = bus_remove_match_internal(bus, match, cookie);
+
+        bus_match_parse_free(components, n_components);
+
+        return r < 0 ? r : q;
+}
+
+bool bus_pid_changed(sd_bus *bus) {
+        assert(bus);
+
+        /* We don't support people creating a bus connection and
+         * keeping it around over a fork(). Let's complain. */
+
+        return bus->original_pid != getpid();
+}
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        sd_bus *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) {
+        sd_bus *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;
+}
+
+static int quit_callback(sd_event_source *event, void *userdata) {
+        sd_bus *bus = userdata;
+
+        assert(event);
+
+        sd_bus_flush(bus);
+
+        return 1;
+}
+
+static int attach_io_events(sd_bus *bus) {
+        int r;
+
+        assert(bus);
+
+        if (bus->input_fd < 0)
+                return 0;
+
+        if (!bus->event)
+                return 0;
+
+        if (!bus->input_io_event_source) {
+                r = sd_event_add_io(bus->event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
+                if (r < 0)
+                        return r;
+
+                r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
+                if (r < 0)
+                        return r;
+
+                r = sd_event_source_set_priority(bus->input_io_event_source, bus->event_priority);
+        } else
+                r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd);
+
+        if (r < 0)
+                return r;
+
+        if (bus->output_fd != bus->input_fd) {
+                assert(bus->output_fd >= 0);
+
+                if (!bus->output_io_event_source) {
+                        r = sd_event_add_io(bus->event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_event_source_set_priority(bus->output_io_event_source, bus->event_priority);
+                } else
+                        r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static void detach_io_events(sd_bus *bus) {
+        assert(bus);
+
+        if (bus->input_io_event_source) {
+                sd_event_source_set_enabled(bus->input_io_event_source, SD_EVENT_OFF);
+                bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
+        }
+
+        if (bus->output_io_event_source) {
+                sd_event_source_set_enabled(bus->output_io_event_source, SD_EVENT_OFF);
+                bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
+        }
+}
+
+_public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(!bus->event, -EBUSY);
+
+        assert(!bus->input_io_event_source);
+        assert(!bus->output_io_event_source);
+        assert(!bus->time_event_source);
+
+        if (event)
+                bus->event = sd_event_ref(event);
+        else  {
+                r = sd_event_default(&bus->event);
+                if (r < 0)
+                        return r;
+        }
+
+        bus->event_priority = priority;
+
+        r = sd_event_add_monotonic(bus->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;
+
+        r = sd_event_add_exit(bus->event, quit_callback, bus, &bus->quit_event_source);
+        if (r < 0)
+                goto fail;
+
+        r = attach_io_events(bus);
+        if (r < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        sd_bus_detach_event(bus);
+        return r;
+}
+
+_public_ int sd_bus_detach_event(sd_bus *bus) {
+        assert_return(bus, -EINVAL);
+
+        if (!bus->event)
+                return 0;
+
+        detach_io_events(bus);
+
+        if (bus->time_event_source) {
+                sd_event_source_set_enabled(bus->time_event_source, SD_EVENT_OFF);
+                bus->time_event_source = sd_event_source_unref(bus->time_event_source);
+        }
+
+        if (bus->quit_event_source) {
+                sd_event_source_set_enabled(bus->quit_event_source, SD_EVENT_OFF);
+                bus->quit_event_source = sd_event_source_unref(bus->quit_event_source);
+        }
+
+        if (bus->event)
+                bus->event = sd_event_unref(bus->event);
+
+        return 1;
+}
+
+_public_ sd_event* sd_bus_get_event(sd_bus *bus) {
+        assert_return(bus, NULL);
+
+        return bus->event;
+}
+
+_public_ sd_bus_message* sd_bus_get_current(sd_bus *bus) {
+        assert_return(bus, NULL);
+
+        return bus->current;
+}
+
+static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus **ret) {
+        sd_bus *b = NULL;
+        int r;
+
+        assert(bus_open);
+        assert(default_bus);
+
+        if (!ret)
+                return !!*default_bus;
+
+        if (*default_bus) {
+                *ret = sd_bus_ref(*default_bus);
+                return 0;
+        }
+
+        r = bus_open(&b);
+        if (r < 0)
+                return r;
+
+        b->default_bus_ptr = default_bus;
+        b->tid = gettid();
+        *default_bus = b;
+
+        *ret = b;
+        return 1;
+}
+
+_public_ int sd_bus_default_system(sd_bus **ret) {
+        static thread_local sd_bus *default_system_bus = NULL;
+
+        return bus_default(sd_bus_open_system, &default_system_bus, ret);
+}
+
+_public_ int sd_bus_default_user(sd_bus **ret) {
+        static thread_local sd_bus *default_user_bus = NULL;
+
+        return bus_default(sd_bus_open_user, &default_user_bus, ret);
+}
+
+_public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) {
+        assert_return(b, -EINVAL);
+        assert_return(tid, -EINVAL);
+        assert_return(!bus_pid_changed(b), -ECHILD);
+
+        if (b->tid != 0) {
+                *tid = b->tid;
+                return 0;
+        }
+
+        if (b->event)
+                return sd_event_get_tid(b->event, tid);
+
+        return -ENXIO;
+}
+
+_public_ char *sd_bus_label_escape(const char *s) {
+        char *r, *t;
+        const char *f;
+
+        assert_return(s, NULL);
+
+        /* Escapes all chars that D-Bus' object path cannot deal
+         * with. Can be reversed with bus_path_unescape(). We special
+         * case the empty string. */
+
+        if (*s == 0)
+                return strdup("_");
+
+        r = new(char, strlen(s)*3 + 1);
+        if (!r)
+                return NULL;
+
+        for (f = s, t = r; *f; f++) {
+
+                /* Escape everything that is not a-zA-Z0-9. We also
+                 * escape 0-9 if it's the first character */
+
+                if (!(*f >= 'A' && *f <= 'Z') &&
+                    !(*f >= 'a' && *f <= 'z') &&
+                    !(f > s && *f >= '0' && *f <= '9')) {
+                        *(t++) = '_';
+                        *(t++) = hexchar(*f >> 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+_public_ char *sd_bus_label_unescape(const char *f) {
+        char *r, *t;
+
+        assert_return(f, NULL);
+
+        /* Special case for the empty string */
+        if (streq(f, "_"))
+                return strdup("");
+
+        r = new(char, strlen(f) + 1);
+        if (!r)
+                return NULL;
+
+        for (t = r; *f; f++) {
+
+                if (*f == '_') {
+                        int a, b;
+
+                        if ((a = unhexchar(f[1])) < 0 ||
+                            (b = unhexchar(f[2])) < 0) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '_';
+                        } else {
+                                *(t++) = (char) ((a << 4) | b);
+                                f += 2;
+                        }
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+_public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
+        sd_bus_creds *c;
+        pid_t pid = 0;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+        assert_return(ret, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(!bus->is_kernel, -ENOTSUP);
+
+        if (!bus->ucred_valid && !isempty(bus->label))
+                return -ENODATA;
+
+        c = bus_creds_new();
+        if (!c)
+                return -ENOMEM;
+
+        if (bus->ucred_valid) {
+                pid = c->pid = bus->ucred.pid;
+                c->uid = bus->ucred.uid;
+                c->gid = bus->ucred.gid;
+
+                c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
+        }
+
+        if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
+                c->label = strdup(bus->label);
+                if (!c->label) {
+                        sd_bus_creds_unref(c);
+                        return -ENOMEM;
+                }
+
+                c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+        }
+
+        r = bus_creds_add_more(c, mask, pid, 0);
+        if (r < 0)
+                return r;
+
+        *ret = c;
+        return 0;
+}
+
+_public_ int sd_bus_try_close(sd_bus *bus) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+        assert_return(bus->is_kernel, -ENOTSUP);
+
+        if (bus->rqueue_size > 0)
+                return -EBUSY;
+
+        if (bus->wqueue_size > 0)
+                return -EBUSY;
+
+        r = bus_kernel_try_close(bus);
+        if (r < 0)
+                return r;
+
+        sd_bus_close(bus);
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/sd-memfd.c b/src/libsystemd/sd-bus/sd-memfd.c
new file mode 100644
index 0000000..112c95f
--- /dev/null
+++ b/src/libsystemd/sd-bus/sd-memfd.c
@@ -0,0 +1,220 @@
+/*-*- 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 <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "kdbus.h"
+
+#include "sd-memfd.h"
+
+struct sd_memfd {
+        int fd;
+        FILE *f;
+};
+
+_public_ int sd_memfd_new(sd_memfd **m) {
+        struct kdbus_cmd_memfd_make cmd = {
+                .size = sizeof(struct kdbus_cmd_memfd_make),
+        };
+        _cleanup_close_ int kdbus = -1;
+        sd_memfd *n;
+
+        assert_return(m, -EINVAL);
+
+        kdbus = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (kdbus < 0)
+                return -errno;
+
+        if (ioctl(kdbus, KDBUS_CMD_MEMFD_NEW, &cmd) < 0)
+                return -errno;
+
+        n = new0(struct sd_memfd, 1);
+        if (!n) {
+                close_nointr_nofail(cmd.fd);
+                return -ENOMEM;
+        }
+
+        n->fd = cmd.fd;
+        *m = n;
+        return 0;
+}
+
+_public_ int sd_memfd_make(int fd, sd_memfd **m) {
+        sd_memfd *n;
+        uint64_t sz;
+
+        assert_return(m, -EINVAL);
+        assert_return(fd >= 0, -EINVAL);
+
+        /* Check if this is a valid memfd */
+        if (ioctl(fd, KDBUS_CMD_MEMFD_SIZE_GET, &sz) < 0)
+                return -ENOTTY;
+
+        n = new0(struct sd_memfd, 1);
+        if (!n)
+                return -ENOMEM;
+
+        n->fd = fd;
+        *m = n;
+
+        return 0;
+}
+
+_public_ void sd_memfd_free(sd_memfd *m) {
+        if (!m)
+                return;
+
+        if (m->f)
+                fclose(m->f);
+        else
+                close_nointr_nofail(m->fd);
+
+        free(m);
+}
+
+_public_ int sd_memfd_get_fd(sd_memfd *m) {
+        assert_return(m, -EINVAL);
+
+        return m->fd;
+}
+
+_public_ int sd_memfd_get_file(sd_memfd *m, FILE **f) {
+        assert_return(m, -EINVAL);
+        assert_return(f, -EINVAL);
+
+        if (!m->f) {
+                m->f = fdopen(m->fd, "r+");
+                if (!m->f)
+                        return -errno;
+        }
+
+        *f = m->f;
+        return 0;
+}
+
+_public_ int sd_memfd_dup_fd(sd_memfd *m) {
+        int fd;
+
+        assert_return(m, -EINVAL);
+
+        fd = fcntl(m->fd, F_DUPFD_CLOEXEC, 3);
+        if (fd < 0)
+                return -errno;
+
+        return fd;
+}
+
+_public_ int sd_memfd_map(sd_memfd *m, uint64_t offset, size_t size, void **p) {
+        void *q;
+        int sealed;
+
+        assert_return(m, -EINVAL);
+        assert_return(size > 0, -EINVAL);
+        assert_return(p, -EINVAL);
+
+        sealed = sd_memfd_get_sealed(m);
+        if (sealed < 0)
+                return sealed;
+
+        q = mmap(NULL, size, sealed ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, m->fd, offset);
+        if (q == MAP_FAILED)
+                return -errno;
+
+        *p = q;
+        return 0;
+}
+
+_public_ int sd_memfd_set_sealed(sd_memfd *m, int b) {
+        int r;
+
+        assert_return(m, -EINVAL);
+
+        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_SET, b);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+_public_ int sd_memfd_get_sealed(sd_memfd *m) {
+        int r, b;
+
+        assert_return(m, -EINVAL);
+
+        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_GET, &b);
+        if (r < 0)
+                return -errno;
+
+        return !!b;
+}
+
+_public_ int sd_memfd_get_size(sd_memfd *m, uint64_t *sz) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(sz, -EINVAL);
+
+        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_GET, sz);
+        if (r < 0)
+                return -errno;
+
+        return r;
+}
+
+_public_ int sd_memfd_set_size(sd_memfd *m, uint64_t sz) {
+        int r;
+
+        assert_return(m, -EINVAL);
+
+        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
+        if (r < 0)
+                return -errno;
+
+        return r;
+}
+
+_public_ int sd_memfd_new_and_map(sd_memfd **m, size_t sz, void **p) {
+        sd_memfd *n;
+        int r;
+
+        r = sd_memfd_new(&n);
+        if (r < 0)
+                return r;
+
+        r = sd_memfd_set_size(n, sz);
+        if (r < 0) {
+                sd_memfd_free(n);
+                return r;
+        }
+
+        r = sd_memfd_map(n, 0, sz, p);
+        if (r < 0) {
+                sd_memfd_free(n);
+                return r;
+        }
+
+        *m = n;
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
new file mode 100644
index 0000000..021379f
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -0,0 +1,581 @@
+/*-*- 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 <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#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, sd_bus_error *ret_error) {
+        log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
+        return 0;
+}
+
+static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        int r;
+
+        assert(bus);
+
+        if (sd_bus_message_is_method_error(m, NULL))
+                return 0;
+
+        if (sd_bus_message_is_method_call(m, "org.object.test", "Foobar")) {
+                log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m));
+
+                r = sd_bus_reply_method_return(m, NULL);
+                if (r < 0) {
+                        log_error("Failed to send reply: %s", strerror(-r));
+                        return r;
+                }
+
+                return 1;
+        }
+
+        return 0;
+}
+
+static int server_init(sd_bus **_bus) {
+        sd_bus *bus = NULL;
+        sd_id128_t id;
+        int r;
+        const char *unique;
+
+        assert(_bus);
+
+        r = sd_bus_open_user(&bus);
+        if (r < 0) {
+                log_error("Failed to connect to user bus: %s", strerror(-r));
+                goto fail;
+        }
+
+        r = sd_bus_get_server_id(bus, &id);
+        if (r < 0) {
+                log_error("Failed to get server ID: %s", strerror(-r));
+                goto fail;
+        }
+
+        r = sd_bus_get_unique_name(bus, &unique);
+        if (r < 0) {
+                log_error("Failed to get unique name: %s", strerror(-r));
+                goto fail;
+        }
+
+        log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
+        log_info("Unique ID: %s", unique);
+        log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
+
+        r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
+        if (r < 0) {
+                log_error("Failed to acquire name: %s", strerror(-r));
+                goto fail;
+        }
+
+        r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL);
+        if (r < 0) {
+                log_error("Failed to add object: %s", strerror(-r));
+                goto fail;
+        }
+
+        r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
+        if (r < 0) {
+                log_error("Failed to add match: %s", strerror(-r));
+                goto fail;
+        }
+
+        r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
+        if (r < 0) {
+                log_error("Failed to add match: %s", strerror(-r));
+                goto fail;
+        }
+
+        bus_match_dump(&bus->match_callbacks, 0);
+
+        *_bus = bus;
+        return 0;
+
+fail:
+        if (bus)
+                sd_bus_unref(bus);
+
+        return r;
+}
+
+static int server(sd_bus *bus) {
+        int r;
+        bool client1_gone = false, client2_gone = false;
+
+        while (!client1_gone || !client2_gone) {
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+                pid_t pid = 0;
+                const char *label = NULL;
+
+                r = sd_bus_process(bus, &m);
+                if (r < 0) {
+                        log_error("Failed to process requests: %s", strerror(-r));
+                        goto fail;
+                }
+
+                if (r == 0) {
+                        r = sd_bus_wait(bus, (uint64_t) -1);
+                        if (r < 0) {
+                                log_error("Failed to wait: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        continue;
+                }
+
+                if (!m)
+                        continue;
+
+                sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
+                sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
+                log_info("Got message! member=%s pid=%lu label=%s",
+                         strna(sd_bus_message_get_member(m)),
+                         (unsigned long) pid,
+                         strna(label));
+                /* bus_message_dump(m); */
+                /* sd_bus_message_rewind(m, true); */
+
+                if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
+                        const char *hello;
+                        _cleanup_free_ char *lowercase = NULL;
+
+                        r = sd_bus_message_read(m, "s", &hello);
+                        if (r < 0) {
+                                log_error("Failed to get parameter: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        lowercase = strdup(hello);
+                        if (!lowercase) {
+                                r = log_oom();
+                                goto fail;
+                        }
+
+                        ascii_strlower(lowercase);
+
+                        r = sd_bus_reply_method_return(m, "s", lowercase);
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
+
+                        r = sd_bus_reply_method_return(m, NULL);
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        client1_gone = true;
+                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
+
+                        r = sd_bus_reply_method_return(m, NULL);
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        client2_gone = true;
+                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
+
+                        sleep(1);
+
+                        r = sd_bus_reply_method_return(m, NULL);
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) {
+                        int fd;
+                        static const char x = 'X';
+
+                        r = sd_bus_message_read(m, "h", &fd);
+                        if (r < 0) {
+                                log_error("Failed to get parameter: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        log_info("Received fd=%d", fd);
+
+                        if (write(fd, &x, 1) < 0) {
+                                log_error("Failed to write to fd: %m");
+                                close_nointr_nofail(fd);
+                                goto fail;
+                        }
+
+                        r = sd_bus_reply_method_return(m, NULL);
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
+
+                        r = sd_bus_reply_method_error(
+                                        m,
+                                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+                }
+        }
+
+        r = 0;
+
+fail:
+        if (bus) {
+                sd_bus_flush(bus);
+                sd_bus_unref(bus);
+        }
+
+        return r;
+}
+
+static void* client1(void*p) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        sd_bus *bus = NULL;
+        sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *hello;
+        int r;
+        int pp[2] = { -1, -1 };
+        char x;
+
+        r = sd_bus_open_user(&bus);
+        if (r < 0) {
+                log_error("Failed to connect to user bus: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/",
+                        "org.freedesktop.systemd.test",
+                        "LowerCase",
+                        &error,
+                        &reply,
+                        "s",
+                        "HELLO");
+        if (r < 0) {
+                log_error("Failed to issue method call: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_message_read(reply, "s", &hello);
+        if (r < 0) {
+                log_error("Failed to get string: %s", strerror(-r));
+                goto finish;
+        }
+
+        assert(streq(hello, "hello"));
+
+        if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
+                log_error("Failed to allocate pipe: %m");
+                r = -errno;
+                goto finish;
+        }
+
+        log_info("Sending fd=%d", pp[1]);
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/",
+                        "org.freedesktop.systemd.test",
+                        "FileDescriptor",
+                        &error,
+                        NULL,
+                        "h",
+                        pp[1]);
+        if (r < 0) {
+                log_error("Failed to issue method call: %s", strerror(-r));
+                goto finish;
+        }
+
+        errno = 0;
+        if (read(pp[0], &x, 1) <= 0) {
+                log_error("Failed to read from pipe: %s", errno ? strerror(errno) : "early read");
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (bus) {
+                _cleanup_bus_message_unref_ sd_bus_message *q;
+
+                r = sd_bus_message_new_method_call(
+                                bus,
+                                "org.freedesktop.systemd.test",
+                                "/",
+                                "org.freedesktop.systemd.test",
+                                "ExitClient1",
+                                &q);
+                if (r < 0)
+                        log_error("Failed to allocate method call: %s", strerror(-r));
+                else
+                        sd_bus_send(bus, q, NULL);
+
+                sd_bus_flush(bus);
+                sd_bus_unref(bus);
+        }
+
+        sd_bus_error_free(&error);
+
+        close_pipe(pp);
+
+        return INT_TO_PTR(r);
+}
+
+static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        bool *x = userdata;
+
+        log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m)));
+
+        *x = 1;
+        return 1;
+}
+
+static void* client2(void*p) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+        sd_bus *bus = NULL;
+        sd_bus_error error = SD_BUS_ERROR_NULL;
+        bool quit = false;
+        const char *mid;
+        int r;
+
+        r = sd_bus_open_user(&bus);
+        if (r < 0) {
+                log_error("Failed to connect to user bus: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/foo/bar/waldo/piep",
+                        "org.object.test",
+                        "Foobar",
+                        &m);
+        if (r < 0) {
+                log_error("Failed to allocate method call: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_send(bus, m, NULL);
+        if (r < 0) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
+                goto finish;
+        }
+
+        sd_bus_message_unref(m);
+        m = NULL;
+
+        r = sd_bus_message_new_signal(
+                        bus,
+                        "/foobar",
+                        "foo.bar",
+                        "Notify",
+                        &m);
+        if (r < 0) {
+                log_error("Failed to allocate signal: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_send(bus, m, NULL);
+        if (r < 0) {
+                log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
+                goto finish;
+        }
+
+        sd_bus_message_unref(m);
+        m = NULL;
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/",
+                        "org.freedesktop.DBus.Peer",
+                        "GetMachineId",
+                        &m);
+        if (r < 0) {
+                log_error("Failed to allocate method call: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_call(bus, m, 0, &error, &reply);
+        if (r < 0) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
+                goto finish;
+        }
+
+        r = sd_bus_message_read(reply, "s", &mid);
+        if (r < 0) {
+                log_error("Failed to parse machine ID: %s", strerror(-r));
+                goto finish;
+        }
+
+        log_info("Machine ID is %s.", mid);
+
+        sd_bus_message_unref(m);
+        m = NULL;
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/",
+                        "org.freedesktop.systemd.test",
+                        "Slow",
+                        &m);
+        if (r < 0) {
+                log_error("Failed to allocate method call: %s", strerror(-r));
+                goto finish;
+        }
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
+        if (r < 0)
+                log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
+        else
+                log_info("Slow call succeed.");
+
+        sd_bus_message_unref(m);
+        m = NULL;
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/",
+                        "org.freedesktop.systemd.test",
+                        "Slow",
+                        &m);
+        if (r < 0) {
+                log_error("Failed to allocate method call: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = sd_bus_call_async(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
+        if (r < 0) {
+                log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
+                goto finish;
+        }
+
+        while (!quit) {
+                r = sd_bus_process(bus, NULL);
+                if (r < 0) {
+                        log_error("Failed to process requests: %s", strerror(-r));
+                        goto finish;
+                }
+                if (r == 0) {
+                        r = sd_bus_wait(bus, (uint64_t) -1);
+                        if (r < 0) {
+                                log_error("Failed to wait: %s", strerror(-r));
+                                goto finish;
+                        }
+                }
+        }
+
+        r = 0;
+
+finish:
+        if (bus) {
+                _cleanup_bus_message_unref_ sd_bus_message *q;
+
+                r = sd_bus_message_new_method_call(
+                                bus,
+                                "org.freedesktop.systemd.test",
+                                "/",
+                                "org.freedesktop.systemd.test",
+                                "ExitClient2",
+                                &q);
+                if (r < 0) {
+                        log_error("Failed to allocate method call: %s", strerror(-r));
+                        goto finish;
+                }
+
+                sd_bus_send(bus, q, NULL);
+                sd_bus_flush(bus);
+                sd_bus_unref(bus);
+        }
+
+        sd_bus_error_free(&error);
+        return INT_TO_PTR(r);
+}
+
+int main(int argc, char *argv[]) {
+        pthread_t c1, c2;
+        sd_bus *bus;
+        void *p;
+        int q, r;
+
+        r = server_init(&bus);
+        if (r < 0) {
+                log_info("Failed to connect to bus, skipping tests.");
+                return EXIT_TEST_SKIP;
+        }
+
+        log_info("Initialized...");
+
+        r = pthread_create(&c1, NULL, client1, bus);
+        if (r != 0)
+                return EXIT_FAILURE;
+
+        r = pthread_create(&c2, NULL, client2, bus);
+        if (r != 0)
+                return EXIT_FAILURE;
+
+        r = server(bus);
+
+        q = pthread_join(c1, &p);
+        if (q != 0)
+                return EXIT_FAILURE;
+        if (PTR_TO_INT(p) < 0)
+                return EXIT_FAILURE;
+
+        q = pthread_join(c2, &p);
+        if (q != 0)
+                return EXIT_FAILURE;
+        if (PTR_TO_INT(p) < 0)
+                return EXIT_FAILURE;
+
+        if (r < 0)
+                return EXIT_FAILURE;
+
+        return EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c
new file mode 100644
index 0000000..d8ddb84
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-cleanup.c
@@ -0,0 +1,80 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+  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 <stdio.h>
+
+#include "sd-bus.h"
+#include "bus-util.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "refcnt.h"
+
+static void test_bus_new(void) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+
+        assert_se(sd_bus_new(&bus) == 0);
+        printf("after new: refcount %u\n", REFCNT_GET(bus->n_ref));
+}
+
+static void test_bus_open(void) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+
+        assert_se(sd_bus_open_system(&bus) >= 0);
+        printf("after open: refcount %u\n", REFCNT_GET(bus->n_ref));
+}
+
+static void test_bus_new_method_call(void) {
+        sd_bus *bus = NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+        assert_se(sd_bus_open_system(&bus) >= 0);
+
+        assert_se(sd_bus_message_new_method_call(bus, "a.service.name", "/an/object/path", "an.interface.name", "AMethodName", &m) >= 0);
+
+        printf("after message_new_method_call: refcount %u\n", REFCNT_GET(bus->n_ref));
+
+        sd_bus_unref(bus);
+        printf("after bus_unref: refcount %u\n", m->n_ref);
+}
+
+static void test_bus_new_signal(void) {
+        sd_bus *bus = NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+        assert_se(sd_bus_open_system(&bus) >= 0);
+
+        assert_se(sd_bus_message_new_signal(bus, "/an/object/path", "an.interface.name", "Name", &m) >= 0);
+
+        printf("after message_new_signal: refcount %u\n", REFCNT_GET(bus->n_ref));
+
+        sd_bus_unref(bus);
+        printf("after bus_unref: refcount %u\n", m->n_ref);
+}
+
+int main(int argc, char **argv) {
+        log_parse_environment();
+        log_open();
+
+        test_bus_new();
+        test_bus_open();
+        test_bus_new_method_call();
+        test_bus_new_signal();
+}
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
new file mode 100644
index 0000000..966b84c
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -0,0 +1,46 @@
+/*-*- 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-bus.h"
+#include "bus-dump.h"
+#include "bus-util.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        int r;
+
+        r = sd_bus_creds_new_from_pid(0, _SD_BUS_CREDS_ALL, &creds);
+        assert_se(r >= 0);
+
+        bus_creds_dump(creds, NULL);
+
+        creds = sd_bus_creds_unref(creds);
+
+        r = sd_bus_creds_new_from_pid(1, _SD_BUS_CREDS_ALL, &creds);
+        if (r != -EACCES) {
+                assert_se(r >= 0);
+                putchar('\n');
+                bus_creds_dump(creds, NULL);
+        }
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
new file mode 100644
index 0000000..b78be54
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -0,0 +1,115 @@
+/*-*- 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-bus.h"
+#include "bus-error.h"
+#include "bus-util.h"
+
+int main(int argc, char *argv[]) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL;
+        const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error");
+        const sd_bus_error temporarily_const_error = {
+                .name = SD_BUS_ERROR_ACCESS_DENIED,
+                .message = "oh! no",
+                ._need_free = -1
+        };
+
+        assert_se(!sd_bus_error_is_set(&error));
+        assert_se(sd_bus_error_set(&error, SD_BUS_ERROR_NOT_SUPPORTED, "xxx") == -ENOTSUP);
+        assert_se(streq(error.name, SD_BUS_ERROR_NOT_SUPPORTED));
+        assert_se(streq(error.message, "xxx"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_NOT_SUPPORTED));
+        assert_se(sd_bus_error_get_errno(&error) == ENOTSUP);
+        assert_se(sd_bus_error_is_set(&error));
+        sd_bus_error_free(&error);
+
+        assert_se(!sd_bus_error_is_set(&error));
+        assert_se(sd_bus_error_setf(&error, SD_BUS_ERROR_FILE_NOT_FOUND, "yyy %i", -1) == -ENOENT);
+        assert_se(streq(error.name, SD_BUS_ERROR_FILE_NOT_FOUND));
+        assert_se(streq(error.message, "yyy -1"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND));
+        assert_se(sd_bus_error_get_errno(&error) == ENOENT);
+        assert_se(sd_bus_error_is_set(&error));
+
+        assert_se(!sd_bus_error_is_set(&second));
+        assert_se(second._need_free == 0);
+        assert_se(error._need_free > 0);
+        assert_se(sd_bus_error_copy(&second, &error) == -ENOENT);
+        assert_se(second._need_free > 0);
+        assert_se(streq(error.name, second.name));
+        assert_se(streq(error.message, second.message));
+        assert_se(sd_bus_error_get_errno(&second) == ENOENT);
+        assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_NOT_FOUND));
+        assert_se(sd_bus_error_is_set(&second));
+
+        sd_bus_error_free(&error);
+        sd_bus_error_free(&second);
+
+        assert_se(!sd_bus_error_is_set(&second));
+        assert_se(const_error._need_free == 0);
+        assert_se(sd_bus_error_copy(&second, &const_error) == -EEXIST);
+        assert_se(second._need_free == 0);
+        assert_se(streq(const_error.name, second.name));
+        assert_se(streq(const_error.message, second.message));
+        assert_se(sd_bus_error_get_errno(&second) == EEXIST);
+        assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_EXISTS));
+        assert_se(sd_bus_error_is_set(&second));
+        sd_bus_error_free(&second);
+
+        assert_se(!sd_bus_error_is_set(&second));
+        assert_se(temporarily_const_error._need_free < 0);
+        assert_se(sd_bus_error_copy(&second, &temporarily_const_error) == -EACCES);
+        assert_se(second._need_free > 0);
+        assert_se(streq(temporarily_const_error.name, second.name));
+        assert_se(streq(temporarily_const_error.message, second.message));
+        assert_se(sd_bus_error_get_errno(&second) == EACCES);
+        assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_ACCESS_DENIED));
+        assert_se(sd_bus_error_is_set(&second));
+
+        assert_se(!sd_bus_error_is_set(&error));
+        assert_se(sd_bus_error_set_const(&error, "System.Error.EUCLEAN", "Hallo") == -EUCLEAN);
+        assert_se(streq(error.name, "System.Error.EUCLEAN"));
+        assert_se(streq(error.message, "Hallo"));
+        assert_se(sd_bus_error_has_name(&error, "System.Error.EUCLEAN"));
+        assert_se(sd_bus_error_get_errno(&error) == EUCLEAN);
+        assert_se(sd_bus_error_is_set(&error));
+        sd_bus_error_free(&error);
+
+        assert_se(!sd_bus_error_is_set(&error));
+        assert_se(sd_bus_error_set_errno(&error, EBUSY) == -EBUSY);
+        assert_se(streq(error.name, "System.Error.EBUSY"));
+        assert_se(streq(error.message, strerror(EBUSY)));
+        assert_se(sd_bus_error_has_name(&error, "System.Error.EBUSY"));
+        assert_se(sd_bus_error_get_errno(&error) == EBUSY);
+        assert_se(sd_bus_error_is_set(&error));
+        sd_bus_error_free(&error);
+
+        assert_se(!sd_bus_error_is_set(&error));
+        assert_se(sd_bus_error_set_errnof(&error, EIO, "Waldi %c", 'X') == -EIO);
+        assert_se(streq(error.name, SD_BUS_ERROR_IO_ERROR));
+        assert_se(streq(error.message, "Waldi X"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR));
+        assert_se(sd_bus_error_get_errno(&error) == EIO);
+        assert_se(sd_bus_error_is_set(&error));
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c
new file mode 100644
index 0000000..cb07c96
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-gvariant.c
@@ -0,0 +1,201 @@
+/*-*- 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/>.
+***/
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#endif
+
+#include "util.h"
+#include "sd-bus.h"
+#include "bus-gvariant.h"
+#include "bus-util.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-dump.h"
+
+static void test_bus_gvariant_is_fixed_size(void) {
+        assert(bus_gvariant_is_fixed_size("") > 0);
+        assert(bus_gvariant_is_fixed_size("()") > 0);
+        assert(bus_gvariant_is_fixed_size("y") > 0);
+        assert(bus_gvariant_is_fixed_size("u") > 0);
+        assert(bus_gvariant_is_fixed_size("b") > 0);
+        assert(bus_gvariant_is_fixed_size("n") > 0);
+        assert(bus_gvariant_is_fixed_size("q") > 0);
+        assert(bus_gvariant_is_fixed_size("i") > 0);
+        assert(bus_gvariant_is_fixed_size("t") > 0);
+        assert(bus_gvariant_is_fixed_size("d") > 0);
+        assert(bus_gvariant_is_fixed_size("s") == 0);
+        assert(bus_gvariant_is_fixed_size("o") == 0);
+        assert(bus_gvariant_is_fixed_size("g") == 0);
+        assert(bus_gvariant_is_fixed_size("h") > 0);
+        assert(bus_gvariant_is_fixed_size("ay") == 0);
+        assert(bus_gvariant_is_fixed_size("v") == 0);
+        assert(bus_gvariant_is_fixed_size("(u)") > 0);
+        assert(bus_gvariant_is_fixed_size("(uuuuy)") > 0);
+        assert(bus_gvariant_is_fixed_size("(uusuuy)") == 0);
+        assert(bus_gvariant_is_fixed_size("a{ss}") == 0);
+        assert(bus_gvariant_is_fixed_size("((u)yyy(b(iiii)))") > 0);
+        assert(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0);
+}
+
+static void test_bus_gvariant_get_size(void) {
+        assert(bus_gvariant_get_size("") == 0);
+        assert(bus_gvariant_get_size("()") == 0);
+        assert(bus_gvariant_get_size("y") == 1);
+        assert(bus_gvariant_get_size("u") == 4);
+        assert(bus_gvariant_get_size("b") == 1);
+        assert(bus_gvariant_get_size("n") == 2);
+        assert(bus_gvariant_get_size("q") == 2);
+        assert(bus_gvariant_get_size("i") == 4);
+        assert(bus_gvariant_get_size("t") == 8);
+        assert(bus_gvariant_get_size("d") == 8);
+        assert(bus_gvariant_get_size("s") < 0);
+        assert(bus_gvariant_get_size("o") < 0);
+        assert(bus_gvariant_get_size("g") < 0);
+        assert(bus_gvariant_get_size("h") == 4);
+        assert(bus_gvariant_get_size("ay") < 0);
+        assert(bus_gvariant_get_size("v") < 0);
+        assert(bus_gvariant_get_size("(u)") == 4);
+        assert(bus_gvariant_get_size("(uuuuy)") == 20);
+        assert(bus_gvariant_get_size("(uusuuy)") < 0);
+        assert(bus_gvariant_get_size("a{ss}") < 0);
+        assert(bus_gvariant_get_size("((u)yyy(b(iiii)))") == 28);
+        assert(bus_gvariant_get_size("((u)yyy(b(iiivi)))") < 0);
+        assert(bus_gvariant_get_size("((b)(t))") == 16);
+        assert(bus_gvariant_get_size("((b)(b)(t))") == 16);
+        assert(bus_gvariant_get_size("(bt)") == 16);
+        assert(bus_gvariant_get_size("((t)(b))") == 16);
+        assert(bus_gvariant_get_size("(tb)") == 16);
+        assert(bus_gvariant_get_size("((b)(b))") == 2);
+        assert(bus_gvariant_get_size("((t)(t))") == 16);
+}
+
+static void test_bus_gvariant_get_alignment(void) {
+        assert(bus_gvariant_get_alignment("") == 1);
+        assert(bus_gvariant_get_alignment("()") == 1);
+        assert(bus_gvariant_get_alignment("y") == 1);
+        assert(bus_gvariant_get_alignment("b") == 1);
+        assert(bus_gvariant_get_alignment("u") == 4);
+        assert(bus_gvariant_get_alignment("s") == 1);
+        assert(bus_gvariant_get_alignment("o") == 1);
+        assert(bus_gvariant_get_alignment("g") == 1);
+        assert(bus_gvariant_get_alignment("v") == 8);
+        assert(bus_gvariant_get_alignment("h") == 4);
+        assert(bus_gvariant_get_alignment("i") == 4);
+        assert(bus_gvariant_get_alignment("t") == 8);
+        assert(bus_gvariant_get_alignment("x") == 8);
+        assert(bus_gvariant_get_alignment("q") == 2);
+        assert(bus_gvariant_get_alignment("n") == 2);
+        assert(bus_gvariant_get_alignment("d") == 8);
+        assert(bus_gvariant_get_alignment("ay") == 1);
+        assert(bus_gvariant_get_alignment("as") == 1);
+        assert(bus_gvariant_get_alignment("au") == 4);
+        assert(bus_gvariant_get_alignment("an") == 2);
+        assert(bus_gvariant_get_alignment("ans") == 2);
+        assert(bus_gvariant_get_alignment("ant") == 8);
+        assert(bus_gvariant_get_alignment("(ss)") == 1);
+        assert(bus_gvariant_get_alignment("(ssu)") == 4);
+        assert(bus_gvariant_get_alignment("a(ssu)") == 4);
+        assert(bus_gvariant_get_alignment("(u)") == 4);
+        assert(bus_gvariant_get_alignment("(uuuuy)") == 4);
+        assert(bus_gvariant_get_alignment("(uusuuy)") == 4);
+        assert(bus_gvariant_get_alignment("a{ss}") == 1);
+        assert(bus_gvariant_get_alignment("((u)yyy(b(iiii)))") == 4);
+        assert(bus_gvariant_get_alignment("((u)yyy(b(iiivi)))") == 8);
+        assert(bus_gvariant_get_alignment("((b)(t))") == 8);
+        assert(bus_gvariant_get_alignment("((b)(b)(t))") == 8);
+        assert(bus_gvariant_get_alignment("(bt)") == 8);
+        assert(bus_gvariant_get_alignment("((t)(b))") == 8);
+        assert(bus_gvariant_get_alignment("(tb)") == 8);
+        assert(bus_gvariant_get_alignment("((b)(b))") == 1);
+        assert(bus_gvariant_get_alignment("((t)(t))") == 8);
+}
+
+static void test_marshal(void) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL;
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        _cleanup_free_ void *blob;
+        size_t sz;
+
+        assert_se(sd_bus_open_system(&bus) >= 0);
+        bus->message_version = 2; /* dirty hack to enable gvariant*/
+
+        assert_se(sd_bus_message_new_method_call(bus, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName", &m) >= 0);
+
+        assert_se(sd_bus_message_append(m,
+                                        "a(usv)", 3,
+                                        4711, "first-string-parameter", "(st)", "X", (uint64_t) 1111,
+                                        4712, "second-string-parameter", "(a(si))", 2, "Y", 5, "Z", 6,
+                                        4713, "third-string-parameter", "(uu)", 1, 2) >= 0);
+
+        assert_se(bus_message_seal(m, 4711, 0) >= 0);
+
+#ifdef HAVE_GLIB
+        {
+                GVariant *v;
+                char *t;
+
+#if !defined(GLIB_VERSION_2_36)
+                g_type_init();
+#endif
+
+                v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuuua(yv))"), m->header, sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m), false, NULL, NULL);
+                t = g_variant_print(v, TRUE);
+                printf("%s\n", t);
+                g_free(t);
+                g_variant_unref(v);
+
+                v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, BUS_MESSAGE_BODY_SIZE(m), false, NULL, NULL);
+                t = g_variant_print(v, TRUE);
+                printf("%s\n", t);
+                g_free(t);
+                g_variant_unref(v);
+        }
+#endif
+
+        assert_se(bus_message_dump(m, NULL, true) >= 0);
+
+        assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
+
+        assert_se(bus_message_from_malloc(NULL, blob, sz, NULL, 0, NULL, NULL, &n) >= 0);
+        blob = NULL;
+
+        assert_se(bus_message_dump(n, NULL, true) >= 0);
+
+        m = sd_bus_message_unref(m);
+
+        assert_se(sd_bus_message_new_method_call(bus, "a.x", "/a/x", "a.x", "Ax", &m) >= 0);
+
+        assert_se(sd_bus_message_append(m, "as", 0) >= 0);
+
+        assert_se(bus_message_seal(m, 4712, 0) >= 0);
+        assert_se(bus_message_dump(m, NULL, true) >= 0);
+}
+
+int main(int argc, char *argv[]) {
+
+        test_bus_gvariant_is_fixed_size();
+        test_bus_gvariant_get_size();
+        test_bus_gvariant_get_alignment();
+        test_marshal();
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c
new file mode 100644
index 0000000..67b6461
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-introspect.c
@@ -0,0 +1,66 @@
+/*-*- 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 "util.h"
+#include "log.h"
+#include "bus-introspect.h"
+
+static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+        return -EINVAL;
+}
+
+static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+        return -EINVAL;
+}
+
+static const sd_bus_vtable vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0),
+        SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED),
+        SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY),
+        SD_BUS_SIGNAL("Wowza", "sss", 0),
+        SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
+        SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0),
+        SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED),
+        SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+        SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_VTABLE_END
+};
+
+int main(int argc, char *argv[]) {
+        struct introspect intro;
+
+        log_set_max_level(LOG_DEBUG);
+
+        assert_se(introspect_begin(&intro, false) >= 0);
+
+        fprintf(intro.f, " <interface name=\"org.foo\">\n");
+        assert_se(introspect_write_interface(&intro, vtable) >= 0);
+        fputs(" </interface>\n", intro.f);
+
+        fflush(intro.f);
+        fputs(intro.introspection, stdout);
+
+        introspect_free(&intro);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c b/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c
new file mode 100644
index 0000000..04627d9
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c
@@ -0,0 +1,303 @@
+/*-*- 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 <ctype.h>
+#include <sys/wait.h>
+
+#include "util.h"
+#include "log.h"
+#include "time-util.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+
+#define MAX_SIZE (4*1024*1024)
+
+static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
+
+static void server(sd_bus *b, size_t *result) {
+        int r;
+
+        for (;;) {
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+                r = sd_bus_process(b, &m);
+                assert_se(r >= 0);
+
+                if (r == 0)
+                        assert_se(sd_bus_wait(b, (usec_t) -1) >= 0);
+                if (!m)
+                        continue;
+
+                if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping"))
+                        assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
+                else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
+                        const void *p;
+                        size_t sz;
+
+                        /* Make sure the mmap is mapped */
+                        assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
+
+                        assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
+                } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
+                        uint64_t res;
+                        assert_se(sd_bus_message_read(m, "t", &res) > 0);
+
+                        *result = res;
+                        return;
+
+                } else
+                        assert_not_reached("Unknown method");
+        }
+}
+
+static void transaction(sd_bus *b, size_t sz) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+        uint8_t *p;
+
+        assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Work", &m) >= 0);
+        assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
+
+        memset(p, 0x80, sz);
+
+        assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0);
+}
+
+static void client_bisect(const char *address) {
+        _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
+        size_t lsize, rsize, csize;
+        sd_bus *b;
+        int r;
+
+        r = sd_bus_new(&b);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(b, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(b);
+        assert_se(r >= 0);
+
+        assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
+
+        lsize = 1;
+        rsize = MAX_SIZE;
+
+        printf("SIZE\tCOPY\tMEMFD\n");
+
+        for (;;) {
+                usec_t t;
+                unsigned n_copying, n_memfd;
+
+                csize = (lsize + rsize) / 2;
+
+                if (csize <= lsize)
+                        break;
+
+                if (csize <= 0)
+                        break;
+
+                printf("%zu\t", csize);
+
+                b->use_memfd = 0;
+
+                t = now(CLOCK_MONOTONIC);
+                for (n_copying = 0;; n_copying++) {
+                        transaction(b, csize);
+                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
+                                break;
+                }
+                printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
+
+                b->use_memfd = -1;
+
+                t = now(CLOCK_MONOTONIC);
+                for (n_memfd = 0;; n_memfd++) {
+                        transaction(b, csize);
+                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
+                                break;
+                }
+                printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
+
+                if (n_copying == n_memfd)
+                        break;
+
+                if (n_copying > n_memfd)
+                        lsize = csize;
+                else
+                        rsize = csize;
+        }
+
+        b->use_memfd = 1;
+        assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
+        assert_se(sd_bus_message_append(x, "t", csize) >= 0);
+        assert_se(sd_bus_send(b, x, NULL) >= 0);
+
+        sd_bus_unref(b);
+}
+
+static void client_chart(const char *address) {
+        _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
+        size_t csize;
+        sd_bus *b;
+        int r;
+
+        r = sd_bus_new(&b);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(b, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(b);
+        assert_se(r >= 0);
+
+        assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
+
+        printf("SIZE\tCOPY\tMEMFD\n");
+
+        for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
+                usec_t t;
+                unsigned n_copying, n_memfd;
+
+                printf("%zu\t", csize);
+
+                b->use_memfd = 0;
+
+                t = now(CLOCK_MONOTONIC);
+                for (n_copying = 0;; n_copying++) {
+                        transaction(b, csize);
+                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
+                                break;
+                }
+
+                printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
+
+                b->use_memfd = -1;
+
+                t = now(CLOCK_MONOTONIC);
+                for (n_memfd = 0;; n_memfd++) {
+                        transaction(b, csize);
+                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
+                                break;
+                }
+
+                printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
+        }
+
+        b->use_memfd = 1;
+        assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
+        assert_se(sd_bus_message_append(x, "t", csize) >= 0);
+        assert_se(sd_bus_send(b, x, NULL) >= 0);
+
+        sd_bus_unref(b);
+}
+
+int main(int argc, char *argv[]) {
+        enum {
+                MODE_BISECT,
+                MODE_CHART,
+        } mode = MODE_BISECT;
+        int i;
+        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+        _cleanup_close_ int bus_ref = -1;
+        cpu_set_t cpuset;
+        size_t result;
+        sd_bus *b;
+        pid_t pid;
+        int r;
+
+        for (i = 1; i < argc; i++) {
+                if (streq(argv[i], "chart")) {
+                        mode = MODE_CHART;
+                        continue;
+                }
+
+                assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
+        }
+
+        assert_se(arg_loop_usec > 0);
+
+        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+
+        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
+        if (bus_ref == -ENOENT)
+                exit(EXIT_TEST_SKIP);
+
+        assert_se(bus_ref >= 0);
+
+        address = strappend("kernel:path=", bus_name);
+        assert_se(address);
+
+        r = sd_bus_new(&b);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(b, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(b);
+        assert_se(r >= 0);
+
+        sync();
+        setpriority(PRIO_PROCESS, 0, -19);
+
+        pid = fork();
+        assert_se(pid >= 0);
+
+        if (pid == 0) {
+                CPU_ZERO(&cpuset);
+                CPU_SET(0, &cpuset);
+                pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+
+                close_nointr_nofail(bus_ref);
+                sd_bus_unref(b);
+
+                switch (mode) {
+                case MODE_BISECT:
+                        client_bisect(address);
+                        break;
+
+                case MODE_CHART:
+                        client_chart(address);
+                        break;
+                }
+
+                _exit(0);
+        }
+
+        CPU_ZERO(&cpuset);
+        CPU_SET(1, &cpuset);
+        pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+
+        server(b, &result);
+
+        if (mode == MODE_BISECT)
+                printf("Copying/memfd are equally fast at %zu bytes\n", result);
+
+        assert_se(waitpid(pid, NULL, 0) == pid);
+
+        sd_bus_unref(b);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
new file mode 100644
index 0000000..0ecad18
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
@@ -0,0 +1,115 @@
+/*-*- 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 "util.h"
+#include "log.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
+
+static void test_one(
+                const char *path,
+                const char *interface,
+                const char *member,
+                const char *arg0,
+                const char *match,
+                bool good) {
+
+        _cleanup_close_ int bus_ref = -1;
+        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        sd_bus *a, *b;
+        int r;
+
+        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+
+        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
+        if (bus_ref == -ENOENT)
+                exit(EXIT_TEST_SKIP);
+
+        assert_se(bus_ref >= 0);
+
+        address = strappend("kernel:path=", bus_name);
+        assert_se(address);
+
+        r = sd_bus_new(&a);
+        assert_se(r >= 0);
+
+        r = sd_bus_new(&b);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(a, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(b, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(a);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(b);
+        assert_se(r >= 0);
+
+        log_debug("match");
+        r = sd_bus_add_match(b, match, NULL, NULL);
+        assert_se(r >= 0);
+
+        log_debug("signal");
+        r = sd_bus_emit_signal(a, path, interface, member, "s", arg0);
+        assert_se(r >= 0);
+
+        r = sd_bus_process(b, &m);
+        assert_se(r >= 0 && (good == !!m));
+
+        sd_bus_unref(a);
+        sd_bus_unref(b);
+}
+
+int main(int argc, char *argv[]) {
+        log_set_max_level(LOG_DEBUG);
+
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/tuut'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "interface='waldo.com'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Piep'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Pi_ep'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foobar'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foo_bar'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
+
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/quux'", false);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar/waldo'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/'", true);
+        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/quux'", false);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c
new file mode 100644
index 0000000..9b17a35
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-kernel.c
@@ -0,0 +1,175 @@
+/*-*- 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 <fcntl.h>
+
+#include "util.h"
+#include "log.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
+#include "bus-dump.h"
+
+int main(int argc, char *argv[]) {
+        _cleanup_close_ int bus_ref = -1;
+        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *ua = NULL, *ub = NULL, *the_string = NULL;
+        sd_bus *a, *b;
+        int r, pipe_fds[2];
+
+        log_set_max_level(LOG_DEBUG);
+
+        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+
+        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
+        if (bus_ref == -ENOENT)
+                return EXIT_TEST_SKIP;
+
+        assert_se(bus_ref >= 0);
+
+        address = strappend("kernel:path=", bus_name);
+        assert_se(address);
+
+        r = sd_bus_new(&a);
+        assert_se(r >= 0);
+
+        r = sd_bus_new(&b);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(a, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(b, address);
+        assert_se(r >= 0);
+
+        assert_se(sd_bus_negotiate_attach_timestamp(a, 1) >= 0);
+        assert_se(sd_bus_negotiate_attach_creds(a, _SD_BUS_CREDS_ALL) >= 0);
+
+        assert_se(sd_bus_negotiate_attach_timestamp(b, 1) >= 0);
+        assert_se(sd_bus_negotiate_attach_creds(b, _SD_BUS_CREDS_ALL) >= 0);
+
+        r = sd_bus_start(a);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(b);
+        assert_se(r >= 0);
+
+        r = sd_bus_get_unique_name(a, &ua);
+        assert_se(r >= 0);
+
+        printf("unique a: %s\n", ua);
+
+        r = sd_bus_get_unique_name(b, &ub);
+        assert_se(r >= 0);
+
+        printf("unique b: %s\n", ub);
+
+        r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay");
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
+        assert_se(r == -EHOSTUNREACH);
+
+        r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL);
+        assert_se(r >= 0);
+
+        r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name");
+        assert_se(r >= 0);
+
+        r = sd_bus_try_close(b);
+        assert_se(r == -EBUSY);
+
+        r = sd_bus_process(b, &m);
+        assert_se(r > 0);
+        assert_se(m);
+
+        bus_message_dump(m, stdout, true);
+        assert_se(sd_bus_message_rewind(m, true) >= 0);
+
+        r = sd_bus_message_read(m, "s", &the_string);
+        assert_se(r >= 0);
+        assert_se(streq(the_string, "I am a string"));
+
+        sd_bus_message_unref(m);
+        m = NULL;
+
+        r = sd_bus_request_name(a, "net.x0pointer.foobar", 0);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_new_method_call(b, "net.x0pointer.foobar", "/a/path", "an.inter.face", "AMethod", &m);
+        assert_se(r >= 0);
+
+        assert_se(pipe2(pipe_fds, O_CLOEXEC) >= 0);
+
+        assert_se(write(pipe_fds[1], "x", 1) == 1);
+
+        close_nointr_nofail(pipe_fds[1]);
+        pipe_fds[1] = -1;
+
+        r = sd_bus_message_append(m, "h", pipe_fds[0]);
+        assert_se(r >= 0);
+
+        close_nointr_nofail(pipe_fds[0]);
+        pipe_fds[0] = -1;
+
+        r = sd_bus_send(b, m, NULL);
+        assert_se(r >= 0);
+
+        for (;;) {
+                sd_bus_message_unref(m);
+                m = NULL;
+                r = sd_bus_process(a, &m);
+                assert_se(r > 0);
+                assert_se(m);
+
+                bus_message_dump(m, stdout, true);
+                assert_se(sd_bus_message_rewind(m, true) >= 0);
+
+                if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) {
+                        int fd;
+                        char x;
+
+                        r = sd_bus_message_read(m, "h", &fd);
+                        assert_se(r >= 0);
+
+                        assert_se(read(fd, &x, 1) == 1);
+                        assert_se(x == 'x');
+                        break;
+                }
+        }
+
+        r = sd_bus_release_name(a, "net.x0pointer.foobar");
+        assert_se(r >= 0);
+
+        r = sd_bus_release_name(a, "net.x0pointer.foobar");
+        assert_se(r == -ESRCH);
+
+        r = sd_bus_try_close(a);
+        assert_se(r >= 0);
+
+        sd_bus_unref(a);
+        sd_bus_unref(b);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
new file mode 100644
index 0000000..4fad049
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -0,0 +1,324 @@
+/*-*- 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 <assert.h>
+#include <stdlib.h>
+#include <byteswap.h>
+
+#ifdef HAVE_GLIB
+#include <gio/gio.h>
+#endif
+
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+#endif
+
+#include "log.h"
+#include "util.h"
+
+#include "sd-bus.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "bus-dump.h"
+
+static void test_bus_label_escape_one(const char *a, const char *b) {
+        _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
+
+        assert_se(t = sd_bus_label_escape(a));
+        assert_se(streq(t, b));
+
+        assert_se(x = sd_bus_label_unescape(t));
+        assert_se(streq(a, x));
+
+        assert_se(y = sd_bus_label_unescape(b));
+        assert_se(streq(a, y));
+}
+
+static void test_bus_label_escape(void) {
+        test_bus_label_escape_one("foo123bar", "foo123bar");
+        test_bus_label_escape_one("foo.bar", "foo_2ebar");
+        test_bus_label_escape_one("foo_2ebar", "foo_5f2ebar");
+        test_bus_label_escape_one("", "_");
+        test_bus_label_escape_one("_", "_5f");
+        test_bus_label_escape_one("1", "_31");
+        test_bus_label_escape_one(":1", "_3a1");
+}
+
+int main(int argc, char *argv[]) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *copy = NULL;
+        int r, boolean;
+        const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature;
+        uint8_t u, v;
+        void *buffer = NULL;
+        size_t sz;
+        char *h;
+        const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
+        char *s;
+        _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
+        _cleanup_fclose_ FILE *ms = NULL;
+        size_t first_size = 0, second_size = 0, third_size = 0;
+
+        r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &m);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "s", "a string");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "s", NULL);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "asg", 2, "string #1", "string #2", "sba(tt)ss");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_open_container(m, 'a', "s");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append_basic(m, 's', "foobar");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append_basic(m, 's', "waldo");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_close_container(m);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append_string_space(m, 5, &s);
+        assert_se(r >= 0);
+        strcpy(s, "hallo");
+
+        r = sd_bus_message_append_array(m, 'i', integer_array, sizeof(integer_array));
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append_array(m, 'u', NULL, 0);
+        assert_se(r >= 0);
+
+        r = bus_message_seal(m, 4711, 0);
+        assert_se(r >= 0);
+
+        bus_message_dump(m, stdout, true);
+
+        ms = open_memstream(&first, &first_size);
+        bus_message_dump(m, ms, false);
+        fflush(ms);
+        assert_se(!ferror(ms));
+
+        r = bus_message_get_blob(m, &buffer, &sz);
+        assert_se(r >= 0);
+
+        h = hexmem(buffer, sz);
+        assert_se(h);
+
+        log_info("message size = %lu, contents =\n%s", (unsigned long) sz, h);
+        free(h);
+
+#ifdef HAVE_GLIB
+        {
+                GDBusMessage *g;
+                char *p;
+
+#if !defined(GLIB_VERSION_2_36)
+                g_type_init();
+#endif
+
+                g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL);
+                p = g_dbus_message_print(g, 0);
+                log_info("%s", p);
+                g_free(p);
+                g_object_unref(g);
+        }
+#endif
+
+#ifdef HAVE_DBUS
+        {
+                DBusMessage *w;
+                DBusError error;
+
+                dbus_error_init(&error);
+
+                w = dbus_message_demarshal(buffer, sz, &error);
+                if (!w)
+                        log_error("%s", error.message);
+                else
+                        dbus_message_unref(w);
+        }
+#endif
+
+        m = sd_bus_message_unref(m);
+
+        r = bus_message_from_malloc(NULL, buffer, sz, NULL, 0, NULL, NULL, &m);
+        assert_se(r >= 0);
+
+        bus_message_dump(m, stdout, true);
+
+        fclose(ms);
+        ms = open_memstream(&second, &second_size);
+        bus_message_dump(m, ms, false);
+        fflush(ms);
+        assert_se(!ferror(ms));
+        assert_se(first_size == second_size);
+        assert_se(memcmp(first, second, first_size) == 0);
+
+        assert_se(sd_bus_message_rewind(m, true) >= 0);
+
+        r = sd_bus_message_read(m, "ssasg", &x, &x2, 2, &y, &z, &a_signature);
+        assert_se(r > 0);
+        assert_se(streq(x, "a string"));
+        assert_se(streq(x2, ""));
+        assert_se(streq(y, "string #1"));
+        assert_se(streq(z, "string #2"));
+        assert_se(streq(a_signature, "sba(tt)ss"));
+
+        r = sd_bus_message_read(m, "sass", &x, 5, &y, &z, &a, &b, &c, &d);
+        assert_se(r > 0);
+        assert_se(streq(x, "foobar"));
+        assert_se(streq(y, "foo"));
+        assert_se(streq(z, "bar"));
+        assert_se(streq(a, "waldo"));
+        assert_se(streq(b, "piep"));
+        assert_se(streq(c, "pap"));
+        assert_se(streq(d, "after"));
+
+        r = sd_bus_message_read(m, "a{yv}", 2, &u, "s", &x, &v, "s", &y);
+        assert_se(r > 0);
+        assert_se(u == 3);
+        assert_se(streq(x, "foo"));
+        assert_se(v == 5);
+        assert_se(streq(y, "waldo"));
+
+        r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
+        assert_se(r > 0);
+        assert_se(boolean);
+        assert_se(streq(x, "aaa"));
+        assert_se(streq(y, "1"));
+        assert_se(streq(a, "bbb"));
+        assert_se(streq(b, "2"));
+        assert_se(streq(c, "ccc"));
+        assert_se(streq(d, "3"));
+
+        assert_se(sd_bus_message_verify_type(m, 'a', "s") > 0);
+
+        r = sd_bus_message_read(m, "as", 2, &x, &y);
+        assert_se(r > 0);
+        assert_se(streq(x, "foobar"));
+        assert_se(streq(y, "waldo"));
+
+        r = sd_bus_message_read_basic(m, 's', &s);
+        assert_se(r > 0);
+        assert_se(streq(s, "hallo"));
+
+        r = sd_bus_message_read_array(m, 'i', (const void**) &return_array, &sz);
+        assert_se(r > 0);
+        assert_se(sz == sizeof(integer_array));
+        assert_se(memcmp(integer_array, return_array, sz) == 0);
+
+        r = sd_bus_message_read_array(m, 'u', (const void**) &return_array, &sz);
+        assert_se(r > 0);
+        assert_se(sz == 0);
+
+        r = sd_bus_message_peek_type(m, NULL, NULL);
+        assert_se(r == 0);
+
+        r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &copy);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_rewind(m, true);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_copy(copy, m, true);
+        assert_se(r >= 0);
+
+        r = bus_message_seal(copy, 4712, 0);
+        assert_se(r >= 0);
+
+        fclose(ms);
+        ms = open_memstream(&third, &third_size);
+        bus_message_dump(copy, ms, false);
+        fflush(ms);
+        assert_se(!ferror(ms));
+
+        printf("<%.*s>\n", (int) first_size, first);
+        printf("<%.*s>\n", (int) third_size, third);
+
+        assert_se(first_size == third_size);
+        assert_se(memcmp(first, third, third_size) == 0);
+
+        r = sd_bus_message_rewind(m, true);
+        assert_se(r >= 0);
+
+        assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
+
+        r = sd_bus_message_skip(m, "ssasg");
+        assert_se(r > 0);
+
+        assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
+
+        r = sd_bus_message_skip(m, "sass");
+        assert_se(r >= 0);
+
+        assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
+
+        r = sd_bus_message_skip(m, "a{yv}");
+        assert_se(r >= 0);
+
+        assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);
+
+        r = sd_bus_message_read(m, "b", &boolean);
+        assert_se(r > 0);
+        assert_se(boolean);
+
+        r = sd_bus_message_enter_container(m, 0, NULL);
+        assert_se(r > 0);
+
+        r = sd_bus_message_read(m, "(ss)", &x, &y);
+        assert_se(r > 0);
+
+        r = sd_bus_message_read(m, "(ss)", &a, &b);
+        assert_se(r > 0);
+
+        r = sd_bus_message_read(m, "(ss)", &c, &d);
+        assert_se(r > 0);
+
+        r = sd_bus_message_read(m, "(ss)", &x, &y);
+        assert_se(r == 0);
+
+        r = sd_bus_message_exit_container(m);
+        assert_se(r >= 0);
+
+        assert_se(streq(x, "aaa"));
+        assert_se(streq(y, "1"));
+        assert_se(streq(a, "bbb"));
+        assert_se(streq(b, "2"));
+        assert_se(streq(c, "ccc"));
+        assert_se(streq(d, "3"));
+
+        test_bus_label_escape();
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c
new file mode 100644
index 0000000..7227e25
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-match.c
@@ -0,0 +1,145 @@
+/*-*- 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 <assert.h>
+
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+
+#include "bus-match.h"
+#include "bus-message.h"
+#include "bus-util.h"
+
+static bool mask[32];
+
+static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        log_info("Ran %i", PTR_TO_INT(userdata));
+        mask[PTR_TO_INT(userdata)] = true;
+        return 0;
+}
+
+static bool mask_contains(unsigned a[], unsigned n) {
+        unsigned i, j;
+
+        for (i = 0; i < ELEMENTSOF(mask); i++) {
+                bool found = false;
+
+                for (j = 0; j < n; j++)
+                        if (a[j] == i) {
+                                found = true;
+                                break;
+                        }
+
+                if (found != mask[i])
+                        return false;
+        }
+
+        return true;
+}
+
+static int match_add(struct bus_match_node *root, const char *match, int value) {
+        struct bus_match_component *components = NULL;
+        unsigned n_components = 0;
+        int r;
+
+        r = bus_match_parse(match, &components, &n_components);
+        if (r < 0)
+                return r;
+
+        r = bus_match_add(root, components, n_components, filter, INT_TO_PTR(value), 0, NULL);
+        bus_match_parse_free(components, n_components);
+
+        return r;
+}
+
+static int match_remove(struct bus_match_node *root, const char *match, int value) {
+        struct bus_match_component *components = NULL;
+        unsigned n_components = 0;
+        int r;
+
+        r = bus_match_parse(match, &components, &n_components);
+        if (r < 0)
+                return r;
+
+        r = bus_match_remove(root, components, n_components, filter, INT_TO_PTR(value), 0);
+        bus_match_parse_free(components, n_components);
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        struct bus_match_node root;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        enum bus_match_node_type i;
+
+        zero(root);
+        root.type = BUS_MATCH_ROOT;
+
+        assert_se(match_add(&root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
+        assert_se(match_add(&root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
+        assert_se(match_add(&root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
+        assert_se(match_add(&root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
+        assert_se(match_add(&root, "", 5) >= 0);
+        assert_se(match_add(&root, "interface='quux.x'", 6) >= 0);
+        assert_se(match_add(&root, "interface='bar.x'", 7) >= 0);
+        assert_se(match_add(&root, "member='waldo',path='/foo/bar'", 8) >= 0);
+        assert_se(match_add(&root, "path='/foo/bar'", 9) >= 0);
+        assert_se(match_add(&root, "path_namespace='/foo'", 10) >= 0);
+        assert_se(match_add(&root, "path_namespace='/foo/quux'", 11) >= 0);
+        assert_se(match_add(&root, "arg1='two'", 12) >= 0);
+        assert_se(match_add(&root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
+        assert_se(match_add(&root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
+
+        bus_match_dump(&root, 0);
+
+        assert_se(sd_bus_message_new_signal(NULL, "/foo/bar", "bar.x", "waldo", &m) >= 0);
+        assert_se(sd_bus_message_append(m, "ssss", "one", "two", "/prefix/three", "prefix.four") >= 0);
+        assert_se(bus_message_seal(m, 1, 0) >= 0);
+
+        zero(mask);
+        assert_se(bus_match_run(NULL, &root, m) == 0);
+        assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
+
+        assert_se(match_remove(&root, "member='waldo',path='/foo/bar'", 8) > 0);
+        assert_se(match_remove(&root, "arg2path='/prefix/',member='waldo'", 13) > 0);
+        assert_se(match_remove(&root, "interface='bar.xx'", 7) == 0);
+
+        bus_match_dump(&root, 0);
+
+        zero(mask);
+        assert_se(bus_match_run(NULL, &root, m) == 0);
+        assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7 }, 6));
+
+        for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
+                char buf[32];
+                const char *x;
+
+                assert_se(x = bus_match_node_type_to_string(i, buf, sizeof(buf)));
+
+                if (i >= BUS_MATCH_MESSAGE_TYPE)
+                        assert_se(bus_match_node_type_from_string(x, strlen(x)) == i);
+        }
+
+        bus_match_free(&root);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-memfd.c b/src/libsystemd/sd-bus/test-bus-memfd.c
new file mode 100644
index 0000000..b9d6a25
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-memfd.c
@@ -0,0 +1,174 @@
+/*-*- 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 <sys/mman.h>
+#include <sys/uio.h>
+
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+
+#include "sd-memfd.h"
+
+int main(int argc, char *argv[]) {
+        sd_memfd *m;
+        char *s;
+        uint64_t sz;
+        int r, fd;
+        FILE *f;
+        char buf[3] = {};
+        struct iovec iov[3] = {};
+        char bufv[3][3] = {};
+
+        log_set_max_level(LOG_DEBUG);
+
+        r = sd_memfd_new(&m);
+        if (r == -ENOENT)
+                return EXIT_TEST_SKIP;
+
+        r = sd_memfd_map(m, 0, 12, (void**) &s);
+        assert_se(r >= 0);
+
+        strcpy(s, "----- world");
+
+        r = sd_memfd_set_sealed(m, 1);
+        assert_se(r == -ETXTBSY);
+
+        assert_se(write(sd_memfd_get_fd(m), "he", 2) == 2);
+        assert_se(write(sd_memfd_get_fd(m), "XXX", 3) == 3);
+        assert_se(streq(s, "heXXX world"));
+
+        /* fix "hello" */
+        assert_se(lseek(sd_memfd_get_fd(m), 2, SEEK_SET) == 2);
+        assert_se(write(sd_memfd_get_fd(m), "ll", 2) == 2);
+
+        assert_se(sd_memfd_get_file(m, &f) >= 0);
+        fputc('o', f);
+        fflush(f);
+
+        /* check content  */
+        assert_se(streq(s, "hello world"));
+
+        assert_se(munmap(s, 12) == 0);
+
+        r = sd_memfd_get_sealed(m);
+        assert_se(r == 0);
+
+        r = sd_memfd_get_size(m, &sz);
+        assert_se(r >= 0);
+        assert_se(sz = page_size());
+
+        /* truncate it */
+        r = sd_memfd_set_size(m, 6);
+        assert_se(r >= 0);
+
+        /* get back new value */
+        r = sd_memfd_get_size(m, &sz);
+        assert_se(r >= 0);
+        assert_se(sz == 6);
+
+        r = sd_memfd_set_sealed(m, 1);
+        assert_se(r >= 0);
+
+        r = sd_memfd_get_sealed(m);
+        assert_se(r == 1);
+
+        fd = sd_memfd_dup_fd(m);
+        assert_se(fd >= 0);
+
+        sd_memfd_free(m);
+
+        /* new sd_memfd, same underlying memfd */
+        r = sd_memfd_make(fd, &m);
+        assert_se(r >= 0);
+
+        /* we did truncate it to 6 */
+        r = sd_memfd_get_size(m, &sz);
+        assert_se(r >= 0 && sz == 6);
+
+        /* map it, check content */
+        r = sd_memfd_map(m, 0, 12, (void **)&s);
+        assert_se(r >= 0);
+
+        /* we only see the truncated size */
+        assert_se(streq(s, "hello "));
+
+        /* it was already sealed */
+        r = sd_memfd_set_sealed(m, 1);
+        assert_se(r == -EALREADY);
+
+        /* we cannot break the seal, it is mapped */
+        r = sd_memfd_set_sealed(m, 0);
+        assert_se(r == -ETXTBSY);
+
+        /* unmap it; become the single owner */
+        assert_se(munmap(s, 12) == 0);
+
+        /* now we can do flip the sealing */
+        r = sd_memfd_set_sealed(m, 0);
+        assert_se(r == 0);
+        r = sd_memfd_get_sealed(m);
+        assert_se(r == 0);
+
+        r = sd_memfd_set_sealed(m, 1);
+        assert_se(r == 0);
+        r = sd_memfd_get_sealed(m);
+        assert_se(r == 1);
+
+        r = sd_memfd_set_sealed(m, 0);
+        assert_se(r == 0);
+        r = sd_memfd_get_sealed(m);
+        assert_se(r == 0);
+
+        /* seek at 2, read() 2 bytes */
+        assert_se(lseek(fd, 2, SEEK_SET) == 2);
+        assert_se(read(fd, buf, 2) == 2);
+
+        /* check content */
+        assert_se(memcmp(buf, "ll", 2) == 0);
+
+        /* writev it out*/
+        iov[0].iov_base = (char *)"ABC";
+        iov[0].iov_len = 3;
+        iov[1].iov_base = (char *)"DEF";
+        iov[1].iov_len = 3;
+        iov[2].iov_base = (char *)"GHI";
+        iov[2].iov_len = 3;
+        assert_se(pwritev(fd, iov, 3, 0) == 9);
+
+        /* readv it back */
+        iov[0].iov_base = bufv[0];
+        iov[0].iov_len = 3;
+        iov[1].iov_base = bufv[1];
+        iov[1].iov_len = 3;
+        iov[2].iov_base = bufv[2];
+        iov[2].iov_len = 3;
+        assert_se(preadv(fd, iov, 3, 0) == 9);
+
+        /* check content */
+        assert_se(memcmp(bufv[0], "ABC", 3) == 0);
+        assert_se(memcmp(bufv[1], "DEF", 3) == 0);
+        assert_se(memcmp(bufv[2], "GHI", 3) == 0);
+
+        sd_memfd_free(m);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
new file mode 100644
index 0000000..e2423c7
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -0,0 +1,500 @@
+/*-*- 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 <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+#include "strv.h"
+
+#include "sd-bus.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "bus-dump.h"
+
+struct context {
+        int fds[2];
+        bool quit;
+        char *something;
+        char *automatic_string_property;
+        uint32_t automatic_integer_property;
+};
+
+static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        struct context *c = userdata;
+        const char *s;
+        char *n = NULL;
+        int r;
+
+        r = sd_bus_message_read(m, "s", &s);
+        assert_se(r > 0);
+
+        n = strjoin("<<<", s, ">>>", NULL);
+        assert_se(n);
+
+        free(c->something);
+        c->something = n;
+
+        log_info("AlterSomething() called, got %s, returning %s", s, n);
+
+        /* This should fail, since the return type doesn't match */
+        assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
+
+        r = sd_bus_reply_method_return(m, "s", n);
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        struct context *c = userdata;
+        int r;
+
+        c->quit = true;
+
+        log_info("Exit called");
+
+        r = sd_bus_reply_method_return(m, "");
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+        struct context *c = userdata;
+        int r;
+
+        log_info("property get for %s called, returning \"%s\".", property, c->something);
+
+        r = sd_bus_message_append(reply, "s", c->something);
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
+        struct context *c = userdata;
+        const char *s;
+        char *n;
+        int r;
+
+        log_info("property set for %s called", property);
+
+        r = sd_bus_message_read(value, "s", &s);
+        assert_se(r >= 0);
+
+        n = strdup(s);
+        assert_se(n);
+
+        free(c->something);
+        c->something = n;
+
+        return 1;
+}
+
+static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+        _cleanup_free_ char *s = NULL;
+        const char *x;
+        int r;
+
+        assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
+        r = sd_bus_message_append(reply, "s", s);
+        assert_se(r >= 0);
+
+        assert_se(x = startswith(path, "/value/"));
+
+        assert_se(PTR_TO_UINT(userdata) == 30);
+
+        return 1;
+}
+
+static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int r;
+
+        assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
+
+        r = sd_bus_reply_method_return(m, NULL);
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int r;
+
+        assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
+
+        r = sd_bus_reply_method_return(m, NULL);
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int r;
+
+        assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
+
+        r = sd_bus_reply_method_return(m, NULL);
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int r;
+
+        assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
+
+        r = sd_bus_reply_method_return(m, NULL);
+        assert_se(r >= 0);
+
+        return 1;
+}
+
+static const sd_bus_vtable vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
+        SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
+        SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
+        SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
+        SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
+        SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
+        SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
+        SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
+        SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable vtable2[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
+        SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
+        SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+        SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
+        SD_BUS_VTABLE_END
+};
+
+static int enumerator_callback(sd_bus *b, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+
+        if (object_path_startswith("/value", path))
+                assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
+
+        return 1;
+}
+
+static void *server(void *p) {
+        struct context *c = p;
+        sd_bus *bus = NULL;
+        sd_id128_t id;
+        int r;
+
+        c->quit = false;
+
+        assert_se(sd_id128_randomize(&id) >= 0);
+
+        assert_se(sd_bus_new(&bus) >= 0);
+        assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
+        assert_se(sd_bus_set_server(bus, 1, id) >= 0);
+
+        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
+        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
+        assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
+        assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
+        assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
+
+        assert_se(sd_bus_start(bus) >= 0);
+
+        log_error("Entering event loop on server");
+
+        while (!c->quit) {
+                log_error("Loop!");
+
+                r = sd_bus_process(bus, NULL);
+                if (r < 0) {
+                        log_error("Failed to process requests: %s", strerror(-r));
+                        goto fail;
+                }
+
+                if (r == 0) {
+                        r = sd_bus_wait(bus, (uint64_t) -1);
+                        if (r < 0) {
+                                log_error("Failed to wait: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        continue;
+                }
+        }
+
+        r = 0;
+
+fail:
+        if (bus) {
+                sd_bus_flush(bus);
+                sd_bus_unref(bus);
+        }
+
+        return INT_TO_PTR(r);
+}
+
+static int client(struct context *c) {
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *s;
+        int r;
+
+        assert_se(sd_bus_new(&bus) >= 0);
+        assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
+        assert_se(sd_bus_start(bus) >= 0);
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
+        assert_se(r >= 0);
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        assert_se(streq(s, "<<<hallo>>>"));
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        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, 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, SD_BUS_ERROR_INVALID_ARGS));
+
+        sd_bus_error_free(&error);
+
+        r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        assert_se(streq(s, "<<<hallo>>>"));
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
+        assert_se(r >= 0);
+
+        r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        assert_se(streq(s, "test"));
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
+        assert_se(r >= 0);
+
+        assert_se(c->automatic_integer_property == 815);
+
+        r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
+        assert_se(r >= 0);
+
+        assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        fputs(s, stdout);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        log_info("read %s", s);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        fputs(s, stdout);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        fputs(s, stdout);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_read(reply, "s", &s);
+        assert_se(r >= 0);
+        fputs(s, stdout);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
+        assert_se(r >= 0);
+
+        bus_message_dump(reply, stdout, true);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        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, 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, 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, "");
+        assert_se(r >= 0);
+
+        bus_message_dump(reply, stdout, true);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_process(bus, &reply);
+        assert_se(r > 0);
+
+        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
+        bus_message_dump(reply, stdout, true);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_process(bus, &reply);
+        assert_se(r > 0);
+
+        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
+        bus_message_dump(reply, stdout, true);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_process(bus, &reply);
+        assert_se(r > 0);
+
+        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
+        bus_message_dump(reply, stdout, true);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
+        assert_se(r >= 0);
+
+        r = sd_bus_process(bus, &reply);
+        assert_se(r > 0);
+
+        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
+        bus_message_dump(reply, stdout, true);
+
+        sd_bus_message_unref(reply);
+        reply = NULL;
+
+        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
+        assert_se(r >= 0);
+
+        sd_bus_flush(bus);
+
+        return 0;
+}
+
+int main(int argc, char *argv[]) {
+        struct context c = {};
+        pthread_t s;
+        void *p;
+        int r, q;
+
+        zero(c);
+
+        c.automatic_integer_property = 4711;
+        assert_se(c.automatic_string_property = strdup("dudeldu"));
+
+        assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
+
+        r = pthread_create(&s, NULL, server, &c);
+        if (r != 0)
+                return -r;
+
+        r = client(&c);
+
+        q = pthread_join(s, &p);
+        if (q != 0)
+                return -q;
+
+        if (r < 0)
+                return r;
+
+        if (PTR_TO_INT(p) < 0)
+                return PTR_TO_INT(p);
+
+        free(c.something);
+        free(c.automatic_string_property);
+
+        return EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c
new file mode 100644
index 0000000..0e65ee7
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-server.c
@@ -0,0 +1,224 @@
+/*-*- 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 <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+
+#include "sd-bus.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-util.h"
+
+struct context {
+        int fds[2];
+
+        bool client_negotiate_unix_fds;
+        bool server_negotiate_unix_fds;
+
+        bool client_anonymous_auth;
+        bool server_anonymous_auth;
+};
+
+static void *server(void *p) {
+        struct context *c = p;
+        sd_bus *bus = NULL;
+        sd_id128_t id;
+        bool quit = false;
+        int r;
+
+        assert_se(sd_id128_randomize(&id) >= 0);
+
+        assert_se(sd_bus_new(&bus) >= 0);
+        assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
+        assert_se(sd_bus_set_server(bus, 1, id) >= 0);
+        assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0);
+        assert_se(sd_bus_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0);
+        assert_se(sd_bus_start(bus) >= 0);
+
+        while (!quit) {
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+
+                r = sd_bus_process(bus, &m);
+                if (r < 0) {
+                        log_error("Failed to process requests: %s", strerror(-r));
+                        goto fail;
+                }
+
+                if (r == 0) {
+                        r = sd_bus_wait(bus, (uint64_t) -1);
+                        if (r < 0) {
+                                log_error("Failed to wait: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        continue;
+                }
+
+                if (!m)
+                        continue;
+
+                log_info("Got message! member=%s", strna(sd_bus_message_get_member(m)));
+
+                if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) {
+
+                        assert_se((sd_bus_can_send(bus, 'h') >= 1) == (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds));
+
+                        r = sd_bus_message_new_method_return(m, &reply);
+                        if (r < 0) {
+                                log_error("Failed to allocate return: %s", strerror(-r));
+                                goto fail;
+                        }
+
+                        quit = true;
+
+                } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
+                        r = sd_bus_message_new_method_error(
+                                        m,
+                                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."),
+                                        &reply);
+                        if (r < 0) {
+                                log_error("Failed to allocate return: %s", strerror(-r));
+                                goto fail;
+                        }
+                }
+
+                if (reply) {
+                        r = sd_bus_send(bus, reply, NULL);
+                        if (r < 0) {
+                                log_error("Failed to send reply: %s", strerror(-r));
+                                goto fail;
+                        }
+                }
+        }
+
+        r = 0;
+
+fail:
+        if (bus) {
+                sd_bus_flush(bus);
+                sd_bus_unref(bus);
+        }
+
+        return INT_TO_PTR(r);
+}
+
+static int client(struct context *c) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert_se(sd_bus_new(&bus) >= 0);
+        assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
+        assert_se(sd_bus_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0);
+        assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0);
+        assert_se(sd_bus_start(bus) >= 0);
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.systemd.test",
+                        "/",
+                        "org.freedesktop.systemd.test",
+                        "Exit",
+                        &m);
+        if (r < 0) {
+                log_error("Failed to allocate method call: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_bus_call(bus, m, 0, &error, &reply);
+        if (r < 0) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
+                return r;
+        }
+
+        return 0;
+}
+
+static int test_one(bool client_negotiate_unix_fds, bool server_negotiate_unix_fds,
+                    bool client_anonymous_auth, bool server_anonymous_auth) {
+
+        struct context c;
+        pthread_t s;
+        void *p;
+        int r, q;
+
+        zero(c);
+
+        assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
+
+        c.client_negotiate_unix_fds = client_negotiate_unix_fds;
+        c.server_negotiate_unix_fds = server_negotiate_unix_fds;
+        c.client_anonymous_auth = client_anonymous_auth;
+        c.server_anonymous_auth = server_anonymous_auth;
+
+        r = pthread_create(&s, NULL, server, &c);
+        if (r != 0)
+                return -r;
+
+        r = client(&c);
+
+        q = pthread_join(s, &p);
+        if (q != 0)
+                return -q;
+
+        if (r < 0)
+                return r;
+
+        if (PTR_TO_INT(p) < 0)
+                return PTR_TO_INT(p);
+
+        return 0;
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+
+        r = test_one(true, true, false, false);
+        assert_se(r >= 0);
+
+        r = test_one(true, false, false, false);
+        assert_se(r >= 0);
+
+        r = test_one(false, true, false, false);
+        assert_se(r >= 0);
+
+        r = test_one(false, false, false, false);
+        assert_se(r >= 0);
+
+        r = test_one(true, true, true, true);
+        assert_se(r >= 0);
+
+        r = test_one(true, true, false, true);
+        assert_se(r >= 0);
+
+        r = test_one(true, true, true, false);
+        assert_se(r == -EPERM);
+
+        return EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c
new file mode 100644
index 0000000..3fc565c
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-signature.c
@@ -0,0 +1,163 @@
+/*-*- 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 <assert.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "bus-signature.h"
+#include "bus-internal.h"
+
+int main(int argc, char *argv[]) {
+        char prefix[256];
+        int r;
+
+        assert_se(signature_is_single("y", false));
+        assert_se(signature_is_single("u", false));
+        assert_se(signature_is_single("v", false));
+        assert_se(signature_is_single("as", false));
+        assert_se(signature_is_single("(ss)", false));
+        assert_se(signature_is_single("()", false));
+        assert_se(signature_is_single("(()()()()())", false));
+        assert_se(signature_is_single("(((())))", false));
+        assert_se(signature_is_single("((((s))))", false));
+        assert_se(signature_is_single("{ss}", true));
+        assert_se(signature_is_single("a{ss}", false));
+        assert_se(!signature_is_single("uu", false));
+        assert_se(!signature_is_single("", false));
+        assert_se(!signature_is_single("(", false));
+        assert_se(!signature_is_single(")", false));
+        assert_se(!signature_is_single("())", false));
+        assert_se(!signature_is_single("((())", false));
+        assert_se(!signature_is_single("{)", false));
+        assert_se(!signature_is_single("{}", true));
+        assert_se(!signature_is_single("{sss}", true));
+        assert_se(!signature_is_single("{s}", true));
+        assert_se(!signature_is_single("{ss}", false));
+        assert_se(!signature_is_single("{ass}", true));
+        assert_se(!signature_is_single("a}", true));
+
+        assert_se(signature_is_pair("yy"));
+        assert_se(signature_is_pair("ss"));
+        assert_se(signature_is_pair("sas"));
+        assert_se(signature_is_pair("sv"));
+        assert_se(signature_is_pair("sa(vs)"));
+        assert_se(!signature_is_pair(""));
+        assert_se(!signature_is_pair("va"));
+        assert_se(!signature_is_pair("sss"));
+        assert_se(!signature_is_pair("{s}ss"));
+
+        assert_se(signature_is_valid("ssa{ss}sssub", true));
+        assert_se(signature_is_valid("ssa{ss}sssub", false));
+        assert_se(signature_is_valid("{ss}", true));
+        assert_se(!signature_is_valid("{ss}", false));
+        assert_se(signature_is_valid("", true));
+        assert_se(signature_is_valid("", false));
+
+        assert_se(signature_is_valid("sssusa(uuubbba(uu)uuuu)a{u(uuuvas)}", false));
+
+        assert_se(!signature_is_valid("a", false));
+        assert_se(signature_is_valid("as", false));
+        assert_se(signature_is_valid("aas", false));
+        assert_se(signature_is_valid("aaas", false));
+        assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad", false));
+        assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false));
+        assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false));
+
+        assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false));
+        assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
+
+        assert_se(namespace_complex_pattern("", ""));
+        assert_se(namespace_complex_pattern("foobar", "foobar"));
+        assert_se(namespace_complex_pattern("foobar.waldo", "foobar.waldo"));
+        assert_se(namespace_complex_pattern("foobar.", "foobar.waldo"));
+        assert_se(namespace_complex_pattern("foobar.waldo", "foobar."));
+        assert_se(!namespace_complex_pattern("foobar.waldo", "foobar"));
+        assert_se(!namespace_complex_pattern("foobar", "foobar.waldo"));
+        assert_se(!namespace_complex_pattern("", "foo"));
+        assert_se(!namespace_complex_pattern("foo", ""));
+        assert_se(!namespace_complex_pattern("foo.", ""));
+
+        assert_se(path_complex_pattern("", ""));
+        assert_se(path_complex_pattern("", "/"));
+        assert_se(path_complex_pattern("/", ""));
+        assert_se(path_complex_pattern("/", "/"));
+        assert_se(path_complex_pattern("/foobar/", "/"));
+        assert_se(path_complex_pattern("/foobar/", "/foobar"));
+        assert_se(path_complex_pattern("/foobar", "/foobar"));
+        assert_se(path_complex_pattern("/foobar", "/foobar/"));
+        assert_se(!path_complex_pattern("/foobar", "/foobar/waldo"));
+        assert_se(path_complex_pattern("/foobar/", "/foobar/waldo"));
+
+        assert_se(namespace_simple_pattern("", ""));
+        assert_se(namespace_simple_pattern("foobar", "foobar"));
+        assert_se(namespace_simple_pattern("foobar.waldo", "foobar.waldo"));
+        assert_se(namespace_simple_pattern("foobar", "foobar.waldo"));
+        assert_se(!namespace_simple_pattern("foobar.waldo", "foobar"));
+        assert_se(!namespace_simple_pattern("", "foo"));
+        assert_se(!namespace_simple_pattern("foo", ""));
+
+        assert_se(streq(object_path_startswith("/foo/bar", "/foo"), "bar"));
+        assert_se(streq(object_path_startswith("/foo", "/foo"), ""));
+        assert_se(streq(object_path_startswith("/foo", "/"), "foo"));
+        assert_se(streq(object_path_startswith("/", "/"), ""));
+        assert_se(!object_path_startswith("/foo", "/bar"));
+        assert_se(!object_path_startswith("/", "/bar"));
+        assert_se(!object_path_startswith("/foo", ""));
+
+        assert_se(object_path_is_valid("/foo/bar"));
+        assert_se(object_path_is_valid("/foo"));
+        assert_se(object_path_is_valid("/"));
+        assert_se(object_path_is_valid("/foo5"));
+        assert_se(object_path_is_valid("/foo_5"));
+        assert_se(!object_path_is_valid(""));
+        assert_se(!object_path_is_valid("/foo/"));
+        assert_se(!object_path_is_valid("//"));
+        assert_se(!object_path_is_valid("//foo"));
+        assert_se(!object_path_is_valid("/foo//bar"));
+        assert_se(!object_path_is_valid("/foo/aaaäöä"));
+
+        OBJECT_PATH_FOREACH_PREFIX(prefix, "/") {
+                log_info("<%s>", prefix);
+                assert_not_reached("???");
+        }
+
+        r = 0;
+        OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx") {
+                log_info("<%s>", prefix);
+                assert_se(streq(prefix, "/"));
+                assert_se(r == 0);
+                r++;
+        }
+        assert_se(r == 1);
+
+        r = 0;
+        OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx/yyy/zzz") {
+                log_info("<%s>", prefix);
+                assert_se(r != 0 || streq(prefix, "/xxx/yyy"));
+                assert_se(r != 1 || streq(prefix, "/xxx"));
+                assert_se(r != 2 || streq(prefix, "/"));
+                r++;
+        }
+        assert_se(r == 3);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c
new file mode 100644
index 0000000..5ad8ed5
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c
@@ -0,0 +1,197 @@
+/*-*- 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 <fcntl.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "log.h"
+
+#include "sd-bus.h"
+#include "sd-memfd.h"
+#include "bus-message.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-dump.h"
+
+#define FIRST_ARRAY 17
+#define SECOND_ARRAY 33
+
+#define STRING_SIZE 123
+
+int main(int argc, char *argv[]) {
+        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+        uint8_t *p;
+        sd_bus *a, *b;
+        int r, bus_ref;
+        sd_bus_message *m;
+        sd_memfd *f;
+        uint64_t sz;
+        uint32_t u32;
+        size_t i, l;
+        char *s;
+
+        log_set_max_level(LOG_DEBUG);
+
+        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+
+        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
+        if (bus_ref == -ENOENT)
+                return EXIT_TEST_SKIP;
+
+        assert_se(bus_ref >= 0);
+
+        address = strappend("kernel:path=", bus_name);
+        assert_se(address);
+
+        r = sd_bus_new(&a);
+        assert_se(r >= 0);
+
+        r = sd_bus_new(&b);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(a, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_set_address(b, address);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(a);
+        assert_se(r >= 0);
+
+        r = sd_bus_start(b);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_new_method_call(b, ":1.1", "/a/path", "an.inter.face", "AMethod", &m);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_open_container(m, 'r', "aysay");
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append_array_space(m, 'y', FIRST_ARRAY, (void**) &p);
+        assert_se(r >= 0);
+
+        p[0] = '<';
+        memset(p+1, 'L', FIRST_ARRAY-2);
+        p[FIRST_ARRAY-1] = '>';
+
+        r = sd_memfd_new_and_map(&f, STRING_SIZE, (void**) &s);
+        assert_se(r >= 0);
+
+        s[0] = '<';
+        for (i = 1; i < STRING_SIZE-2; i++)
+                s[i] = '0' + (i % 10);
+        s[STRING_SIZE-2] = '>';
+        s[STRING_SIZE-1] = 0;
+        munmap(s, STRING_SIZE);
+
+        r = sd_memfd_get_size(f, &sz);
+        assert_se(r >= 0);
+        assert_se(sz == STRING_SIZE);
+
+        r = sd_bus_message_append_string_memfd(m, f);
+        assert_se(r >= 0);
+
+        sd_memfd_free(f);
+
+        r = sd_memfd_new_and_map(&f, SECOND_ARRAY, (void**) &p);
+        assert_se(r >= 0);
+
+        p[0] = '<';
+        memset(p+1, 'P', SECOND_ARRAY-2);
+        p[SECOND_ARRAY-1] = '>';
+        munmap(p, SECOND_ARRAY);
+
+        r = sd_memfd_get_size(f, &sz);
+        assert_se(r >= 0);
+        assert_se(sz == SECOND_ARRAY);
+
+        r = sd_bus_message_append_array_memfd(m, 'y', f);
+        assert_se(r >= 0);
+
+        sd_memfd_free(f);
+
+        r = sd_bus_message_close_container(m);
+        assert_se(r >= 0);
+
+        r = sd_bus_message_append(m, "u", 4711);
+        assert_se(r >= 0);
+
+        r = bus_message_seal(m, 55, 99*USEC_PER_SEC);
+        assert_se(r >= 0);
+
+        bus_message_dump(m, stdout, true);
+
+        r = sd_bus_send(b, m, NULL);
+        assert_se(r >= 0);
+
+        sd_bus_message_unref(m);
+
+        r = sd_bus_process(a, &m);
+        assert_se(r > 0);
+
+        bus_message_dump(m, stdout, true);
+        sd_bus_message_rewind(m, true);
+
+        r = sd_bus_message_enter_container(m, 'r', "aysay");
+        assert_se(r > 0);
+
+        r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l);
+        assert_se(r > 0);
+        assert_se(l == FIRST_ARRAY);
+
+        assert_se(p[0] == '<');
+        for (i = 1; i < l-1; i++)
+                assert_se(p[i] == 'L');
+        assert_se(p[l-1] == '>');
+
+        r = sd_bus_message_read(m, "s", &s);
+        assert_se(r > 0);
+
+        assert_se(s[0] == '<');
+        for (i = 1; i < STRING_SIZE-2; i++)
+                assert_se(s[i] == (char) ('0' + (i % 10)));
+        assert_se(s[STRING_SIZE-2] == '>');
+        assert_se(s[STRING_SIZE-1] == 0);
+
+        r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l);
+        assert_se(r > 0);
+        assert_se(l == SECOND_ARRAY);
+
+        assert_se(p[0] == '<');
+        for (i = 1; i < l-1; i++)
+                assert_se(p[i] == 'P');
+        assert_se(p[l-1] == '>');
+
+        r = sd_bus_message_exit_container(m);
+        assert_se(r > 0);
+
+        r = sd_bus_message_read(m, "u", &u32);
+        assert_se(r > 0);
+        assert_se(u32 == 4711);
+
+        sd_bus_message_unref(m);
+
+        sd_bus_unref(a);
+        sd_bus_unref(b);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-event.c b/src/libsystemd/sd-event.c
deleted file mode 100644
index f33a9ec..0000000
--- a/src/libsystemd/sd-event.c
+++ /dev/null
@@ -1,2224 +0,0 @@
-/*-*- 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 <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <sys/wait.h>
-#include <pthread.h>
-
-#include "sd-id128.h"
-#include "sd-daemon.h"
-#include "macro.h"
-#include "prioq.h"
-#include "hashmap.h"
-#include "util.h"
-#include "time-util.h"
-#include "missing.h"
-
-#include "sd-event.h"
-
-#define EPOLL_QUEUE_MAX 512U
-#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
-
-typedef enum EventSourceType {
-        SOURCE_IO,
-        SOURCE_MONOTONIC,
-        SOURCE_REALTIME,
-        SOURCE_SIGNAL,
-        SOURCE_CHILD,
-        SOURCE_DEFER,
-        SOURCE_EXIT,
-        SOURCE_WATCHDOG
-} EventSourceType;
-
-struct sd_event_source {
-        unsigned n_ref;
-
-        sd_event *event;
-        void *userdata;
-        sd_event_handler_t prepare;
-
-        EventSourceType type:4;
-        int enabled:3;
-        bool pending:1;
-        bool dispatching:1;
-
-        int64_t priority;
-        unsigned pending_index;
-        unsigned prepare_index;
-        unsigned pending_iteration;
-        unsigned prepare_iteration;
-
-        union {
-                struct {
-                        sd_event_io_handler_t callback;
-                        int fd;
-                        uint32_t events;
-                        uint32_t revents;
-                        bool registered:1;
-                } io;
-                struct {
-                        sd_event_time_handler_t callback;
-                        usec_t next, accuracy;
-                        unsigned earliest_index;
-                        unsigned latest_index;
-                } time;
-                struct {
-                        sd_event_signal_handler_t callback;
-                        struct signalfd_siginfo siginfo;
-                        int sig;
-                } signal;
-                struct {
-                        sd_event_child_handler_t callback;
-                        siginfo_t siginfo;
-                        pid_t pid;
-                        int options;
-                } child;
-                struct {
-                        sd_event_handler_t callback;
-                } defer;
-                struct {
-                        sd_event_handler_t callback;
-                        unsigned prioq_index;
-                } exit;
-        };
-};
-
-struct sd_event {
-        unsigned n_ref;
-
-        int epoll_fd;
-        int signal_fd;
-        int realtime_fd;
-        int monotonic_fd;
-        int watchdog_fd;
-
-        Prioq *pending;
-        Prioq *prepare;
-
-        /* For both clocks we maintain two priority queues each, one
-         * ordered for the earliest times the events may be
-         * dispatched, and one ordered by the latest times they must
-         * have been dispatched. The range between the top entries in
-         * the two prioqs is the time window we can freely schedule
-         * wakeups in */
-        Prioq *monotonic_earliest;
-        Prioq *monotonic_latest;
-        Prioq *realtime_earliest;
-        Prioq *realtime_latest;
-
-        usec_t realtime_next, monotonic_next;
-        usec_t perturb;
-
-        sigset_t sigset;
-        sd_event_source **signal_sources;
-
-        Hashmap *child_sources;
-        unsigned n_enabled_child_sources;
-
-        Prioq *exit;
-
-        pid_t original_pid;
-
-        unsigned iteration;
-        dual_timestamp timestamp;
-        int state;
-
-        bool exit_requested:1;
-        bool need_process_child:1;
-        bool watchdog:1;
-
-        int exit_code;
-
-        pid_t tid;
-        sd_event **default_event_ptr;
-
-        usec_t watchdog_last, watchdog_period;
-
-        unsigned n_sources;
-};
-
-static int pending_prioq_compare(const void *a, const void *b) {
-        const sd_event_source *x = a, *y = b;
-
-        assert(x->pending);
-        assert(y->pending);
-
-        /* Enabled ones first */
-        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
-                return -1;
-        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
-                return 1;
-
-        /* Lower priority values first */
-        if (x->priority < y->priority)
-                return -1;
-        if (x->priority > y->priority)
-                return 1;
-
-        /* Older entries first */
-        if (x->pending_iteration < y->pending_iteration)
-                return -1;
-        if (x->pending_iteration > y->pending_iteration)
-                return 1;
-
-        /* Stability for the rest */
-        if (x < y)
-                return -1;
-        if (x > y)
-                return 1;
-
-        return 0;
-}
-
-static int prepare_prioq_compare(const void *a, const void *b) {
-        const sd_event_source *x = a, *y = b;
-
-        assert(x->prepare);
-        assert(y->prepare);
-
-        /* Move most recently prepared ones last, so that we can stop
-         * preparing as soon as we hit one that has already been
-         * prepared in the current iteration */
-        if (x->prepare_iteration < y->prepare_iteration)
-                return -1;
-        if (x->prepare_iteration > y->prepare_iteration)
-                return 1;
-
-        /* Enabled ones first */
-        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
-                return -1;
-        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
-                return 1;
-
-        /* Lower priority values first */
-        if (x->priority < y->priority)
-                return -1;
-        if (x->priority > y->priority)
-                return 1;
-
-        /* Stability for the rest */
-        if (x < y)
-                return -1;
-        if (x > y)
-                return 1;
-
-        return 0;
-}
-
-static int earliest_time_prioq_compare(const void *a, const void *b) {
-        const sd_event_source *x = a, *y = b;
-
-        assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME);
-        assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME);
-
-        /* Enabled ones first */
-        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
-                return -1;
-        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
-                return 1;
-
-        /* Move the pending ones to the end */
-        if (!x->pending && y->pending)
-                return -1;
-        if (x->pending && !y->pending)
-                return 1;
-
-        /* Order by time */
-        if (x->time.next < y->time.next)
-                return -1;
-        if (x->time.next > y->time.next)
-                return 1;
-
-        /* Stability for the rest */
-        if (x < y)
-                return -1;
-        if (x > y)
-                return 1;
-
-        return 0;
-}
-
-static int latest_time_prioq_compare(const void *a, const void *b) {
-        const sd_event_source *x = a, *y = b;
-
-        assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) ||
-               (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME));
-
-        /* Enabled ones first */
-        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
-                return -1;
-        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
-                return 1;
-
-        /* Move the pending ones to the end */
-        if (!x->pending && y->pending)
-                return -1;
-        if (x->pending && !y->pending)
-                return 1;
-
-        /* Order by time */
-        if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy)
-                return -1;
-        if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
-                return 1;
-
-        /* Stability for the rest */
-        if (x < y)
-                return -1;
-        if (x > y)
-                return 1;
-
-        return 0;
-}
-
-static int exit_prioq_compare(const void *a, const void *b) {
-        const sd_event_source *x = a, *y = b;
-
-        assert(x->type == SOURCE_EXIT);
-        assert(y->type == SOURCE_EXIT);
-
-        /* Enabled ones first */
-        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
-                return -1;
-        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
-                return 1;
-
-        /* Lower priority values first */
-        if (x->priority < y->priority)
-                return -1;
-        if (x->priority > y->priority)
-                return 1;
-
-        /* Stability for the rest */
-        if (x < y)
-                return -1;
-        if (x > y)
-                return 1;
-
-        return 0;
-}
-
-static void event_free(sd_event *e) {
-        assert(e);
-        assert(e->n_sources == 0);
-
-        if (e->default_event_ptr)
-                *(e->default_event_ptr) = NULL;
-
-        if (e->epoll_fd >= 0)
-                close_nointr_nofail(e->epoll_fd);
-
-        if (e->signal_fd >= 0)
-                close_nointr_nofail(e->signal_fd);
-
-        if (e->realtime_fd >= 0)
-                close_nointr_nofail(e->realtime_fd);
-
-        if (e->monotonic_fd >= 0)
-                close_nointr_nofail(e->monotonic_fd);
-
-        if (e->watchdog_fd >= 0)
-                close_nointr_nofail(e->watchdog_fd);
-
-        prioq_free(e->pending);
-        prioq_free(e->prepare);
-        prioq_free(e->monotonic_earliest);
-        prioq_free(e->monotonic_latest);
-        prioq_free(e->realtime_earliest);
-        prioq_free(e->realtime_latest);
-        prioq_free(e->exit);
-
-        free(e->signal_sources);
-
-        hashmap_free(e->child_sources);
-        free(e);
-}
-
-_public_ int sd_event_new(sd_event** ret) {
-        sd_event *e;
-        int r;
-
-        assert_return(ret, -EINVAL);
-
-        e = new0(sd_event, 1);
-        if (!e)
-                return -ENOMEM;
-
-        e->n_ref = 1;
-        e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1;
-        e->realtime_next = e->monotonic_next = (usec_t) -1;
-        e->original_pid = getpid();
-
-        assert_se(sigemptyset(&e->sigset) == 0);
-
-        e->pending = prioq_new(pending_prioq_compare);
-        if (!e->pending) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        e->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-        if (e->epoll_fd < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        *ret = e;
-        return 0;
-
-fail:
-        event_free(e);
-        return r;
-}
-
-_public_ sd_event* sd_event_ref(sd_event *e) {
-        assert_return(e, NULL);
-
-        assert(e->n_ref >= 1);
-        e->n_ref++;
-
-        return e;
-}
-
-_public_ sd_event* sd_event_unref(sd_event *e) {
-
-        if (!e)
-                return NULL;
-
-        assert(e->n_ref >= 1);
-        e->n_ref--;
-
-        if (e->n_ref <= 0)
-                event_free(e);
-
-        return NULL;
-}
-
-static bool event_pid_changed(sd_event *e) {
-        assert(e);
-
-        /* We don't support people creating am event loop and keeping
-         * it around over a fork(). Let's complain. */
-
-        return e->original_pid != getpid();
-}
-
-static int source_io_unregister(sd_event_source *s) {
-        int r;
-
-        assert(s);
-        assert(s->type == SOURCE_IO);
-
-        if (!s->io.registered)
-                return 0;
-
-        r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
-        if (r < 0)
-                return -errno;
-
-        s->io.registered = false;
-        return 0;
-}
-
-static int source_io_register(
-                sd_event_source *s,
-                int enabled,
-                uint32_t events) {
-
-        struct epoll_event ev = {};
-        int r;
-
-        assert(s);
-        assert(s->type == SOURCE_IO);
-        assert(enabled != SD_EVENT_OFF);
-
-        ev.events = events;
-        ev.data.ptr = s;
-
-        if (enabled == SD_EVENT_ONESHOT)
-                ev.events |= EPOLLONESHOT;
-
-        if (s->io.registered)
-                r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
-        else
-                r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
-
-        if (r < 0)
-                return -errno;
-
-        s->io.registered = true;
-
-        return 0;
-}
-
-static void source_free(sd_event_source *s) {
-        assert(s);
-
-        if (s->event) {
-                assert(s->event->n_sources > 0);
-
-                switch (s->type) {
-
-                case SOURCE_IO:
-                        if (s->io.fd >= 0)
-                                source_io_unregister(s);
-
-                        break;
-
-                case SOURCE_MONOTONIC:
-                        prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index);
-                        prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index);
-                        break;
-
-                case SOURCE_REALTIME:
-                        prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index);
-                        prioq_remove(s->event->realtime_latest, s, &s->time.latest_index);
-                        break;
-
-                case SOURCE_SIGNAL:
-                        if (s->signal.sig > 0) {
-                                if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
-                                        assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
-
-                                if (s->event->signal_sources)
-                                        s->event->signal_sources[s->signal.sig] = NULL;
-                        }
-
-                        break;
-
-                case SOURCE_CHILD:
-                        if (s->child.pid > 0) {
-                                if (s->enabled != SD_EVENT_OFF) {
-                                        assert(s->event->n_enabled_child_sources > 0);
-                                        s->event->n_enabled_child_sources--;
-                                }
-
-                                if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
-                                        assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
-
-                                hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
-                        }
-
-                        break;
-
-                case SOURCE_DEFER:
-                        /* nothing */
-                        break;
-
-                case SOURCE_EXIT:
-                        prioq_remove(s->event->exit, s, &s->exit.prioq_index);
-                        break;
-
-                case SOURCE_WATCHDOG:
-                        assert_not_reached("Wut? I shouldn't exist.");
-                }
-
-                if (s->pending)
-                        prioq_remove(s->event->pending, s, &s->pending_index);
-
-                if (s->prepare)
-                        prioq_remove(s->event->prepare, s, &s->prepare_index);
-
-                s->event->n_sources--;
-                sd_event_unref(s->event);
-        }
-
-        free(s);
-}
-
-static int source_set_pending(sd_event_source *s, bool b) {
-        int r;
-
-        assert(s);
-        assert(s->type != SOURCE_EXIT);
-
-        if (s->pending == b)
-                return 0;
-
-        s->pending = b;
-
-        if (b) {
-                s->pending_iteration = s->event->iteration;
-
-                r = prioq_put(s->event->pending, s, &s->pending_index);
-                if (r < 0) {
-                        s->pending = false;
-                        return r;
-                }
-        } else
-                assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
-
-        if (s->type == SOURCE_REALTIME) {
-                prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
-                prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
-        } else if (s->type == SOURCE_MONOTONIC) {
-                prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
-                prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
-        }
-
-        return 0;
-}
-
-static sd_event_source *source_new(sd_event *e, EventSourceType type) {
-        sd_event_source *s;
-
-        assert(e);
-
-        s = new0(sd_event_source, 1);
-        if (!s)
-                return NULL;
-
-        s->n_ref = 1;
-        s->event = sd_event_ref(e);
-        s->type = type;
-        s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
-
-        e->n_sources ++;
-
-        return s;
-}
-
-_public_ int sd_event_add_io(
-                sd_event *e,
-                int fd,
-                uint32_t events,
-                sd_event_io_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
-
-        sd_event_source *s;
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(fd >= 0, -EINVAL);
-        assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        s = source_new(e, SOURCE_IO);
-        if (!s)
-                return -ENOMEM;
-
-        s->io.fd = fd;
-        s->io.events = events;
-        s->io.callback = callback;
-        s->userdata = userdata;
-        s->enabled = SD_EVENT_ON;
-
-        r = source_io_register(s, s->enabled, events);
-        if (r < 0) {
-                source_free(s);
-                return -errno;
-        }
-
-        *ret = s;
-        return 0;
-}
-
-static int event_setup_timer_fd(
-                sd_event *e,
-                EventSourceType type,
-                int *timer_fd,
-                clockid_t id) {
-
-        struct epoll_event ev = {};
-        int r, fd;
-        sd_id128_t bootid;
-
-        assert(e);
-        assert(timer_fd);
-
-        if (_likely_(*timer_fd >= 0))
-                return 0;
-
-        fd = timerfd_create(id, TFD_NONBLOCK|TFD_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        ev.events = EPOLLIN;
-        ev.data.ptr = INT_TO_PTR(type);
-
-        r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
-        if (r < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        /* When we sleep for longer, we try to realign the wakeup to
-           the same time wihtin each minute/second/250ms, so that
-           events all across the system can be coalesced into a single
-           CPU wakeup. However, let's take some system-specific
-           randomness for this value, so that in a network of systems
-           with synced clocks timer events are distributed a
-           bit. Here, we calculate a perturbation usec offset from the
-           boot ID. */
-
-        if (sd_id128_get_boot(&bootid) >= 0)
-                e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE;
-
-        *timer_fd = fd;
-        return 0;
-}
-
-static int event_add_time_internal(
-                sd_event *e,
-                EventSourceType type,
-                int *timer_fd,
-                clockid_t id,
-                Prioq **earliest,
-                Prioq **latest,
-                uint64_t usec,
-                uint64_t accuracy,
-                sd_event_time_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
-
-        sd_event_source *s;
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(usec != (uint64_t) -1, -EINVAL);
-        assert_return(accuracy != (uint64_t) -1, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        assert(timer_fd);
-        assert(earliest);
-        assert(latest);
-
-        if (!*earliest) {
-                *earliest = prioq_new(earliest_time_prioq_compare);
-                if (!*earliest)
-                        return -ENOMEM;
-        }
-
-        if (!*latest) {
-                *latest = prioq_new(latest_time_prioq_compare);
-                if (!*latest)
-                        return -ENOMEM;
-        }
-
-        if (*timer_fd < 0) {
-                r = event_setup_timer_fd(e, type, timer_fd, id);
-                if (r < 0)
-                        return r;
-        }
-
-        s = source_new(e, type);
-        if (!s)
-                return -ENOMEM;
-
-        s->time.next = usec;
-        s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
-        s->time.callback = callback;
-        s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
-        s->userdata = userdata;
-        s->enabled = SD_EVENT_ONESHOT;
-
-        r = prioq_put(*earliest, s, &s->time.earliest_index);
-        if (r < 0)
-                goto fail;
-
-        r = prioq_put(*latest, s, &s->time.latest_index);
-        if (r < 0)
-                goto fail;
-
-        *ret = s;
-        return 0;
-
-fail:
-        source_free(s);
-        return r;
-}
-
-_public_ int sd_event_add_monotonic(sd_event *e,
-                                    uint64_t usec,
-                                    uint64_t accuracy,
-                                    sd_event_time_handler_t callback,
-                                    void *userdata,
-                                    sd_event_source **ret) {
-
-        return event_add_time_internal(e, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
-}
-
-_public_ int sd_event_add_realtime(sd_event *e,
-                                   uint64_t usec,
-                                   uint64_t accuracy,
-                                   sd_event_time_handler_t callback,
-                                   void *userdata,
-                                   sd_event_source **ret) {
-
-        return event_add_time_internal(e, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
-}
-
-static int event_update_signal_fd(sd_event *e) {
-        struct epoll_event ev = {};
-        bool add_to_epoll;
-        int r;
-
-        assert(e);
-
-        add_to_epoll = e->signal_fd < 0;
-
-        r = signalfd(e->signal_fd, &e->sigset, SFD_NONBLOCK|SFD_CLOEXEC);
-        if (r < 0)
-                return -errno;
-
-        e->signal_fd = r;
-
-        if (!add_to_epoll)
-                return 0;
-
-        ev.events = EPOLLIN;
-        ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL);
-
-        r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev);
-        if (r < 0) {
-                close_nointr_nofail(e->signal_fd);
-                e->signal_fd = -1;
-
-                return -errno;
-        }
-
-        return 0;
-}
-
-_public_ int sd_event_add_signal(
-                sd_event *e,
-                int sig,
-                sd_event_signal_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
-
-        sd_event_source *s;
-        sigset_t ss;
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(sig > 0, -EINVAL);
-        assert_return(sig < _NSIG, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
-        if (r < 0)
-                return -errno;
-
-        if (!sigismember(&ss, sig))
-                return -EBUSY;
-
-        if (!e->signal_sources) {
-                e->signal_sources = new0(sd_event_source*, _NSIG);
-                if (!e->signal_sources)
-                        return -ENOMEM;
-        } else if (e->signal_sources[sig])
-                return -EBUSY;
-
-        s = source_new(e, SOURCE_SIGNAL);
-        if (!s)
-                return -ENOMEM;
-
-        s->signal.sig = sig;
-        s->signal.callback = callback;
-        s->userdata = userdata;
-        s->enabled = SD_EVENT_ON;
-
-        e->signal_sources[sig] = s;
-        assert_se(sigaddset(&e->sigset, sig) == 0);
-
-        if (sig != SIGCHLD || e->n_enabled_child_sources == 0) {
-                r = event_update_signal_fd(e);
-                if (r < 0) {
-                        source_free(s);
-                        return r;
-                }
-        }
-
-        *ret = s;
-        return 0;
-}
-
-_public_ int sd_event_add_child(
-                sd_event *e,
-                pid_t pid,
-                int options,
-                sd_event_child_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
-
-        sd_event_source *s;
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(pid > 1, -EINVAL);
-        assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
-        assert_return(options != 0, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func);
-        if (r < 0)
-                return r;
-
-        if (hashmap_contains(e->child_sources, INT_TO_PTR(pid)))
-                return -EBUSY;
-
-        s = source_new(e, SOURCE_CHILD);
-        if (!s)
-                return -ENOMEM;
-
-        s->child.pid = pid;
-        s->child.options = options;
-        s->child.callback = callback;
-        s->userdata = userdata;
-        s->enabled = SD_EVENT_ONESHOT;
-
-        r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s);
-        if (r < 0) {
-                source_free(s);
-                return r;
-        }
-
-        e->n_enabled_child_sources ++;
-
-        assert_se(sigaddset(&e->sigset, SIGCHLD) == 0);
-
-        if (!e->signal_sources || !e->signal_sources[SIGCHLD]) {
-                r = event_update_signal_fd(e);
-                if (r < 0) {
-                        source_free(s);
-                        return -errno;
-                }
-        }
-
-        e->need_process_child = true;
-
-        *ret = s;
-        return 0;
-}
-
-_public_ int sd_event_add_defer(
-                sd_event *e,
-                sd_event_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
-
-        sd_event_source *s;
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        s = source_new(e, SOURCE_DEFER);
-        if (!s)
-                return -ENOMEM;
-
-        s->defer.callback = callback;
-        s->userdata = userdata;
-        s->enabled = SD_EVENT_ONESHOT;
-
-        r = source_set_pending(s, true);
-        if (r < 0) {
-                source_free(s);
-                return r;
-        }
-
-        *ret = s;
-        return 0;
-}
-
-_public_ int sd_event_add_exit(
-                sd_event *e,
-                sd_event_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
-
-        sd_event_source *s;
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        if (!e->exit) {
-                e->exit = prioq_new(exit_prioq_compare);
-                if (!e->exit)
-                        return -ENOMEM;
-        }
-
-        s = source_new(e, SOURCE_EXIT);
-        if (!s)
-                return -ENOMEM;
-
-        s->exit.callback = callback;
-        s->userdata = userdata;
-        s->exit.prioq_index = PRIOQ_IDX_NULL;
-        s->enabled = SD_EVENT_ONESHOT;
-
-        r = prioq_put(s->event->exit, s, &s->exit.prioq_index);
-        if (r < 0) {
-                source_free(s);
-                return r;
-        }
-
-        *ret = s;
-        return 0;
-}
-
-_public_ sd_event_source* sd_event_source_ref(sd_event_source *s) {
-        assert_return(s, NULL);
-
-        assert(s->n_ref >= 1);
-        s->n_ref++;
-
-        return s;
-}
-
-_public_ sd_event_source* sd_event_source_unref(sd_event_source *s) {
-
-        if (!s)
-                return NULL;
-
-        assert(s->n_ref >= 1);
-        s->n_ref--;
-
-        if (s->n_ref <= 0) {
-                /* Here's a special hack: when we are called from a
-                 * dispatch handler we won't free the event source
-                 * immediately, but we will detach the fd from the
-                 * epoll. This way it is safe for the caller to unref
-                 * the event source and immediately close the fd, but
-                 * we still retain a valid event source object after
-                 * the callback. */
-
-                if (s->dispatching) {
-                        if (s->type == SOURCE_IO)
-                                source_io_unregister(s);
-                } else
-                        source_free(s);
-        }
-
-        return NULL;
-}
-
-_public_ sd_event *sd_event_source_get_event(sd_event_source *s) {
-        assert_return(s, NULL);
-
-        return s->event;
-}
-
-_public_ int sd_event_source_get_pending(sd_event_source *s) {
-        assert_return(s, -EINVAL);
-        assert_return(s->type != SOURCE_EXIT, -EDOM);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        return s->pending;
-}
-
-_public_ int sd_event_source_get_io_fd(sd_event_source *s) {
-        assert_return(s, -EINVAL);
-        assert_return(s->type == SOURCE_IO, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        return s->io.fd;
-}
-
-_public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
-        int r;
-
-        assert_return(s, -EINVAL);
-        assert_return(fd >= 0, -EINVAL);
-        assert_return(s->type == SOURCE_IO, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        if (s->io.fd == fd)
-                return 0;
-
-        if (s->enabled == SD_EVENT_OFF) {
-                s->io.fd = fd;
-                s->io.registered = false;
-        } else {
-                int saved_fd;
-
-                saved_fd = s->io.fd;
-                assert(s->io.registered);
-
-                s->io.fd = fd;
-                s->io.registered = false;
-
-                r = source_io_register(s, s->enabled, s->io.events);
-                if (r < 0) {
-                        s->io.fd = saved_fd;
-                        s->io.registered = true;
-                        return r;
-                }
-
-                epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
-        }
-
-        return 0;
-}
-
-_public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) {
-        assert_return(s, -EINVAL);
-        assert_return(events, -EINVAL);
-        assert_return(s->type == SOURCE_IO, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        *events = s->io.events;
-        return 0;
-}
-
-_public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) {
-        int r;
-
-        assert_return(s, -EINVAL);
-        assert_return(s->type == SOURCE_IO, -EDOM);
-        assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        if (s->io.events == events)
-                return 0;
-
-        if (s->enabled != SD_EVENT_OFF) {
-                r = source_io_register(s, s->enabled, events);
-                if (r < 0)
-                        return r;
-        }
-
-        s->io.events = events;
-        source_set_pending(s, false);
-
-        return 0;
-}
-
-_public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) {
-        assert_return(s, -EINVAL);
-        assert_return(revents, -EINVAL);
-        assert_return(s->type == SOURCE_IO, -EDOM);
-        assert_return(s->pending, -ENODATA);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        *revents = s->io.revents;
-        return 0;
-}
-
-_public_ int sd_event_source_get_signal(sd_event_source *s) {
-        assert_return(s, -EINVAL);
-        assert_return(s->type == SOURCE_SIGNAL, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        return s->signal.sig;
-}
-
-_public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) {
-        assert_return(s, -EINVAL);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        return s->priority;
-}
-
-_public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) {
-        assert_return(s, -EINVAL);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        if (s->priority == priority)
-                return 0;
-
-        s->priority = priority;
-
-        if (s->pending)
-                prioq_reshuffle(s->event->pending, s, &s->pending_index);
-
-        if (s->prepare)
-                prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
-
-        if (s->type == SOURCE_EXIT)
-                prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
-
-        return 0;
-}
-
-_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
-        assert_return(s, -EINVAL);
-        assert_return(m, -EINVAL);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        *m = s->enabled;
-        return 0;
-}
-
-_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
-        int r;
-
-        assert_return(s, -EINVAL);
-        assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        if (s->enabled == m)
-                return 0;
-
-        if (m == SD_EVENT_OFF) {
-
-                switch (s->type) {
-
-                case SOURCE_IO:
-                        r = source_io_unregister(s);
-                        if (r < 0)
-                                return r;
-
-                        s->enabled = m;
-                        break;
-
-                case SOURCE_MONOTONIC:
-                        s->enabled = m;
-                        prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
-                        prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
-                        break;
-
-                case SOURCE_REALTIME:
-                        s->enabled = m;
-                        prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
-                        prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
-                        break;
-
-                case SOURCE_SIGNAL:
-                        s->enabled = m;
-                        if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) {
-                                assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
-                                event_update_signal_fd(s->event);
-                        }
-
-                        break;
-
-                case SOURCE_CHILD:
-                        s->enabled = m;
-
-                        assert(s->event->n_enabled_child_sources > 0);
-                        s->event->n_enabled_child_sources--;
-
-                        if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
-                                assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
-                                event_update_signal_fd(s->event);
-                        }
-
-                        break;
-
-                case SOURCE_EXIT:
-                        s->enabled = m;
-                        prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
-                        break;
-
-                case SOURCE_DEFER:
-                        s->enabled = m;
-                        break;
-
-                case SOURCE_WATCHDOG:
-                        assert_not_reached("Wut? I shouldn't exist.");
-                }
-
-        } else {
-                switch (s->type) {
-
-                case SOURCE_IO:
-                        r = source_io_register(s, m, s->io.events);
-                        if (r < 0)
-                                return r;
-
-                        s->enabled = m;
-                        break;
-
-                case SOURCE_MONOTONIC:
-                        s->enabled = m;
-                        prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
-                        prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
-                        break;
-
-                case SOURCE_REALTIME:
-                        s->enabled = m;
-                        prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
-                        prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
-                        break;
-
-                case SOURCE_SIGNAL:
-                        s->enabled = m;
-
-                        if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)  {
-                                assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0);
-                                event_update_signal_fd(s->event);
-                        }
-                        break;
-
-                case SOURCE_CHILD:
-                        s->enabled = m;
-
-                        if (s->enabled == SD_EVENT_OFF) {
-                                s->event->n_enabled_child_sources++;
-
-                                if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
-                                        assert_se(sigaddset(&s->event->sigset, SIGCHLD) == 0);
-                                        event_update_signal_fd(s->event);
-                                }
-                        }
-                        break;
-
-                case SOURCE_EXIT:
-                        s->enabled = m;
-                        prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
-                        break;
-
-                case SOURCE_DEFER:
-                        s->enabled = m;
-                        break;
-
-                case SOURCE_WATCHDOG:
-                        assert_not_reached("Wut? I shouldn't exist.");
-                }
-        }
-
-        if (s->pending)
-                prioq_reshuffle(s->event->pending, s, &s->pending_index);
-
-        if (s->prepare)
-                prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
-
-        return 0;
-}
-
-_public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) {
-        assert_return(s, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        *usec = s->time.next;
-        return 0;
-}
-
-_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
-        assert_return(s, -EINVAL);
-        assert_return(usec != (uint64_t) -1, -EINVAL);
-        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        s->time.next = usec;
-
-        source_set_pending(s, false);
-
-        if (s->type == SOURCE_REALTIME) {
-                prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
-                prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
-        } else {
-                prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
-                prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
-        }
-
-        return 0;
-}
-
-_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) {
-        assert_return(s, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        *usec = s->time.accuracy;
-        return 0;
-}
-
-_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) {
-        assert_return(s, -EINVAL);
-        assert_return(usec != (uint64_t) -1, -EINVAL);
-        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        if (usec == 0)
-                usec = DEFAULT_ACCURACY_USEC;
-
-        s->time.accuracy = usec;
-
-        source_set_pending(s, false);
-
-        if (s->type == SOURCE_REALTIME)
-                prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
-        else
-                prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
-
-        return 0;
-}
-
-_public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
-        assert_return(s, -EINVAL);
-        assert_return(pid, -EINVAL);
-        assert_return(s->type == SOURCE_CHILD, -EDOM);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        *pid = s->child.pid;
-        return 0;
-}
-
-_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) {
-        int r;
-
-        assert_return(s, -EINVAL);
-        assert_return(s->type != SOURCE_EXIT, -EDOM);
-        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(s->event), -ECHILD);
-
-        if (s->prepare == callback)
-                return 0;
-
-        if (callback && s->prepare) {
-                s->prepare = callback;
-                return 0;
-        }
-
-        r = prioq_ensure_allocated(&s->event->prepare, prepare_prioq_compare);
-        if (r < 0)
-                return r;
-
-        s->prepare = callback;
-
-        if (callback) {
-                r = prioq_put(s->event->prepare, s, &s->prepare_index);
-                if (r < 0)
-                        return r;
-        } else
-                prioq_remove(s->event->prepare, s, &s->prepare_index);
-
-        return 0;
-}
-
-_public_ void* sd_event_source_get_userdata(sd_event_source *s) {
-        assert_return(s, NULL);
-
-        return s->userdata;
-}
-
-_public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) {
-        void *ret;
-
-        assert_return(s, NULL);
-
-        ret = s->userdata;
-        s->userdata = userdata;
-
-        return ret;
-}
-
-static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
-        usec_t c;
-        assert(e);
-        assert(a <= b);
-
-        if (a <= 0)
-                return 0;
-
-        if (b <= a + 1)
-                return a;
-
-        /*
-          Find a good time to wake up again between times a and b. We
-          have two goals here:
-
-          a) We want to wake up as seldom as possible, hence prefer
-             later times over earlier times.
-
-          b) But if we have to wake up, then let's make sure to
-             dispatch as much as possible on the entire system.
-
-          We implement this by waking up everywhere at the same time
-          within any given minute if we can, synchronised via the
-          perturbation value determined from the boot ID. If we can't,
-          then we try to find the same spot in every 10s, then 1s and
-          then 250ms step. Otherwise, we pick the last possible time
-          to wake up.
-        */
-
-        c = (b / USEC_PER_MINUTE) * USEC_PER_MINUTE + e->perturb;
-        if (c >= b) {
-                if (_unlikely_(c < USEC_PER_MINUTE))
-                        return b;
-
-                c -= USEC_PER_MINUTE;
-        }
-
-        if (c >= a)
-                return c;
-
-        c = (b / (USEC_PER_SEC*10)) * (USEC_PER_SEC*10) + (e->perturb % (USEC_PER_SEC*10));
-        if (c >= b) {
-                if (_unlikely_(c < USEC_PER_SEC*10))
-                        return b;
-
-                c -= USEC_PER_SEC*10;
-        }
-
-        if (c >= a)
-                return c;
-
-        c = (b / USEC_PER_SEC) * USEC_PER_SEC + (e->perturb % USEC_PER_SEC);
-        if (c >= b) {
-                if (_unlikely_(c < USEC_PER_SEC))
-                        return b;
-
-                c -= USEC_PER_SEC;
-        }
-
-        if (c >= a)
-                return c;
-
-        c = (b / (USEC_PER_MSEC*250)) * (USEC_PER_MSEC*250) + (e->perturb % (USEC_PER_MSEC*250));
-        if (c >= b) {
-                if (_unlikely_(c < USEC_PER_MSEC*250))
-                        return b;
-
-                c -= USEC_PER_MSEC*250;
-        }
-
-        if (c >= a)
-                return c;
-
-        return b;
-}
-
-static int event_arm_timer(
-                sd_event *e,
-                int timer_fd,
-                Prioq *earliest,
-                Prioq *latest,
-                usec_t *next) {
-
-        struct itimerspec its = {};
-        sd_event_source *a, *b;
-        usec_t t;
-        int r;
-
-        assert(e);
-        assert(next);
-
-        a = prioq_peek(earliest);
-        if (!a || a->enabled == SD_EVENT_OFF) {
-
-                if (timer_fd < 0)
-                        return 0;
-
-                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);
-
-        t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy);
-        if (*next == t)
-                return 0;
-
-        assert_se(timer_fd >= 0);
-
-        if (t == 0) {
-                /* We don' want to disarm here, just mean some time looooong ago. */
-                its.it_value.tv_sec = 0;
-                its.it_value.tv_nsec = 1;
-        } else
-                timespec_store(&its.it_value, t);
-
-        r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
-        if (r < 0)
-                return -errno;
-
-        *next = t;
-        return 0;
-}
-
-static int process_io(sd_event *e, sd_event_source *s, uint32_t revents) {
-        assert(e);
-        assert(s);
-        assert(s->type == SOURCE_IO);
-
-        /* If the event source was already pending, we just OR in the
-         * new revents, otherwise we reset the value. The ORing is
-         * necessary to handle EPOLLONESHOT events properly where
-         * readability might happen independently of writability, and
-         * we need to keep track of both */
-
-        if (s->pending)
-                s->io.revents |= revents;
-        else
-                s->io.revents = revents;
-
-        return source_set_pending(s, true);
-}
-
-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_return(events == EPOLLIN, -EIO);
-
-        ss = read(fd, &x, sizeof(x));
-        if (ss < 0) {
-                if (errno == EAGAIN || errno == EINTR)
-                        return 0;
-
-                return -errno;
-        }
-
-        if (_unlikely_(ss != sizeof(x)))
-                return -EIO;
-
-        if (next)
-                *next = (usec_t) -1;
-
-        return 0;
-}
-
-static int process_timer(
-                sd_event *e,
-                usec_t n,
-                Prioq *earliest,
-                Prioq *latest) {
-
-        sd_event_source *s;
-        int r;
-
-        assert(e);
-
-        for (;;) {
-                s = prioq_peek(earliest);
-                if (!s ||
-                    s->time.next > n ||
-                    s->enabled == SD_EVENT_OFF ||
-                    s->pending)
-                        break;
-
-                r = source_set_pending(s, true);
-                if (r < 0)
-                        return r;
-
-                prioq_reshuffle(earliest, s, &s->time.earliest_index);
-                prioq_reshuffle(latest, s, &s->time.latest_index);
-        }
-
-        return 0;
-}
-
-static int process_child(sd_event *e) {
-        sd_event_source *s;
-        Iterator i;
-        int r;
-
-        assert(e);
-
-        e->need_process_child = false;
-
-        /*
-           So, this is ugly. We iteratively invoke waitid() with P_PID
-           + WNOHANG for each PID we wait for, instead of using
-           P_ALL. This is because we only want to get child
-           information of very specific child processes, and not all
-           of them. We might not have processed the SIGCHLD even of a
-           previous invocation and we don't want to maintain a
-           unbounded *per-child* event queue, hence we really don't
-           want anything flushed out of the kernel's queue that we
-           don't care about. Since this is O(n) this means that if you
-           have a lot of processes you probably want to handle SIGCHLD
-           yourself.
-
-           We do not reap the children here (by using WNOWAIT), this
-           is only done after the event source is dispatched so that
-           the callback still sees the process as a zombie.
-        */
-
-        HASHMAP_FOREACH(s, e->child_sources, i) {
-                assert(s->type == SOURCE_CHILD);
-
-                if (s->pending)
-                        continue;
-
-                if (s->enabled == SD_EVENT_OFF)
-                        continue;
-
-                zero(s->child.siginfo);
-                r = waitid(P_PID, s->child.pid, &s->child.siginfo,
-                           WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
-                if (r < 0)
-                        return -errno;
-
-                if (s->child.siginfo.si_pid != 0) {
-                        bool zombie =
-                                s->child.siginfo.si_code == CLD_EXITED ||
-                                s->child.siginfo.si_code == CLD_KILLED ||
-                                s->child.siginfo.si_code == CLD_DUMPED;
-
-                        if (!zombie && (s->child.options & WEXITED)) {
-                                /* If the child isn't dead then let's
-                                 * immediately remove the state change
-                                 * from the queue, since there's no
-                                 * benefit in leaving it queued */
-
-                                assert(s->child.options & (WSTOPPED|WCONTINUED));
-                                waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
-                        }
-
-                        r = source_set_pending(s, true);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        return 0;
-}
-
-static int process_signal(sd_event *e, uint32_t events) {
-        bool read_one = false;
-        int r;
-
-        assert(e);
-        assert(e->signal_sources);
-
-        assert_return(events == EPOLLIN, -EIO);
-
-        for (;;) {
-                struct signalfd_siginfo si;
-                ssize_t ss;
-                sd_event_source *s;
-
-                ss = read(e->signal_fd, &si, sizeof(si));
-                if (ss < 0) {
-                        if (errno == EAGAIN || errno == EINTR)
-                                return read_one;
-
-                        return -errno;
-                }
-
-                if (_unlikely_(ss != sizeof(si)))
-                        return -EIO;
-
-                read_one = true;
-
-                s = e->signal_sources[si.ssi_signo];
-                if (si.ssi_signo == SIGCHLD) {
-                        r = process_child(e);
-                        if (r < 0)
-                                return r;
-                        if (r > 0 || !s)
-                                continue;
-                } else
-                        if (!s)
-                                return -EIO;
-
-                s->signal.siginfo = si;
-                r = source_set_pending(s, true);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int source_dispatch(sd_event_source *s) {
-        int r = 0;
-
-        assert(s);
-        assert(s->pending || s->type == SOURCE_EXIT);
-
-        if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
-                r = source_set_pending(s, false);
-                if (r < 0)
-                        return r;
-        }
-
-        if (s->enabled == SD_EVENT_ONESHOT) {
-                r = sd_event_source_set_enabled(s, SD_EVENT_OFF);
-                if (r < 0)
-                        return r;
-        }
-
-        s->dispatching = true;
-
-        switch (s->type) {
-
-        case SOURCE_IO:
-                r = s->io.callback(s, s->io.fd, s->io.revents, s->userdata);
-                break;
-
-        case SOURCE_MONOTONIC:
-                r = s->time.callback(s, s->time.next, s->userdata);
-                break;
-
-        case SOURCE_REALTIME:
-                r = s->time.callback(s, s->time.next, s->userdata);
-                break;
-
-        case SOURCE_SIGNAL:
-                r = s->signal.callback(s, &s->signal.siginfo, s->userdata);
-                break;
-
-        case SOURCE_CHILD: {
-                bool zombie;
-
-                zombie = s->child.siginfo.si_code == CLD_EXITED ||
-                         s->child.siginfo.si_code == CLD_KILLED ||
-                         s->child.siginfo.si_code == CLD_DUMPED;
-
-                r = s->child.callback(s, &s->child.siginfo, s->userdata);
-
-                /* Now, reap the PID for good. */
-                if (zombie)
-                        waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED);
-
-                break;
-        }
-
-        case SOURCE_DEFER:
-                r = s->defer.callback(s, s->userdata);
-                break;
-
-        case SOURCE_EXIT:
-                r = s->exit.callback(s, s->userdata);
-                break;
-
-        case SOURCE_WATCHDOG:
-                assert_not_reached("Wut? I shouldn't exist.");
-        }
-
-        s->dispatching = false;
-
-        if (r < 0)
-                log_debug("Event source %p returned error, disabling: %s", s, strerror(-r));
-
-        if (s->n_ref == 0)
-                source_free(s);
-        else if (r < 0)
-                sd_event_source_set_enabled(s, SD_EVENT_OFF);
-
-        return 1;
-}
-
-static int event_prepare(sd_event *e) {
-        int r;
-
-        assert(e);
-
-        for (;;) {
-                sd_event_source *s;
-
-                s = prioq_peek(e->prepare);
-                if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
-                        break;
-
-                s->prepare_iteration = e->iteration;
-                r = prioq_reshuffle(e->prepare, s, &s->prepare_index);
-                if (r < 0)
-                        return r;
-
-                assert(s->prepare);
-
-                s->dispatching = true;
-                r = s->prepare(s, s->userdata);
-                s->dispatching = false;
-
-                if (r < 0)
-                        log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r));
-
-                if (s->n_ref == 0)
-                        source_free(s);
-                else if (r < 0)
-                        sd_event_source_set_enabled(s, SD_EVENT_OFF);
-        }
-
-        return 0;
-}
-
-static int dispatch_exit(sd_event *e) {
-        sd_event_source *p;
-        int r;
-
-        assert(e);
-
-        p = prioq_peek(e->exit);
-        if (!p || p->enabled == SD_EVENT_OFF) {
-                e->state = SD_EVENT_FINISHED;
-                return 0;
-        }
-
-        sd_event_ref(e);
-        e->iteration++;
-        e->state = SD_EVENT_EXITING;
-
-        r = source_dispatch(p);
-
-        e->state = SD_EVENT_PASSIVE;
-        sd_event_unref(e);
-
-        return r;
-}
-
-static sd_event_source* event_next_pending(sd_event *e) {
-        sd_event_source *p;
-
-        assert(e);
-
-        p = prioq_peek(e->pending);
-        if (!p)
-                return NULL;
-
-        if (p->enabled == SD_EVENT_OFF)
-                return NULL;
-
-        return p;
-}
-
-static int arm_watchdog(sd_event *e) {
-        struct itimerspec its = {};
-        usec_t t;
-        int r;
-
-        assert(e);
-        assert(e->watchdog_fd >= 0);
-
-        t = sleep_between(e,
-                          e->watchdog_last + (e->watchdog_period / 2),
-                          e->watchdog_last + (e->watchdog_period * 3 / 4));
-
-        timespec_store(&its.it_value, t);
-
-        r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int process_watchdog(sd_event *e) {
-        assert(e);
-
-        if (!e->watchdog)
-                return 0;
-
-        /* Don't notify watchdog too often */
-        if (e->watchdog_last + e->watchdog_period / 4 > e->timestamp.monotonic)
-                return 0;
-
-        sd_notify(false, "WATCHDOG=1");
-        e->watchdog_last = e->timestamp.monotonic;
-
-        return arm_watchdog(e);
-}
-
-_public_ int sd_event_run(sd_event *e, uint64_t timeout) {
-        struct epoll_event *ev_queue;
-        unsigned ev_queue_max;
-        sd_event_source *p;
-        int r, i, m;
-
-        assert_return(e, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
-
-        if (e->exit_requested)
-                return dispatch_exit(e);
-
-        sd_event_ref(e);
-        e->iteration++;
-        e->state = SD_EVENT_RUNNING;
-
-        r = event_prepare(e);
-        if (r < 0)
-                goto finish;
-
-        r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next);
-        if (r < 0)
-                goto finish;
-
-        r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next);
-        if (r < 0)
-                goto finish;
-
-        if (event_next_pending(e) || e->need_process_child)
-                timeout = 0;
-        ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX);
-        ev_queue = newa(struct epoll_event, ev_queue_max);
-
-        m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
-                       timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
-        if (m < 0) {
-                r = errno == EAGAIN || errno == EINTR ? 1 : -errno;
-                goto finish;
-        }
-
-        dual_timestamp_get(&e->timestamp);
-
-        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, &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, &e->realtime_next);
-                else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL))
-                        r = process_signal(e, ev_queue[i].events);
-                else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
-                        r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
-                else
-                        r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = process_watchdog(e);
-        if (r < 0)
-                goto finish;
-
-        r = process_timer(e, e->timestamp.monotonic, e->monotonic_earliest, e->monotonic_latest);
-        if (r < 0)
-                goto finish;
-
-        r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest);
-        if (r < 0)
-                goto finish;
-
-        if (e->need_process_child) {
-                r = process_child(e);
-                if (r < 0)
-                        goto finish;
-        }
-
-        p = event_next_pending(e);
-        if (!p) {
-                r = 1;
-                goto finish;
-        }
-
-        r = source_dispatch(p);
-
-finish:
-        e->state = SD_EVENT_PASSIVE;
-        sd_event_unref(e);
-
-        return r;
-}
-
-_public_ int sd_event_loop(sd_event *e) {
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-        assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
-
-        sd_event_ref(e);
-
-        while (e->state != SD_EVENT_FINISHED) {
-                r = sd_event_run(e, (uint64_t) -1);
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = e->exit_code;
-
-finish:
-        sd_event_unref(e);
-        return r;
-}
-
-_public_ int sd_event_get_state(sd_event *e) {
-        assert_return(e, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        return e->state;
-}
-
-_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
-        assert_return(e, -EINVAL);
-        assert_return(code, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        if (!e->exit_requested)
-                return -ENODATA;
-
-        *code = e->exit_code;
-        return 0;
-}
-
-_public_ int sd_event_exit(sd_event *e, int code) {
-        assert_return(e, -EINVAL);
-        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        e->exit_requested = true;
-        e->exit_code = code;
-
-        return 0;
-}
-
-_public_ int sd_event_get_now_realtime(sd_event *e, uint64_t *usec) {
-        assert_return(e, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        *usec = e->timestamp.realtime;
-        return 0;
-}
-
-_public_ int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec) {
-        assert_return(e, -EINVAL);
-        assert_return(usec, -EINVAL);
-        assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        *usec = e->timestamp.monotonic;
-        return 0;
-}
-
-_public_ int sd_event_default(sd_event **ret) {
-
-        static thread_local sd_event *default_event = NULL;
-        sd_event *e;
-        int r;
-
-        if (!ret)
-                return !!default_event;
-
-        if (default_event) {
-                *ret = sd_event_ref(default_event);
-                return 0;
-        }
-
-        r = sd_event_new(&e);
-        if (r < 0)
-                return r;
-
-        e->default_event_ptr = &default_event;
-        e->tid = gettid();
-        default_event = e;
-
-        *ret = e;
-        return 1;
-}
-
-_public_ int sd_event_get_tid(sd_event *e, pid_t *tid) {
-        assert_return(e, -EINVAL);
-        assert_return(tid, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        if (e->tid != 0) {
-                *tid = e->tid;
-                return 0;
-        }
-
-        return -ENXIO;
-}
-
-_public_ int sd_event_set_watchdog(sd_event *e, int b) {
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        if (e->watchdog == !!b)
-                return e->watchdog;
-
-        if (b) {
-                struct epoll_event ev = {};
-
-                r = sd_watchdog_enabled(false, &e->watchdog_period);
-                if (r <= 0)
-                        return r;
-
-                /* Issue first ping immediately */
-                sd_notify(false, "WATCHDOG=1");
-                e->watchdog_last = now(CLOCK_MONOTONIC);
-
-                e->watchdog_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
-                if (e->watchdog_fd < 0)
-                        return -errno;
-
-                r = arm_watchdog(e);
-                if (r < 0)
-                        goto fail;
-
-                ev.events = EPOLLIN;
-                ev.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG);
-
-                r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev);
-                if (r < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-
-        } else {
-                if (e->watchdog_fd >= 0) {
-                        epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
-                        close_nointr_nofail(e->watchdog_fd);
-                        e->watchdog_fd = -1;
-                }
-        }
-
-        e->watchdog = !!b;
-        return e->watchdog;
-
-fail:
-        close_nointr_nofail(e->watchdog_fd);
-        e->watchdog_fd = -1;
-        return r;
-}
-
-_public_ int sd_event_get_watchdog(sd_event *e) {
-        assert_return(e, -EINVAL);
-        assert_return(!event_pid_changed(e), -ECHILD);
-
-        return e->watchdog;
-}
diff --git a/src/libsystemd/sd-event/Makefile b/src/libsystemd/sd-event/Makefile
new file mode 120000
index 0000000..94aaae2
--- /dev/null
+++ b/src/libsystemd/sd-event/Makefile
@@ -0,0 +1 @@
+../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h
new file mode 100644
index 0000000..e58020d
--- /dev/null
+++ b/src/libsystemd/sd-event/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/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
new file mode 100644
index 0000000..f33a9ec
--- /dev/null
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -0,0 +1,2224 @@
+/*-*- 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 <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <sys/wait.h>
+#include <pthread.h>
+
+#include "sd-id128.h"
+#include "sd-daemon.h"
+#include "macro.h"
+#include "prioq.h"
+#include "hashmap.h"
+#include "util.h"
+#include "time-util.h"
+#include "missing.h"
+
+#include "sd-event.h"
+
+#define EPOLL_QUEUE_MAX 512U
+#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
+
+typedef enum EventSourceType {
+        SOURCE_IO,
+        SOURCE_MONOTONIC,
+        SOURCE_REALTIME,
+        SOURCE_SIGNAL,
+        SOURCE_CHILD,
+        SOURCE_DEFER,
+        SOURCE_EXIT,
+        SOURCE_WATCHDOG
+} EventSourceType;
+
+struct sd_event_source {
+        unsigned n_ref;
+
+        sd_event *event;
+        void *userdata;
+        sd_event_handler_t prepare;
+
+        EventSourceType type:4;
+        int enabled:3;
+        bool pending:1;
+        bool dispatching:1;
+
+        int64_t priority;
+        unsigned pending_index;
+        unsigned prepare_index;
+        unsigned pending_iteration;
+        unsigned prepare_iteration;
+
+        union {
+                struct {
+                        sd_event_io_handler_t callback;
+                        int fd;
+                        uint32_t events;
+                        uint32_t revents;
+                        bool registered:1;
+                } io;
+                struct {
+                        sd_event_time_handler_t callback;
+                        usec_t next, accuracy;
+                        unsigned earliest_index;
+                        unsigned latest_index;
+                } time;
+                struct {
+                        sd_event_signal_handler_t callback;
+                        struct signalfd_siginfo siginfo;
+                        int sig;
+                } signal;
+                struct {
+                        sd_event_child_handler_t callback;
+                        siginfo_t siginfo;
+                        pid_t pid;
+                        int options;
+                } child;
+                struct {
+                        sd_event_handler_t callback;
+                } defer;
+                struct {
+                        sd_event_handler_t callback;
+                        unsigned prioq_index;
+                } exit;
+        };
+};
+
+struct sd_event {
+        unsigned n_ref;
+
+        int epoll_fd;
+        int signal_fd;
+        int realtime_fd;
+        int monotonic_fd;
+        int watchdog_fd;
+
+        Prioq *pending;
+        Prioq *prepare;
+
+        /* For both clocks we maintain two priority queues each, one
+         * ordered for the earliest times the events may be
+         * dispatched, and one ordered by the latest times they must
+         * have been dispatched. The range between the top entries in
+         * the two prioqs is the time window we can freely schedule
+         * wakeups in */
+        Prioq *monotonic_earliest;
+        Prioq *monotonic_latest;
+        Prioq *realtime_earliest;
+        Prioq *realtime_latest;
+
+        usec_t realtime_next, monotonic_next;
+        usec_t perturb;
+
+        sigset_t sigset;
+        sd_event_source **signal_sources;
+
+        Hashmap *child_sources;
+        unsigned n_enabled_child_sources;
+
+        Prioq *exit;
+
+        pid_t original_pid;
+
+        unsigned iteration;
+        dual_timestamp timestamp;
+        int state;
+
+        bool exit_requested:1;
+        bool need_process_child:1;
+        bool watchdog:1;
+
+        int exit_code;
+
+        pid_t tid;
+        sd_event **default_event_ptr;
+
+        usec_t watchdog_last, watchdog_period;
+
+        unsigned n_sources;
+};
+
+static int pending_prioq_compare(const void *a, const void *b) {
+        const sd_event_source *x = a, *y = b;
+
+        assert(x->pending);
+        assert(y->pending);
+
+        /* Enabled ones first */
+        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
+                return -1;
+        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
+                return 1;
+
+        /* Lower priority values first */
+        if (x->priority < y->priority)
+                return -1;
+        if (x->priority > y->priority)
+                return 1;
+
+        /* Older entries first */
+        if (x->pending_iteration < y->pending_iteration)
+                return -1;
+        if (x->pending_iteration > y->pending_iteration)
+                return 1;
+
+        /* Stability for the rest */
+        if (x < y)
+                return -1;
+        if (x > y)
+                return 1;
+
+        return 0;
+}
+
+static int prepare_prioq_compare(const void *a, const void *b) {
+        const sd_event_source *x = a, *y = b;
+
+        assert(x->prepare);
+        assert(y->prepare);
+
+        /* Move most recently prepared ones last, so that we can stop
+         * preparing as soon as we hit one that has already been
+         * prepared in the current iteration */
+        if (x->prepare_iteration < y->prepare_iteration)
+                return -1;
+        if (x->prepare_iteration > y->prepare_iteration)
+                return 1;
+
+        /* Enabled ones first */
+        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
+                return -1;
+        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
+                return 1;
+
+        /* Lower priority values first */
+        if (x->priority < y->priority)
+                return -1;
+        if (x->priority > y->priority)
+                return 1;
+
+        /* Stability for the rest */
+        if (x < y)
+                return -1;
+        if (x > y)
+                return 1;
+
+        return 0;
+}
+
+static int earliest_time_prioq_compare(const void *a, const void *b) {
+        const sd_event_source *x = a, *y = b;
+
+        assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME);
+        assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME);
+
+        /* Enabled ones first */
+        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
+                return -1;
+        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
+                return 1;
+
+        /* Move the pending ones to the end */
+        if (!x->pending && y->pending)
+                return -1;
+        if (x->pending && !y->pending)
+                return 1;
+
+        /* Order by time */
+        if (x->time.next < y->time.next)
+                return -1;
+        if (x->time.next > y->time.next)
+                return 1;
+
+        /* Stability for the rest */
+        if (x < y)
+                return -1;
+        if (x > y)
+                return 1;
+
+        return 0;
+}
+
+static int latest_time_prioq_compare(const void *a, const void *b) {
+        const sd_event_source *x = a, *y = b;
+
+        assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) ||
+               (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME));
+
+        /* Enabled ones first */
+        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
+                return -1;
+        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
+                return 1;
+
+        /* Move the pending ones to the end */
+        if (!x->pending && y->pending)
+                return -1;
+        if (x->pending && !y->pending)
+                return 1;
+
+        /* Order by time */
+        if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy)
+                return -1;
+        if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
+                return 1;
+
+        /* Stability for the rest */
+        if (x < y)
+                return -1;
+        if (x > y)
+                return 1;
+
+        return 0;
+}
+
+static int exit_prioq_compare(const void *a, const void *b) {
+        const sd_event_source *x = a, *y = b;
+
+        assert(x->type == SOURCE_EXIT);
+        assert(y->type == SOURCE_EXIT);
+
+        /* Enabled ones first */
+        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
+                return -1;
+        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
+                return 1;
+
+        /* Lower priority values first */
+        if (x->priority < y->priority)
+                return -1;
+        if (x->priority > y->priority)
+                return 1;
+
+        /* Stability for the rest */
+        if (x < y)
+                return -1;
+        if (x > y)
+                return 1;
+
+        return 0;
+}
+
+static void event_free(sd_event *e) {
+        assert(e);
+        assert(e->n_sources == 0);
+
+        if (e->default_event_ptr)
+                *(e->default_event_ptr) = NULL;
+
+        if (e->epoll_fd >= 0)
+                close_nointr_nofail(e->epoll_fd);
+
+        if (e->signal_fd >= 0)
+                close_nointr_nofail(e->signal_fd);
+
+        if (e->realtime_fd >= 0)
+                close_nointr_nofail(e->realtime_fd);
+
+        if (e->monotonic_fd >= 0)
+                close_nointr_nofail(e->monotonic_fd);
+
+        if (e->watchdog_fd >= 0)
+                close_nointr_nofail(e->watchdog_fd);
+
+        prioq_free(e->pending);
+        prioq_free(e->prepare);
+        prioq_free(e->monotonic_earliest);
+        prioq_free(e->monotonic_latest);
+        prioq_free(e->realtime_earliest);
+        prioq_free(e->realtime_latest);
+        prioq_free(e->exit);
+
+        free(e->signal_sources);
+
+        hashmap_free(e->child_sources);
+        free(e);
+}
+
+_public_ int sd_event_new(sd_event** ret) {
+        sd_event *e;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        e = new0(sd_event, 1);
+        if (!e)
+                return -ENOMEM;
+
+        e->n_ref = 1;
+        e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1;
+        e->realtime_next = e->monotonic_next = (usec_t) -1;
+        e->original_pid = getpid();
+
+        assert_se(sigemptyset(&e->sigset) == 0);
+
+        e->pending = prioq_new(pending_prioq_compare);
+        if (!e->pending) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        e->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+        if (e->epoll_fd < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        *ret = e;
+        return 0;
+
+fail:
+        event_free(e);
+        return r;
+}
+
+_public_ sd_event* sd_event_ref(sd_event *e) {
+        assert_return(e, NULL);
+
+        assert(e->n_ref >= 1);
+        e->n_ref++;
+
+        return e;
+}
+
+_public_ sd_event* sd_event_unref(sd_event *e) {
+
+        if (!e)
+                return NULL;
+
+        assert(e->n_ref >= 1);
+        e->n_ref--;
+
+        if (e->n_ref <= 0)
+                event_free(e);
+
+        return NULL;
+}
+
+static bool event_pid_changed(sd_event *e) {
+        assert(e);
+
+        /* We don't support people creating am event loop and keeping
+         * it around over a fork(). Let's complain. */
+
+        return e->original_pid != getpid();
+}
+
+static int source_io_unregister(sd_event_source *s) {
+        int r;
+
+        assert(s);
+        assert(s->type == SOURCE_IO);
+
+        if (!s->io.registered)
+                return 0;
+
+        r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
+        if (r < 0)
+                return -errno;
+
+        s->io.registered = false;
+        return 0;
+}
+
+static int source_io_register(
+                sd_event_source *s,
+                int enabled,
+                uint32_t events) {
+
+        struct epoll_event ev = {};
+        int r;
+
+        assert(s);
+        assert(s->type == SOURCE_IO);
+        assert(enabled != SD_EVENT_OFF);
+
+        ev.events = events;
+        ev.data.ptr = s;
+
+        if (enabled == SD_EVENT_ONESHOT)
+                ev.events |= EPOLLONESHOT;
+
+        if (s->io.registered)
+                r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
+        else
+                r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
+
+        if (r < 0)
+                return -errno;
+
+        s->io.registered = true;
+
+        return 0;
+}
+
+static void source_free(sd_event_source *s) {
+        assert(s);
+
+        if (s->event) {
+                assert(s->event->n_sources > 0);
+
+                switch (s->type) {
+
+                case SOURCE_IO:
+                        if (s->io.fd >= 0)
+                                source_io_unregister(s);
+
+                        break;
+
+                case SOURCE_MONOTONIC:
+                        prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index);
+                        prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index);
+                        break;
+
+                case SOURCE_REALTIME:
+                        prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index);
+                        prioq_remove(s->event->realtime_latest, s, &s->time.latest_index);
+                        break;
+
+                case SOURCE_SIGNAL:
+                        if (s->signal.sig > 0) {
+                                if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
+                                        assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
+
+                                if (s->event->signal_sources)
+                                        s->event->signal_sources[s->signal.sig] = NULL;
+                        }
+
+                        break;
+
+                case SOURCE_CHILD:
+                        if (s->child.pid > 0) {
+                                if (s->enabled != SD_EVENT_OFF) {
+                                        assert(s->event->n_enabled_child_sources > 0);
+                                        s->event->n_enabled_child_sources--;
+                                }
+
+                                if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
+                                        assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
+
+                                hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
+                        }
+
+                        break;
+
+                case SOURCE_DEFER:
+                        /* nothing */
+                        break;
+
+                case SOURCE_EXIT:
+                        prioq_remove(s->event->exit, s, &s->exit.prioq_index);
+                        break;
+
+                case SOURCE_WATCHDOG:
+                        assert_not_reached("Wut? I shouldn't exist.");
+                }
+
+                if (s->pending)
+                        prioq_remove(s->event->pending, s, &s->pending_index);
+
+                if (s->prepare)
+                        prioq_remove(s->event->prepare, s, &s->prepare_index);
+
+                s->event->n_sources--;
+                sd_event_unref(s->event);
+        }
+
+        free(s);
+}
+
+static int source_set_pending(sd_event_source *s, bool b) {
+        int r;
+
+        assert(s);
+        assert(s->type != SOURCE_EXIT);
+
+        if (s->pending == b)
+                return 0;
+
+        s->pending = b;
+
+        if (b) {
+                s->pending_iteration = s->event->iteration;
+
+                r = prioq_put(s->event->pending, s, &s->pending_index);
+                if (r < 0) {
+                        s->pending = false;
+                        return r;
+                }
+        } else
+                assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
+
+        if (s->type == SOURCE_REALTIME) {
+                prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
+                prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
+        } else if (s->type == SOURCE_MONOTONIC) {
+                prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
+                prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
+        }
+
+        return 0;
+}
+
+static sd_event_source *source_new(sd_event *e, EventSourceType type) {
+        sd_event_source *s;
+
+        assert(e);
+
+        s = new0(sd_event_source, 1);
+        if (!s)
+                return NULL;
+
+        s->n_ref = 1;
+        s->event = sd_event_ref(e);
+        s->type = type;
+        s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
+
+        e->n_sources ++;
+
+        return s;
+}
+
+_public_ int sd_event_add_io(
+                sd_event *e,
+                int fd,
+                uint32_t events,
+                sd_event_io_handler_t callback,
+                void *userdata,
+                sd_event_source **ret) {
+
+        sd_event_source *s;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        s = source_new(e, SOURCE_IO);
+        if (!s)
+                return -ENOMEM;
+
+        s->io.fd = fd;
+        s->io.events = events;
+        s->io.callback = callback;
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ON;
+
+        r = source_io_register(s, s->enabled, events);
+        if (r < 0) {
+                source_free(s);
+                return -errno;
+        }
+
+        *ret = s;
+        return 0;
+}
+
+static int event_setup_timer_fd(
+                sd_event *e,
+                EventSourceType type,
+                int *timer_fd,
+                clockid_t id) {
+
+        struct epoll_event ev = {};
+        int r, fd;
+        sd_id128_t bootid;
+
+        assert(e);
+        assert(timer_fd);
+
+        if (_likely_(*timer_fd >= 0))
+                return 0;
+
+        fd = timerfd_create(id, TFD_NONBLOCK|TFD_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        ev.events = EPOLLIN;
+        ev.data.ptr = INT_TO_PTR(type);
+
+        r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
+        if (r < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        /* When we sleep for longer, we try to realign the wakeup to
+           the same time wihtin each minute/second/250ms, so that
+           events all across the system can be coalesced into a single
+           CPU wakeup. However, let's take some system-specific
+           randomness for this value, so that in a network of systems
+           with synced clocks timer events are distributed a
+           bit. Here, we calculate a perturbation usec offset from the
+           boot ID. */
+
+        if (sd_id128_get_boot(&bootid) >= 0)
+                e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE;
+
+        *timer_fd = fd;
+        return 0;
+}
+
+static int event_add_time_internal(
+                sd_event *e,
+                EventSourceType type,
+                int *timer_fd,
+                clockid_t id,
+                Prioq **earliest,
+                Prioq **latest,
+                uint64_t usec,
+                uint64_t accuracy,
+                sd_event_time_handler_t callback,
+                void *userdata,
+                sd_event_source **ret) {
+
+        sd_event_source *s;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(usec != (uint64_t) -1, -EINVAL);
+        assert_return(accuracy != (uint64_t) -1, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        assert(timer_fd);
+        assert(earliest);
+        assert(latest);
+
+        if (!*earliest) {
+                *earliest = prioq_new(earliest_time_prioq_compare);
+                if (!*earliest)
+                        return -ENOMEM;
+        }
+
+        if (!*latest) {
+                *latest = prioq_new(latest_time_prioq_compare);
+                if (!*latest)
+                        return -ENOMEM;
+        }
+
+        if (*timer_fd < 0) {
+                r = event_setup_timer_fd(e, type, timer_fd, id);
+                if (r < 0)
+                        return r;
+        }
+
+        s = source_new(e, type);
+        if (!s)
+                return -ENOMEM;
+
+        s->time.next = usec;
+        s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
+        s->time.callback = callback;
+        s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ONESHOT;
+
+        r = prioq_put(*earliest, s, &s->time.earliest_index);
+        if (r < 0)
+                goto fail;
+
+        r = prioq_put(*latest, s, &s->time.latest_index);
+        if (r < 0)
+                goto fail;
+
+        *ret = s;
+        return 0;
+
+fail:
+        source_free(s);
+        return r;
+}
+
+_public_ int sd_event_add_monotonic(sd_event *e,
+                                    uint64_t usec,
+                                    uint64_t accuracy,
+                                    sd_event_time_handler_t callback,
+                                    void *userdata,
+                                    sd_event_source **ret) {
+
+        return event_add_time_internal(e, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
+}
+
+_public_ int sd_event_add_realtime(sd_event *e,
+                                   uint64_t usec,
+                                   uint64_t accuracy,
+                                   sd_event_time_handler_t callback,
+                                   void *userdata,
+                                   sd_event_source **ret) {
+
+        return event_add_time_internal(e, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
+}
+
+static int event_update_signal_fd(sd_event *e) {
+        struct epoll_event ev = {};
+        bool add_to_epoll;
+        int r;
+
+        assert(e);
+
+        add_to_epoll = e->signal_fd < 0;
+
+        r = signalfd(e->signal_fd, &e->sigset, SFD_NONBLOCK|SFD_CLOEXEC);
+        if (r < 0)
+                return -errno;
+
+        e->signal_fd = r;
+
+        if (!add_to_epoll)
+                return 0;
+
+        ev.events = EPOLLIN;
+        ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL);
+
+        r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev);
+        if (r < 0) {
+                close_nointr_nofail(e->signal_fd);
+                e->signal_fd = -1;
+
+                return -errno;
+        }
+
+        return 0;
+}
+
+_public_ int sd_event_add_signal(
+                sd_event *e,
+                int sig,
+                sd_event_signal_handler_t callback,
+                void *userdata,
+                sd_event_source **ret) {
+
+        sd_event_source *s;
+        sigset_t ss;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(sig > 0, -EINVAL);
+        assert_return(sig < _NSIG, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
+        if (r < 0)
+                return -errno;
+
+        if (!sigismember(&ss, sig))
+                return -EBUSY;
+
+        if (!e->signal_sources) {
+                e->signal_sources = new0(sd_event_source*, _NSIG);
+                if (!e->signal_sources)
+                        return -ENOMEM;
+        } else if (e->signal_sources[sig])
+                return -EBUSY;
+
+        s = source_new(e, SOURCE_SIGNAL);
+        if (!s)
+                return -ENOMEM;
+
+        s->signal.sig = sig;
+        s->signal.callback = callback;
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ON;
+
+        e->signal_sources[sig] = s;
+        assert_se(sigaddset(&e->sigset, sig) == 0);
+
+        if (sig != SIGCHLD || e->n_enabled_child_sources == 0) {
+                r = event_update_signal_fd(e);
+                if (r < 0) {
+                        source_free(s);
+                        return r;
+                }
+        }
+
+        *ret = s;
+        return 0;
+}
+
+_public_ int sd_event_add_child(
+                sd_event *e,
+                pid_t pid,
+                int options,
+                sd_event_child_handler_t callback,
+                void *userdata,
+                sd_event_source **ret) {
+
+        sd_event_source *s;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(pid > 1, -EINVAL);
+        assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
+        assert_return(options != 0, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func);
+        if (r < 0)
+                return r;
+
+        if (hashmap_contains(e->child_sources, INT_TO_PTR(pid)))
+                return -EBUSY;
+
+        s = source_new(e, SOURCE_CHILD);
+        if (!s)
+                return -ENOMEM;
+
+        s->child.pid = pid;
+        s->child.options = options;
+        s->child.callback = callback;
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ONESHOT;
+
+        r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s);
+        if (r < 0) {
+                source_free(s);
+                return r;
+        }
+
+        e->n_enabled_child_sources ++;
+
+        assert_se(sigaddset(&e->sigset, SIGCHLD) == 0);
+
+        if (!e->signal_sources || !e->signal_sources[SIGCHLD]) {
+                r = event_update_signal_fd(e);
+                if (r < 0) {
+                        source_free(s);
+                        return -errno;
+                }
+        }
+
+        e->need_process_child = true;
+
+        *ret = s;
+        return 0;
+}
+
+_public_ int sd_event_add_defer(
+                sd_event *e,
+                sd_event_handler_t callback,
+                void *userdata,
+                sd_event_source **ret) {
+
+        sd_event_source *s;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        s = source_new(e, SOURCE_DEFER);
+        if (!s)
+                return -ENOMEM;
+
+        s->defer.callback = callback;
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ONESHOT;
+
+        r = source_set_pending(s, true);
+        if (r < 0) {
+                source_free(s);
+                return r;
+        }
+
+        *ret = s;
+        return 0;
+}
+
+_public_ int sd_event_add_exit(
+                sd_event *e,
+                sd_event_handler_t callback,
+                void *userdata,
+                sd_event_source **ret) {
+
+        sd_event_source *s;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        if (!e->exit) {
+                e->exit = prioq_new(exit_prioq_compare);
+                if (!e->exit)
+                        return -ENOMEM;
+        }
+
+        s = source_new(e, SOURCE_EXIT);
+        if (!s)
+                return -ENOMEM;
+
+        s->exit.callback = callback;
+        s->userdata = userdata;
+        s->exit.prioq_index = PRIOQ_IDX_NULL;
+        s->enabled = SD_EVENT_ONESHOT;
+
+        r = prioq_put(s->event->exit, s, &s->exit.prioq_index);
+        if (r < 0) {
+                source_free(s);
+                return r;
+        }
+
+        *ret = s;
+        return 0;
+}
+
+_public_ sd_event_source* sd_event_source_ref(sd_event_source *s) {
+        assert_return(s, NULL);
+
+        assert(s->n_ref >= 1);
+        s->n_ref++;
+
+        return s;
+}
+
+_public_ sd_event_source* sd_event_source_unref(sd_event_source *s) {
+
+        if (!s)
+                return NULL;
+
+        assert(s->n_ref >= 1);
+        s->n_ref--;
+
+        if (s->n_ref <= 0) {
+                /* Here's a special hack: when we are called from a
+                 * dispatch handler we won't free the event source
+                 * immediately, but we will detach the fd from the
+                 * epoll. This way it is safe for the caller to unref
+                 * the event source and immediately close the fd, but
+                 * we still retain a valid event source object after
+                 * the callback. */
+
+                if (s->dispatching) {
+                        if (s->type == SOURCE_IO)
+                                source_io_unregister(s);
+                } else
+                        source_free(s);
+        }
+
+        return NULL;
+}
+
+_public_ sd_event *sd_event_source_get_event(sd_event_source *s) {
+        assert_return(s, NULL);
+
+        return s->event;
+}
+
+_public_ int sd_event_source_get_pending(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type != SOURCE_EXIT, -EDOM);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        return s->pending;
+}
+
+_public_ int sd_event_source_get_io_fd(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_IO, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        return s->io.fd;
+}
+
+_public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
+        int r;
+
+        assert_return(s, -EINVAL);
+        assert_return(fd >= 0, -EINVAL);
+        assert_return(s->type == SOURCE_IO, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (s->io.fd == fd)
+                return 0;
+
+        if (s->enabled == SD_EVENT_OFF) {
+                s->io.fd = fd;
+                s->io.registered = false;
+        } else {
+                int saved_fd;
+
+                saved_fd = s->io.fd;
+                assert(s->io.registered);
+
+                s->io.fd = fd;
+                s->io.registered = false;
+
+                r = source_io_register(s, s->enabled, s->io.events);
+                if (r < 0) {
+                        s->io.fd = saved_fd;
+                        s->io.registered = true;
+                        return r;
+                }
+
+                epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
+        }
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) {
+        assert_return(s, -EINVAL);
+        assert_return(events, -EINVAL);
+        assert_return(s->type == SOURCE_IO, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        *events = s->io.events;
+        return 0;
+}
+
+_public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) {
+        int r;
+
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_IO, -EDOM);
+        assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (s->io.events == events)
+                return 0;
+
+        if (s->enabled != SD_EVENT_OFF) {
+                r = source_io_register(s, s->enabled, events);
+                if (r < 0)
+                        return r;
+        }
+
+        s->io.events = events;
+        source_set_pending(s, false);
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) {
+        assert_return(s, -EINVAL);
+        assert_return(revents, -EINVAL);
+        assert_return(s->type == SOURCE_IO, -EDOM);
+        assert_return(s->pending, -ENODATA);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        *revents = s->io.revents;
+        return 0;
+}
+
+_public_ int sd_event_source_get_signal(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_SIGNAL, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        return s->signal.sig;
+}
+
+_public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) {
+        assert_return(s, -EINVAL);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        return s->priority;
+}
+
+_public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) {
+        assert_return(s, -EINVAL);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (s->priority == priority)
+                return 0;
+
+        s->priority = priority;
+
+        if (s->pending)
+                prioq_reshuffle(s->event->pending, s, &s->pending_index);
+
+        if (s->prepare)
+                prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
+
+        if (s->type == SOURCE_EXIT)
+                prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
+        assert_return(s, -EINVAL);
+        assert_return(m, -EINVAL);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        *m = s->enabled;
+        return 0;
+}
+
+_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
+        int r;
+
+        assert_return(s, -EINVAL);
+        assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (s->enabled == m)
+                return 0;
+
+        if (m == SD_EVENT_OFF) {
+
+                switch (s->type) {
+
+                case SOURCE_IO:
+                        r = source_io_unregister(s);
+                        if (r < 0)
+                                return r;
+
+                        s->enabled = m;
+                        break;
+
+                case SOURCE_MONOTONIC:
+                        s->enabled = m;
+                        prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
+                        prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
+                        break;
+
+                case SOURCE_REALTIME:
+                        s->enabled = m;
+                        prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
+                        prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
+                        break;
+
+                case SOURCE_SIGNAL:
+                        s->enabled = m;
+                        if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) {
+                                assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
+                                event_update_signal_fd(s->event);
+                        }
+
+                        break;
+
+                case SOURCE_CHILD:
+                        s->enabled = m;
+
+                        assert(s->event->n_enabled_child_sources > 0);
+                        s->event->n_enabled_child_sources--;
+
+                        if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
+                                assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
+                                event_update_signal_fd(s->event);
+                        }
+
+                        break;
+
+                case SOURCE_EXIT:
+                        s->enabled = m;
+                        prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
+                        break;
+
+                case SOURCE_DEFER:
+                        s->enabled = m;
+                        break;
+
+                case SOURCE_WATCHDOG:
+                        assert_not_reached("Wut? I shouldn't exist.");
+                }
+
+        } else {
+                switch (s->type) {
+
+                case SOURCE_IO:
+                        r = source_io_register(s, m, s->io.events);
+                        if (r < 0)
+                                return r;
+
+                        s->enabled = m;
+                        break;
+
+                case SOURCE_MONOTONIC:
+                        s->enabled = m;
+                        prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
+                        prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
+                        break;
+
+                case SOURCE_REALTIME:
+                        s->enabled = m;
+                        prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
+                        prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
+                        break;
+
+                case SOURCE_SIGNAL:
+                        s->enabled = m;
+
+                        if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)  {
+                                assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0);
+                                event_update_signal_fd(s->event);
+                        }
+                        break;
+
+                case SOURCE_CHILD:
+                        s->enabled = m;
+
+                        if (s->enabled == SD_EVENT_OFF) {
+                                s->event->n_enabled_child_sources++;
+
+                                if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
+                                        assert_se(sigaddset(&s->event->sigset, SIGCHLD) == 0);
+                                        event_update_signal_fd(s->event);
+                                }
+                        }
+                        break;
+
+                case SOURCE_EXIT:
+                        s->enabled = m;
+                        prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
+                        break;
+
+                case SOURCE_DEFER:
+                        s->enabled = m;
+                        break;
+
+                case SOURCE_WATCHDOG:
+                        assert_not_reached("Wut? I shouldn't exist.");
+                }
+        }
+
+        if (s->pending)
+                prioq_reshuffle(s->event->pending, s, &s->pending_index);
+
+        if (s->prepare)
+                prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) {
+        assert_return(s, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        *usec = s->time.next;
+        return 0;
+}
+
+_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
+        assert_return(s, -EINVAL);
+        assert_return(usec != (uint64_t) -1, -EINVAL);
+        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        s->time.next = usec;
+
+        source_set_pending(s, false);
+
+        if (s->type == SOURCE_REALTIME) {
+                prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
+                prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
+        } else {
+                prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
+                prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
+        }
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) {
+        assert_return(s, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        *usec = s->time.accuracy;
+        return 0;
+}
+
+_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) {
+        assert_return(s, -EINVAL);
+        assert_return(usec != (uint64_t) -1, -EINVAL);
+        assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (usec == 0)
+                usec = DEFAULT_ACCURACY_USEC;
+
+        s->time.accuracy = usec;
+
+        source_set_pending(s, false);
+
+        if (s->type == SOURCE_REALTIME)
+                prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
+        else
+                prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
+        assert_return(s, -EINVAL);
+        assert_return(pid, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        *pid = s->child.pid;
+        return 0;
+}
+
+_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) {
+        int r;
+
+        assert_return(s, -EINVAL);
+        assert_return(s->type != SOURCE_EXIT, -EDOM);
+        assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (s->prepare == callback)
+                return 0;
+
+        if (callback && s->prepare) {
+                s->prepare = callback;
+                return 0;
+        }
+
+        r = prioq_ensure_allocated(&s->event->prepare, prepare_prioq_compare);
+        if (r < 0)
+                return r;
+
+        s->prepare = callback;
+
+        if (callback) {
+                r = prioq_put(s->event->prepare, s, &s->prepare_index);
+                if (r < 0)
+                        return r;
+        } else
+                prioq_remove(s->event->prepare, s, &s->prepare_index);
+
+        return 0;
+}
+
+_public_ void* sd_event_source_get_userdata(sd_event_source *s) {
+        assert_return(s, NULL);
+
+        return s->userdata;
+}
+
+_public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) {
+        void *ret;
+
+        assert_return(s, NULL);
+
+        ret = s->userdata;
+        s->userdata = userdata;
+
+        return ret;
+}
+
+static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
+        usec_t c;
+        assert(e);
+        assert(a <= b);
+
+        if (a <= 0)
+                return 0;
+
+        if (b <= a + 1)
+                return a;
+
+        /*
+          Find a good time to wake up again between times a and b. We
+          have two goals here:
+
+          a) We want to wake up as seldom as possible, hence prefer
+             later times over earlier times.
+
+          b) But if we have to wake up, then let's make sure to
+             dispatch as much as possible on the entire system.
+
+          We implement this by waking up everywhere at the same time
+          within any given minute if we can, synchronised via the
+          perturbation value determined from the boot ID. If we can't,
+          then we try to find the same spot in every 10s, then 1s and
+          then 250ms step. Otherwise, we pick the last possible time
+          to wake up.
+        */
+
+        c = (b / USEC_PER_MINUTE) * USEC_PER_MINUTE + e->perturb;
+        if (c >= b) {
+                if (_unlikely_(c < USEC_PER_MINUTE))
+                        return b;
+
+                c -= USEC_PER_MINUTE;
+        }
+
+        if (c >= a)
+                return c;
+
+        c = (b / (USEC_PER_SEC*10)) * (USEC_PER_SEC*10) + (e->perturb % (USEC_PER_SEC*10));
+        if (c >= b) {
+                if (_unlikely_(c < USEC_PER_SEC*10))
+                        return b;
+
+                c -= USEC_PER_SEC*10;
+        }
+
+        if (c >= a)
+                return c;
+
+        c = (b / USEC_PER_SEC) * USEC_PER_SEC + (e->perturb % USEC_PER_SEC);
+        if (c >= b) {
+                if (_unlikely_(c < USEC_PER_SEC))
+                        return b;
+
+                c -= USEC_PER_SEC;
+        }
+
+        if (c >= a)
+                return c;
+
+        c = (b / (USEC_PER_MSEC*250)) * (USEC_PER_MSEC*250) + (e->perturb % (USEC_PER_MSEC*250));
+        if (c >= b) {
+                if (_unlikely_(c < USEC_PER_MSEC*250))
+                        return b;
+
+                c -= USEC_PER_MSEC*250;
+        }
+
+        if (c >= a)
+                return c;
+
+        return b;
+}
+
+static int event_arm_timer(
+                sd_event *e,
+                int timer_fd,
+                Prioq *earliest,
+                Prioq *latest,
+                usec_t *next) {
+
+        struct itimerspec its = {};
+        sd_event_source *a, *b;
+        usec_t t;
+        int r;
+
+        assert(e);
+        assert(next);
+
+        a = prioq_peek(earliest);
+        if (!a || a->enabled == SD_EVENT_OFF) {
+
+                if (timer_fd < 0)
+                        return 0;
+
+                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);
+
+        t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy);
+        if (*next == t)
+                return 0;
+
+        assert_se(timer_fd >= 0);
+
+        if (t == 0) {
+                /* We don' want to disarm here, just mean some time looooong ago. */
+                its.it_value.tv_sec = 0;
+                its.it_value.tv_nsec = 1;
+        } else
+                timespec_store(&its.it_value, t);
+
+        r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
+        if (r < 0)
+                return -errno;
+
+        *next = t;
+        return 0;
+}
+
+static int process_io(sd_event *e, sd_event_source *s, uint32_t revents) {
+        assert(e);
+        assert(s);
+        assert(s->type == SOURCE_IO);
+
+        /* If the event source was already pending, we just OR in the
+         * new revents, otherwise we reset the value. The ORing is
+         * necessary to handle EPOLLONESHOT events properly where
+         * readability might happen independently of writability, and
+         * we need to keep track of both */
+
+        if (s->pending)
+                s->io.revents |= revents;
+        else
+                s->io.revents = revents;
+
+        return source_set_pending(s, true);
+}
+
+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_return(events == EPOLLIN, -EIO);
+
+        ss = read(fd, &x, sizeof(x));
+        if (ss < 0) {
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
+
+                return -errno;
+        }
+
+        if (_unlikely_(ss != sizeof(x)))
+                return -EIO;
+
+        if (next)
+                *next = (usec_t) -1;
+
+        return 0;
+}
+
+static int process_timer(
+                sd_event *e,
+                usec_t n,
+                Prioq *earliest,
+                Prioq *latest) {
+
+        sd_event_source *s;
+        int r;
+
+        assert(e);
+
+        for (;;) {
+                s = prioq_peek(earliest);
+                if (!s ||
+                    s->time.next > n ||
+                    s->enabled == SD_EVENT_OFF ||
+                    s->pending)
+                        break;
+
+                r = source_set_pending(s, true);
+                if (r < 0)
+                        return r;
+
+                prioq_reshuffle(earliest, s, &s->time.earliest_index);
+                prioq_reshuffle(latest, s, &s->time.latest_index);
+        }
+
+        return 0;
+}
+
+static int process_child(sd_event *e) {
+        sd_event_source *s;
+        Iterator i;
+        int r;
+
+        assert(e);
+
+        e->need_process_child = false;
+
+        /*
+           So, this is ugly. We iteratively invoke waitid() with P_PID
+           + WNOHANG for each PID we wait for, instead of using
+           P_ALL. This is because we only want to get child
+           information of very specific child processes, and not all
+           of them. We might not have processed the SIGCHLD even of a
+           previous invocation and we don't want to maintain a
+           unbounded *per-child* event queue, hence we really don't
+           want anything flushed out of the kernel's queue that we
+           don't care about. Since this is O(n) this means that if you
+           have a lot of processes you probably want to handle SIGCHLD
+           yourself.
+
+           We do not reap the children here (by using WNOWAIT), this
+           is only done after the event source is dispatched so that
+           the callback still sees the process as a zombie.
+        */
+
+        HASHMAP_FOREACH(s, e->child_sources, i) {
+                assert(s->type == SOURCE_CHILD);
+
+                if (s->pending)
+                        continue;
+
+                if (s->enabled == SD_EVENT_OFF)
+                        continue;
+
+                zero(s->child.siginfo);
+                r = waitid(P_PID, s->child.pid, &s->child.siginfo,
+                           WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
+                if (r < 0)
+                        return -errno;
+
+                if (s->child.siginfo.si_pid != 0) {
+                        bool zombie =
+                                s->child.siginfo.si_code == CLD_EXITED ||
+                                s->child.siginfo.si_code == CLD_KILLED ||
+                                s->child.siginfo.si_code == CLD_DUMPED;
+
+                        if (!zombie && (s->child.options & WEXITED)) {
+                                /* If the child isn't dead then let's
+                                 * immediately remove the state change
+                                 * from the queue, since there's no
+                                 * benefit in leaving it queued */
+
+                                assert(s->child.options & (WSTOPPED|WCONTINUED));
+                                waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
+                        }
+
+                        r = source_set_pending(s, true);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
+
+static int process_signal(sd_event *e, uint32_t events) {
+        bool read_one = false;
+        int r;
+
+        assert(e);
+        assert(e->signal_sources);
+
+        assert_return(events == EPOLLIN, -EIO);
+
+        for (;;) {
+                struct signalfd_siginfo si;
+                ssize_t ss;
+                sd_event_source *s;
+
+                ss = read(e->signal_fd, &si, sizeof(si));
+                if (ss < 0) {
+                        if (errno == EAGAIN || errno == EINTR)
+                                return read_one;
+
+                        return -errno;
+                }
+
+                if (_unlikely_(ss != sizeof(si)))
+                        return -EIO;
+
+                read_one = true;
+
+                s = e->signal_sources[si.ssi_signo];
+                if (si.ssi_signo == SIGCHLD) {
+                        r = process_child(e);
+                        if (r < 0)
+                                return r;
+                        if (r > 0 || !s)
+                                continue;
+                } else
+                        if (!s)
+                                return -EIO;
+
+                s->signal.siginfo = si;
+                r = source_set_pending(s, true);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int source_dispatch(sd_event_source *s) {
+        int r = 0;
+
+        assert(s);
+        assert(s->pending || s->type == SOURCE_EXIT);
+
+        if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
+                r = source_set_pending(s, false);
+                if (r < 0)
+                        return r;
+        }
+
+        if (s->enabled == SD_EVENT_ONESHOT) {
+                r = sd_event_source_set_enabled(s, SD_EVENT_OFF);
+                if (r < 0)
+                        return r;
+        }
+
+        s->dispatching = true;
+
+        switch (s->type) {
+
+        case SOURCE_IO:
+                r = s->io.callback(s, s->io.fd, s->io.revents, s->userdata);
+                break;
+
+        case SOURCE_MONOTONIC:
+                r = s->time.callback(s, s->time.next, s->userdata);
+                break;
+
+        case SOURCE_REALTIME:
+                r = s->time.callback(s, s->time.next, s->userdata);
+                break;
+
+        case SOURCE_SIGNAL:
+                r = s->signal.callback(s, &s->signal.siginfo, s->userdata);
+                break;
+
+        case SOURCE_CHILD: {
+                bool zombie;
+
+                zombie = s->child.siginfo.si_code == CLD_EXITED ||
+                         s->child.siginfo.si_code == CLD_KILLED ||
+                         s->child.siginfo.si_code == CLD_DUMPED;
+
+                r = s->child.callback(s, &s->child.siginfo, s->userdata);
+
+                /* Now, reap the PID for good. */
+                if (zombie)
+                        waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED);
+
+                break;
+        }
+
+        case SOURCE_DEFER:
+                r = s->defer.callback(s, s->userdata);
+                break;
+
+        case SOURCE_EXIT:
+                r = s->exit.callback(s, s->userdata);
+                break;
+
+        case SOURCE_WATCHDOG:
+                assert_not_reached("Wut? I shouldn't exist.");
+        }
+
+        s->dispatching = false;
+
+        if (r < 0)
+                log_debug("Event source %p returned error, disabling: %s", s, strerror(-r));
+
+        if (s->n_ref == 0)
+                source_free(s);
+        else if (r < 0)
+                sd_event_source_set_enabled(s, SD_EVENT_OFF);
+
+        return 1;
+}
+
+static int event_prepare(sd_event *e) {
+        int r;
+
+        assert(e);
+
+        for (;;) {
+                sd_event_source *s;
+
+                s = prioq_peek(e->prepare);
+                if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
+                        break;
+
+                s->prepare_iteration = e->iteration;
+                r = prioq_reshuffle(e->prepare, s, &s->prepare_index);
+                if (r < 0)
+                        return r;
+
+                assert(s->prepare);
+
+                s->dispatching = true;
+                r = s->prepare(s, s->userdata);
+                s->dispatching = false;
+
+                if (r < 0)
+                        log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r));
+
+                if (s->n_ref == 0)
+                        source_free(s);
+                else if (r < 0)
+                        sd_event_source_set_enabled(s, SD_EVENT_OFF);
+        }
+
+        return 0;
+}
+
+static int dispatch_exit(sd_event *e) {
+        sd_event_source *p;
+        int r;
+
+        assert(e);
+
+        p = prioq_peek(e->exit);
+        if (!p || p->enabled == SD_EVENT_OFF) {
+                e->state = SD_EVENT_FINISHED;
+                return 0;
+        }
+
+        sd_event_ref(e);
+        e->iteration++;
+        e->state = SD_EVENT_EXITING;
+
+        r = source_dispatch(p);
+
+        e->state = SD_EVENT_PASSIVE;
+        sd_event_unref(e);
+
+        return r;
+}
+
+static sd_event_source* event_next_pending(sd_event *e) {
+        sd_event_source *p;
+
+        assert(e);
+
+        p = prioq_peek(e->pending);
+        if (!p)
+                return NULL;
+
+        if (p->enabled == SD_EVENT_OFF)
+                return NULL;
+
+        return p;
+}
+
+static int arm_watchdog(sd_event *e) {
+        struct itimerspec its = {};
+        usec_t t;
+        int r;
+
+        assert(e);
+        assert(e->watchdog_fd >= 0);
+
+        t = sleep_between(e,
+                          e->watchdog_last + (e->watchdog_period / 2),
+                          e->watchdog_last + (e->watchdog_period * 3 / 4));
+
+        timespec_store(&its.it_value, t);
+
+        r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int process_watchdog(sd_event *e) {
+        assert(e);
+
+        if (!e->watchdog)
+                return 0;
+
+        /* Don't notify watchdog too often */
+        if (e->watchdog_last + e->watchdog_period / 4 > e->timestamp.monotonic)
+                return 0;
+
+        sd_notify(false, "WATCHDOG=1");
+        e->watchdog_last = e->timestamp.monotonic;
+
+        return arm_watchdog(e);
+}
+
+_public_ int sd_event_run(sd_event *e, uint64_t timeout) {
+        struct epoll_event *ev_queue;
+        unsigned ev_queue_max;
+        sd_event_source *p;
+        int r, i, m;
+
+        assert_return(e, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
+
+        if (e->exit_requested)
+                return dispatch_exit(e);
+
+        sd_event_ref(e);
+        e->iteration++;
+        e->state = SD_EVENT_RUNNING;
+
+        r = event_prepare(e);
+        if (r < 0)
+                goto finish;
+
+        r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next);
+        if (r < 0)
+                goto finish;
+
+        r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next);
+        if (r < 0)
+                goto finish;
+
+        if (event_next_pending(e) || e->need_process_child)
+                timeout = 0;
+        ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX);
+        ev_queue = newa(struct epoll_event, ev_queue_max);
+
+        m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
+                       timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
+        if (m < 0) {
+                r = errno == EAGAIN || errno == EINTR ? 1 : -errno;
+                goto finish;
+        }
+
+        dual_timestamp_get(&e->timestamp);
+
+        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, &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, &e->realtime_next);
+                else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL))
+                        r = process_signal(e, ev_queue[i].events);
+                else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
+                        r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
+                else
+                        r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = process_watchdog(e);
+        if (r < 0)
+                goto finish;
+
+        r = process_timer(e, e->timestamp.monotonic, e->monotonic_earliest, e->monotonic_latest);
+        if (r < 0)
+                goto finish;
+
+        r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest);
+        if (r < 0)
+                goto finish;
+
+        if (e->need_process_child) {
+                r = process_child(e);
+                if (r < 0)
+                        goto finish;
+        }
+
+        p = event_next_pending(e);
+        if (!p) {
+                r = 1;
+                goto finish;
+        }
+
+        r = source_dispatch(p);
+
+finish:
+        e->state = SD_EVENT_PASSIVE;
+        sd_event_unref(e);
+
+        return r;
+}
+
+_public_ int sd_event_loop(sd_event *e) {
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+        assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
+
+        sd_event_ref(e);
+
+        while (e->state != SD_EVENT_FINISHED) {
+                r = sd_event_run(e, (uint64_t) -1);
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = e->exit_code;
+
+finish:
+        sd_event_unref(e);
+        return r;
+}
+
+_public_ int sd_event_get_state(sd_event *e) {
+        assert_return(e, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        return e->state;
+}
+
+_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
+        assert_return(e, -EINVAL);
+        assert_return(code, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        if (!e->exit_requested)
+                return -ENODATA;
+
+        *code = e->exit_code;
+        return 0;
+}
+
+_public_ int sd_event_exit(sd_event *e, int code) {
+        assert_return(e, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        e->exit_requested = true;
+        e->exit_code = code;
+
+        return 0;
+}
+
+_public_ int sd_event_get_now_realtime(sd_event *e, uint64_t *usec) {
+        assert_return(e, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        *usec = e->timestamp.realtime;
+        return 0;
+}
+
+_public_ int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec) {
+        assert_return(e, -EINVAL);
+        assert_return(usec, -EINVAL);
+        assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        *usec = e->timestamp.monotonic;
+        return 0;
+}
+
+_public_ int sd_event_default(sd_event **ret) {
+
+        static thread_local sd_event *default_event = NULL;
+        sd_event *e;
+        int r;
+
+        if (!ret)
+                return !!default_event;
+
+        if (default_event) {
+                *ret = sd_event_ref(default_event);
+                return 0;
+        }
+
+        r = sd_event_new(&e);
+        if (r < 0)
+                return r;
+
+        e->default_event_ptr = &default_event;
+        e->tid = gettid();
+        default_event = e;
+
+        *ret = e;
+        return 1;
+}
+
+_public_ int sd_event_get_tid(sd_event *e, pid_t *tid) {
+        assert_return(e, -EINVAL);
+        assert_return(tid, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        if (e->tid != 0) {
+                *tid = e->tid;
+                return 0;
+        }
+
+        return -ENXIO;
+}
+
+_public_ int sd_event_set_watchdog(sd_event *e, int b) {
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        if (e->watchdog == !!b)
+                return e->watchdog;
+
+        if (b) {
+                struct epoll_event ev = {};
+
+                r = sd_watchdog_enabled(false, &e->watchdog_period);
+                if (r <= 0)
+                        return r;
+
+                /* Issue first ping immediately */
+                sd_notify(false, "WATCHDOG=1");
+                e->watchdog_last = now(CLOCK_MONOTONIC);
+
+                e->watchdog_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
+                if (e->watchdog_fd < 0)
+                        return -errno;
+
+                r = arm_watchdog(e);
+                if (r < 0)
+                        goto fail;
+
+                ev.events = EPOLLIN;
+                ev.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG);
+
+                r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev);
+                if (r < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+        } else {
+                if (e->watchdog_fd >= 0) {
+                        epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
+                        close_nointr_nofail(e->watchdog_fd);
+                        e->watchdog_fd = -1;
+                }
+        }
+
+        e->watchdog = !!b;
+        return e->watchdog;
+
+fail:
+        close_nointr_nofail(e->watchdog_fd);
+        e->watchdog_fd = -1;
+        return r;
+}
+
+_public_ int sd_event_get_watchdog(sd_event *e) {
+        assert_return(e, -EINVAL);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        return e->watchdog;
+}
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
new file mode 100644
index 0000000..28ef6a3
--- /dev/null
+++ b/src/libsystemd/sd-event/test-event.c
@@ -0,0 +1,248 @@
+/*-*- 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 "log.h"
+#include "util.h"
+
+static int prepare_handler(sd_event_source *s, void *userdata) {
+        log_info("preparing %c", PTR_TO_INT(userdata));
+        return 1;
+}
+
+static bool got_a, got_b, got_c, got_unref;
+static unsigned got_d;
+
+static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        sd_event_source_unref(s);
+        got_unref = true;
+        return 0;
+}
+
+static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+
+        log_info("got IO on %c", PTR_TO_INT(userdata));
+
+        if (userdata == INT_TO_PTR('a')) {
+                assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
+                assert_se(!got_a);
+                got_a = true;
+        } else if (userdata == INT_TO_PTR('b')) {
+                assert_se(!got_b);
+                got_b = true;
+        } else if (userdata == INT_TO_PTR('d')) {
+                got_d++;
+                if (got_d < 2)
+                        assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
+                else
+                        assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
+        } else
+                assert_not_reached("Yuck!");
+
+        return 1;
+}
+
+static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
+
+        assert(s);
+        assert(si);
+
+        log_info("got child on %c", PTR_TO_INT(userdata));
+
+        assert(userdata == INT_TO_PTR('f'));
+
+        assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
+        sd_event_source_unref(s);
+
+        return 1;
+}
+
+static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+        sd_event_source *p;
+        sigset_t ss;
+        pid_t pid;
+
+        assert(s);
+        assert(si);
+
+        log_info("got signal on %c", PTR_TO_INT(userdata));
+
+        assert(userdata == INT_TO_PTR('e'));
+
+        assert_se(sigemptyset(&ss) >= 0);
+        assert_se(sigaddset(&ss, SIGCHLD) >= 0);
+        assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
+
+        pid = fork();
+        assert_se(pid >= 0);
+
+        if (pid == 0)
+                _exit(0);
+
+        assert_se(sd_event_add_child(sd_event_source_get_event(s), pid, WEXITED, child_handler, INT_TO_PTR('f'), &p) >= 0);
+        assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
+
+        sd_event_source_unref(s);
+
+        return 1;
+}
+
+static int defer_handler(sd_event_source *s, void *userdata) {
+        sd_event_source *p;
+        sigset_t ss;
+
+        assert(s);
+
+        log_info("got defer on %c", PTR_TO_INT(userdata));
+
+        assert(userdata == INT_TO_PTR('d'));
+
+        assert_se(sigemptyset(&ss) >= 0);
+        assert_se(sigaddset(&ss, SIGUSR1) >= 0);
+        assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
+        assert_se(sd_event_add_signal(sd_event_source_get_event(s), SIGUSR1, signal_handler, INT_TO_PTR('e'), &p) >= 0);
+        assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
+        raise(SIGUSR1);
+
+        sd_event_source_unref(s);
+
+        return 1;
+}
+
+static bool do_quit = false;
+
+static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+        log_info("got timer on %c", PTR_TO_INT(userdata));
+
+        if (userdata == INT_TO_PTR('c')) {
+
+                if (do_quit) {
+                        sd_event_source *p;
+
+                        assert_se(sd_event_add_defer(sd_event_source_get_event(s), defer_handler, INT_TO_PTR('d'), &p) >= 0);
+                        assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
+                } else {
+                        assert(!got_c);
+                        got_c = true;
+                }
+        } else
+                assert_not_reached("Huh?");
+
+        return 2;
+}
+
+static bool got_exit = false;
+
+static int exit_handler(sd_event_source *s, void *userdata) {
+        log_info("got quit handler on %c", PTR_TO_INT(userdata));
+
+        got_exit = true;
+
+        return 3;
+}
+
+int main(int argc, char *argv[]) {
+        sd_event *e = NULL;
+        sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
+        static const char ch = 'x';
+        int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
+
+        assert_se(pipe(a) >= 0);
+        assert_se(pipe(b) >= 0);
+        assert_se(pipe(d) >= 0);
+        assert_se(pipe(k) >= 0);
+
+        assert_se(sd_event_default(&e) >= 0);
+
+        assert_se(sd_event_set_watchdog(e, true) >= 0);
+
+        /* Test whether we cleanly can destroy an io event source from its own handler */
+        got_unref = false;
+        assert_se(sd_event_add_io(e, k[0], EPOLLIN, unref_handler, NULL, &t) >= 0);
+        assert_se(write(k[1], &ch, 1) == 1);
+        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
+        assert_se(got_unref);
+
+        got_a = false, got_b = false, got_c = false, got_d = 0;
+
+        /* Add a oneshot handler, trigger it, re-enable it, and trigger
+         * it again. */
+        assert_se(sd_event_add_io(e, d[0], EPOLLIN, io_handler, INT_TO_PTR('d'), &w) >= 0);
+        assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
+        assert_se(write(d[1], &ch, 1) >= 0);
+        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
+        assert_se(got_d == 1);
+        assert_se(write(d[1], &ch, 1) >= 0);
+        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
+        assert_se(got_d == 2);
+
+        assert_se(sd_event_add_io(e, a[0], EPOLLIN, io_handler, INT_TO_PTR('a'), &x) >= 0);
+        assert_se(sd_event_add_io(e, b[0], EPOLLIN, io_handler, INT_TO_PTR('b'), &y) >= 0);
+        assert_se(sd_event_add_monotonic(e, 0, 0, time_handler, INT_TO_PTR('c'), &z) >= 0);
+        assert_se(sd_event_add_exit(e, exit_handler, INT_TO_PTR('g'), &q) >= 0);
+
+        assert_se(sd_event_source_set_priority(x, 99) >= 0);
+        assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
+        assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
+        assert_se(sd_event_source_set_priority(z, 50) >= 0);
+        assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
+        assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
+
+        assert_se(write(a[1], &ch, 1) >= 0);
+        assert_se(write(b[1], &ch, 1) >= 0);
+
+        assert_se(!got_a && !got_b && !got_c);
+
+        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
+
+        assert_se(!got_a && got_b && !got_c);
+
+        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
+
+        assert_se(!got_a && got_b && got_c);
+
+        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
+
+        assert_se(got_a && got_b && got_c);
+
+        sd_event_source_unref(x);
+        sd_event_source_unref(y);
+
+        do_quit = true;
+        assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
+        assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
+
+        assert_se(sd_event_loop(e) >= 0);
+
+        sd_event_source_unref(z);
+        sd_event_source_unref(q);
+
+        sd_event_source_unref(w);
+
+        sd_event_unref(e);
+
+        close_pipe(a);
+        close_pipe(b);
+        close_pipe(d);
+        close_pipe(k);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-memfd.c b/src/libsystemd/sd-memfd.c
deleted file mode 100644
index 112c95f..0000000
--- a/src/libsystemd/sd-memfd.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*-*- 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 <stdio.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-
-#include "util.h"
-#include "kdbus.h"
-
-#include "sd-memfd.h"
-
-struct sd_memfd {
-        int fd;
-        FILE *f;
-};
-
-_public_ int sd_memfd_new(sd_memfd **m) {
-        struct kdbus_cmd_memfd_make cmd = {
-                .size = sizeof(struct kdbus_cmd_memfd_make),
-        };
-        _cleanup_close_ int kdbus = -1;
-        sd_memfd *n;
-
-        assert_return(m, -EINVAL);
-
-        kdbus = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (kdbus < 0)
-                return -errno;
-
-        if (ioctl(kdbus, KDBUS_CMD_MEMFD_NEW, &cmd) < 0)
-                return -errno;
-
-        n = new0(struct sd_memfd, 1);
-        if (!n) {
-                close_nointr_nofail(cmd.fd);
-                return -ENOMEM;
-        }
-
-        n->fd = cmd.fd;
-        *m = n;
-        return 0;
-}
-
-_public_ int sd_memfd_make(int fd, sd_memfd **m) {
-        sd_memfd *n;
-        uint64_t sz;
-
-        assert_return(m, -EINVAL);
-        assert_return(fd >= 0, -EINVAL);
-
-        /* Check if this is a valid memfd */
-        if (ioctl(fd, KDBUS_CMD_MEMFD_SIZE_GET, &sz) < 0)
-                return -ENOTTY;
-
-        n = new0(struct sd_memfd, 1);
-        if (!n)
-                return -ENOMEM;
-
-        n->fd = fd;
-        *m = n;
-
-        return 0;
-}
-
-_public_ void sd_memfd_free(sd_memfd *m) {
-        if (!m)
-                return;
-
-        if (m->f)
-                fclose(m->f);
-        else
-                close_nointr_nofail(m->fd);
-
-        free(m);
-}
-
-_public_ int sd_memfd_get_fd(sd_memfd *m) {
-        assert_return(m, -EINVAL);
-
-        return m->fd;
-}
-
-_public_ int sd_memfd_get_file(sd_memfd *m, FILE **f) {
-        assert_return(m, -EINVAL);
-        assert_return(f, -EINVAL);
-
-        if (!m->f) {
-                m->f = fdopen(m->fd, "r+");
-                if (!m->f)
-                        return -errno;
-        }
-
-        *f = m->f;
-        return 0;
-}
-
-_public_ int sd_memfd_dup_fd(sd_memfd *m) {
-        int fd;
-
-        assert_return(m, -EINVAL);
-
-        fd = fcntl(m->fd, F_DUPFD_CLOEXEC, 3);
-        if (fd < 0)
-                return -errno;
-
-        return fd;
-}
-
-_public_ int sd_memfd_map(sd_memfd *m, uint64_t offset, size_t size, void **p) {
-        void *q;
-        int sealed;
-
-        assert_return(m, -EINVAL);
-        assert_return(size > 0, -EINVAL);
-        assert_return(p, -EINVAL);
-
-        sealed = sd_memfd_get_sealed(m);
-        if (sealed < 0)
-                return sealed;
-
-        q = mmap(NULL, size, sealed ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, m->fd, offset);
-        if (q == MAP_FAILED)
-                return -errno;
-
-        *p = q;
-        return 0;
-}
-
-_public_ int sd_memfd_set_sealed(sd_memfd *m, int b) {
-        int r;
-
-        assert_return(m, -EINVAL);
-
-        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_SET, b);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-_public_ int sd_memfd_get_sealed(sd_memfd *m) {
-        int r, b;
-
-        assert_return(m, -EINVAL);
-
-        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_GET, &b);
-        if (r < 0)
-                return -errno;
-
-        return !!b;
-}
-
-_public_ int sd_memfd_get_size(sd_memfd *m, uint64_t *sz) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(sz, -EINVAL);
-
-        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_GET, sz);
-        if (r < 0)
-                return -errno;
-
-        return r;
-}
-
-_public_ int sd_memfd_set_size(sd_memfd *m, uint64_t sz) {
-        int r;
-
-        assert_return(m, -EINVAL);
-
-        r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
-        if (r < 0)
-                return -errno;
-
-        return r;
-}
-
-_public_ int sd_memfd_new_and_map(sd_memfd **m, size_t sz, void **p) {
-        sd_memfd *n;
-        int r;
-
-        r = sd_memfd_new(&n);
-        if (r < 0)
-                return r;
-
-        r = sd_memfd_set_size(n, sz);
-        if (r < 0) {
-                sd_memfd_free(n);
-                return r;
-        }
-
-        r = sd_memfd_map(n, 0, sz, p);
-        if (r < 0) {
-                sd_memfd_free(n);
-                return r;
-        }
-
-        *m = n;
-        return 0;
-}
diff --git a/src/libsystemd/sd-resolve.c b/src/libsystemd/sd-resolve.c
deleted file mode 100644
index 464967b..0000000
--- a/src/libsystemd/sd-resolve.c
+++ /dev/null
@@ -1,1130 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2005-2008 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 <assert.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/select.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <stdint.h>
-#include <pthread.h>
-#include <sys/prctl.h>
-
-#include "sd-resolve.h"
-#include "util.h"
-
-#define MAX_WORKERS 16
-#define MAX_QUERIES 256
-#define BUFSIZE (10240)
-
-typedef enum {
-        REQUEST_ADDRINFO,
-        RESPONSE_ADDRINFO,
-        REQUEST_NAMEINFO,
-        RESPONSE_NAMEINFO,
-        REQUEST_RES_QUERY,
-        REQUEST_RES_SEARCH,
-        RESPONSE_RES,
-        REQUEST_TERMINATE,
-        RESPONSE_DIED
-} QueryType;
-
-enum {
-        REQUEST_RECV_FD = 0,
-        REQUEST_SEND_FD = 1,
-        RESPONSE_RECV_FD = 2,
-        RESPONSE_SEND_FD = 3,
-        MESSAGE_FD_MAX = 4
-};
-
-struct sd_resolve {
-        int fds[MESSAGE_FD_MAX];
-
-        pthread_t workers[MAX_WORKERS];
-        unsigned valid_workers;
-
-        unsigned current_id, current_index;
-        sd_resolve_query* queries[MAX_QUERIES];
-
-        sd_resolve_query *done_head, *done_tail;
-
-        int n_queries;
-        int dead;
-};
-
-struct sd_resolve_query {
-        sd_resolve *resolve;
-        int done;
-        unsigned id;
-        QueryType type;
-        sd_resolve_query *done_next, *done_prev;
-        int ret;
-        int _errno;
-        int _h_errno;
-        struct addrinfo *addrinfo;
-        char *serv, *host;
-        void *userdata;
-};
-
-typedef struct RHeader {
-        QueryType type;
-        unsigned id;
-        size_t length;
-} RHeader;
-
-typedef struct AddrInfoRequest {
-        struct RHeader header;
-        int hints_is_null;
-        int ai_flags;
-        int ai_family;
-        int ai_socktype;
-        int ai_protocol;
-        size_t node_len, service_len;
-} AddrInfoRequest;
-
-typedef struct AddrInfoResponse {
-        struct RHeader header;
-        int ret;
-        int _errno;
-        int _h_errno;
-        /* followed by addrinfo_serialization[] */
-} AddrInfoResponse;
-
-typedef struct AddrInfoSerialization {
-        int ai_flags;
-        int ai_family;
-        int ai_socktype;
-        int ai_protocol;
-        size_t ai_addrlen;
-        size_t canonname_len;
-        /* Followed by ai_addr amd ai_canonname with variable lengths */
-} AddrInfoSerialization;
-
-typedef struct NameInfoRequest {
-        struct RHeader header;
-        int flags;
-        socklen_t sockaddr_len;
-        int gethost, getserv;
-} NameInfoRequest;
-
-typedef struct NameInfoResponse {
-        struct RHeader header;
-        size_t hostlen, servlen;
-        int ret;
-        int _errno;
-        int _h_errno;
-} NameInfoResponse;
-
-typedef struct ResRequest {
-        struct RHeader header;
-        int class;
-        int type;
-        size_t dname_len;
-} ResRequest;
-
-typedef struct ResResponse {
-        struct RHeader header;
-        int ret;
-        int _errno;
-        int _h_errno;
-} ResResponse;
-
-typedef union Packet {
-        RHeader rheader;
-        AddrInfoRequest addrinfo_request;
-        AddrInfoResponse addrinfo_response;
-        NameInfoRequest nameinfo_request;
-        NameInfoResponse nameinfo_response;
-        ResRequest res_request;
-        ResResponse res_response;
-} Packet;
-
-static int send_died(int out_fd) {
-        RHeader rh = {};
-        assert(out_fd > 0);
-
-        rh.type = RESPONSE_DIED;
-        rh.id = 0;
-        rh.length = sizeof(rh);
-
-        return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
-}
-
-static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
-        AddrInfoSerialization s;
-        size_t cnl, l;
-        assert(p);
-        assert(ai);
-        assert(length);
-        assert(*length <= maxlength);
-
-        cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
-        l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
-
-        if (*length + l > maxlength)
-                return NULL;
-
-        s.ai_flags = ai->ai_flags;
-        s.ai_family = ai->ai_family;
-        s.ai_socktype = ai->ai_socktype;
-        s.ai_protocol = ai->ai_protocol;
-        s.ai_addrlen = ai->ai_addrlen;
-        s.canonname_len = cnl;
-
-        memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
-        memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
-
-        if (ai->ai_canonname)
-                strcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname);
-
-        *length += l;
-        return (uint8_t*) p + l;
-}
-
-static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
-        AddrInfoResponse data[BUFSIZE/sizeof(AddrInfoResponse) + 1] = {};
-        AddrInfoResponse *resp = data;
-        assert(out_fd >= 0);
-
-        resp->header.type = RESPONSE_ADDRINFO;
-        resp->header.id = id;
-        resp->header.length = sizeof(AddrInfoResponse);
-        resp->ret = ret;
-        resp->_errno = _errno;
-        resp->_h_errno = _h_errno;
-
-        if (ret == 0 && ai) {
-                void *p = data + 1;
-                struct addrinfo *k;
-
-                for (k = ai; k; k = k->ai_next) {
-                        p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p);
-                        if (!p) {
-                                resp->ret = EAI_MEMORY;
-                                break;
-                        }
-                }
-        }
-
-        if (ai)
-                freeaddrinfo(ai);
-
-        return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
-}
-
-static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
-        NameInfoResponse data[BUFSIZE/sizeof(NameInfoResponse) + 1] = {};
-        size_t hl, sl;
-        NameInfoResponse *resp = data;
-
-        assert(out_fd >= 0);
-
-        sl = serv ? strlen(serv)+1 : 0;
-        hl = host ? strlen(host)+1 : 0;
-
-        resp->header.type = RESPONSE_NAMEINFO;
-        resp->header.id = id;
-        resp->header.length = sizeof(NameInfoResponse) + hl + sl;
-        resp->ret = ret;
-        resp->_errno = _errno;
-        resp->_h_errno = _h_errno;
-        resp->hostlen = hl;
-        resp->servlen = sl;
-
-        assert(sizeof(data) >= resp->header.length);
-
-        if (host)
-                memcpy((uint8_t *)data + sizeof(NameInfoResponse), host, hl);
-
-        if (serv)
-                memcpy((uint8_t *)data + sizeof(NameInfoResponse) + hl, serv, sl);
-
-        return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
-}
-
-static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
-        ResResponse data[BUFSIZE/sizeof(ResResponse) + 1] = {};
-        ResResponse *resp = data;
-
-        assert(out_fd >= 0);
-
-        resp->header.type = RESPONSE_RES;
-        resp->header.id = id;
-        resp->header.length = sizeof(ResResponse) + (ret < 0 ? 0 : ret);
-        resp->ret = ret;
-        resp->_errno = _errno;
-        resp->_h_errno = _h_errno;
-
-        assert(sizeof(data) >= resp->header.length);
-
-        if (ret > 0)
-                memcpy((uint8_t *)data + sizeof(ResResponse), answer, ret);
-
-        return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
-}
-
-static int handle_request(int out_fd, const Packet *packet, size_t length) {
-        const RHeader *req;
-        assert(out_fd >= 0);
-
-        req = &packet->rheader;
-        assert(req);
-        assert(length >= sizeof(RHeader));
-        assert(length == req->length);
-
-        switch (req->type) {
-        case REQUEST_ADDRINFO: {
-               struct addrinfo ai = {}, *result = NULL;
-               const AddrInfoRequest *ai_req = &packet->addrinfo_request;
-               const char *node, *service;
-               int ret;
-
-               assert(length >= sizeof(AddrInfoRequest));
-               assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len);
-
-               ai.ai_flags = ai_req->ai_flags;
-               ai.ai_family = ai_req->ai_family;
-               ai.ai_socktype = ai_req->ai_socktype;
-               ai.ai_protocol = ai_req->ai_protocol;
-
-               node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
-               service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
-
-               ret = getaddrinfo(node, service,
-                               ai_req->hints_is_null ? NULL : &ai,
-                               &result);
-
-               /* send_addrinfo_reply() frees result */
-               return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
-        }
-
-        case REQUEST_NAMEINFO: {
-               int ret;
-               const NameInfoRequest *ni_req = &packet->nameinfo_request;
-               char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
-               struct sockaddr_storage sa;
-
-               assert(length >= sizeof(NameInfoRequest));
-               assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len);
-
-               memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
-
-               ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
-                               ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
-                               ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
-                               ni_req->flags);
-
-               return send_nameinfo_reply(out_fd, req->id, ret,
-                               ret == 0 && ni_req->gethost ? hostbuf : NULL,
-                               ret == 0 && ni_req->getserv ? servbuf : NULL,
-                               errno, h_errno);
-        }
-
-        case REQUEST_RES_QUERY:
-        case REQUEST_RES_SEARCH: {
-                 int ret;
-                 HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
-                 const ResRequest *res_req = &packet->res_request;
-                 const char *dname;
-
-                 assert(length >= sizeof(ResRequest));
-                 assert(length == sizeof(ResRequest) + res_req->dname_len);
-
-                 dname = (const char *) req + sizeof(ResRequest);
-
-                 if (req->type == REQUEST_RES_QUERY)
-                         ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
-                 else
-                         ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
-
-                 return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
-        }
-
-        case REQUEST_TERMINATE:
-                 /* Quit */
-                 return -1;
-
-        default:
-                 ;
-        }
-
-        return 0;
-}
-
-static void* thread_worker(void *p) {
-        sd_resolve *resolve = p;
-        sigset_t fullset;
-
-        /* No signals in this thread please */
-        sigfillset(&fullset);
-        pthread_sigmask(SIG_BLOCK, &fullset, NULL);
-
-        while (!resolve->dead) {
-                Packet buf[BUFSIZE/sizeof(Packet) + 1];
-                ssize_t length;
-
-                length = recv(resolve->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0);
-
-                if (length <= 0) {
-                        if (length < 0 && (errno == EAGAIN || errno == EINTR))
-                                continue;
-                        break;
-                }
-
-                if (resolve->dead)
-                        break;
-
-                if (handle_request(resolve->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
-                        break;
-        }
-
-        send_died(resolve->fds[RESPONSE_SEND_FD]);
-
-        return NULL;
-}
-
-_public_ sd_resolve* sd_resolve_new(unsigned n_proc) {
-        sd_resolve *resolve = NULL;
-        int i, r;
-
-        assert(n_proc >= 1);
-
-        if (n_proc > MAX_WORKERS)
-                n_proc = MAX_WORKERS;
-
-        resolve = new(sd_resolve, 1);
-        if (!resolve) {
-                errno = ENOMEM;
-                goto fail;
-        }
-
-        resolve->dead = 0;
-        resolve->valid_workers = 0;
-
-        for (i = 0; i < MESSAGE_FD_MAX; i++)
-                resolve->fds[i] = -1;
-
-        memset(resolve->queries, 0, sizeof(resolve->queries));
-
-        r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds);
-        if (r < 0)
-                goto fail;
-
-        r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds+2);
-        if (r < 0)
-                goto fail;
-
-        for (resolve->valid_workers = 0; resolve->valid_workers < n_proc; resolve->valid_workers++) {
-                r = pthread_create(&resolve->workers[resolve->valid_workers], NULL, thread_worker, resolve);
-                if (r) {
-                        errno = r;
-                        goto fail;
-                }
-        }
-
-        resolve->current_index = resolve->current_id = 0;
-        resolve->done_head = resolve->done_tail = NULL;
-        resolve->n_queries = 0;
-
-        fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
-
-        return resolve;
-
-fail:
-        if (resolve)
-                sd_resolve_free(resolve);
-
-        return NULL;
-}
-
-_public_ void sd_resolve_free(sd_resolve *resolve) {
-        int i;
-        int saved_errno = errno;
-        unsigned p;
-
-        assert(resolve);
-
-        resolve->dead = 1;
-
-        if (resolve->fds[REQUEST_SEND_FD] >= 0) {
-                RHeader req = {};
-
-                req.type = REQUEST_TERMINATE;
-                req.length = sizeof(req);
-                req.id = 0;
-
-                /* Send one termination packet for each worker */
-                for (p = 0; p < resolve->valid_workers; p++)
-                        send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
-        }
-
-        /* Now terminate them and wait until they are gone. */
-        for (p = 0; p < resolve->valid_workers; p++) {
-                for (;;) {
-                        if (pthread_join(resolve->workers[p], NULL) != EINTR)
-                                break;
-                }
-        }
-
-        /* Close all communication channels */
-        for (i = 0; i < MESSAGE_FD_MAX; i++)
-                if (resolve->fds[i] >= 0)
-                        close(resolve->fds[i]);
-
-        for (p = 0; p < MAX_QUERIES; p++)
-                if (resolve->queries[p])
-                        sd_resolve_cancel(resolve, resolve->queries[p]);
-
-        free(resolve);
-
-        errno = saved_errno;
-}
-
-_public_ int sd_resolve_fd(sd_resolve *resolve) {
-        assert(resolve);
-
-        return resolve->fds[RESPONSE_RECV_FD];
-}
-
-static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
-        sd_resolve_query *q;
-        assert(resolve);
-
-        q = resolve->queries[id % MAX_QUERIES];
-        if (q)
-                if (q->id == id)
-                        return q;
-
-        return NULL;
-}
-
-static void complete_query(sd_resolve *resolve, sd_resolve_query *q) {
-        assert(resolve);
-        assert(q);
-        assert(!q->done);
-
-        q->done = 1;
-
-        if ((q->done_prev = resolve->done_tail))
-                resolve->done_tail->done_next = q;
-        else
-                resolve->done_head = q;
-
-        resolve->done_tail = q;
-        q->done_next = NULL;
-}
-
-static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
-        AddrInfoSerialization s;
-        size_t l;
-        struct addrinfo *ai;
-        assert(p);
-        assert(ret_ai);
-        assert(length);
-
-        if (*length < sizeof(AddrInfoSerialization))
-                return NULL;
-
-        memcpy(&s, p, sizeof(s));
-
-        l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
-        if (*length < l)
-                return NULL;
-
-        ai = new(struct addrinfo, 1);
-        if (!ai)
-                goto fail;
-
-        ai->ai_addr = NULL;
-        ai->ai_canonname = NULL;
-        ai->ai_next = NULL;
-
-        if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
-                goto fail;
-
-        if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
-                goto fail;
-
-        ai->ai_flags = s.ai_flags;
-        ai->ai_family = s.ai_family;
-        ai->ai_socktype = s.ai_socktype;
-        ai->ai_protocol = s.ai_protocol;
-        ai->ai_addrlen = s.ai_addrlen;
-
-        if (ai->ai_addr)
-                memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(AddrInfoSerialization), s.ai_addrlen);
-
-        if (ai->ai_canonname)
-                memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
-
-        *length -= l;
-        *ret_ai = ai;
-
-        return (const uint8_t*) p + l;
-
-
-fail:
-        if (ai)
-                sd_resolve_freeaddrinfo(ai);
-
-        return NULL;
-}
-
-static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
-        const RHeader *resp;
-        sd_resolve_query *q;
-
-        assert(resolve);
-
-        resp = &packet->rheader;
-        assert(resp);
-        assert(length >= sizeof(RHeader));
-        assert(length == resp->length);
-
-        if (resp->type == RESPONSE_DIED) {
-                resolve->dead = 1;
-                return 0;
-        }
-
-        q = lookup_query(resolve, resp->id);
-        if (!q)
-                return 0;
-
-        switch (resp->type) {
-        case RESPONSE_ADDRINFO: {
-                const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
-                const void *p;
-                size_t l;
-                struct addrinfo *prev = NULL;
-
-                assert(length >= sizeof(AddrInfoResponse));
-                assert(q->type == REQUEST_ADDRINFO);
-
-                q->ret = ai_resp->ret;
-                q->_errno = ai_resp->_errno;
-                q->_h_errno = ai_resp->_h_errno;
-                l = length - sizeof(AddrInfoResponse);
-                p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
-
-                while (l > 0 && p) {
-                        struct addrinfo *ai = NULL;
-                        p = unserialize_addrinfo(p, &ai, &l);
-
-                        if (!p || !ai) {
-                                q->ret = EAI_MEMORY;
-                                break;
-                        }
-
-                        if (prev)
-                                prev->ai_next = ai;
-                        else
-                                q->addrinfo = ai;
-
-                        prev = ai;
-                }
-
-                complete_query(resolve, q);
-                break;
-        }
-
-        case RESPONSE_NAMEINFO: {
-                const NameInfoResponse *ni_resp = &packet->nameinfo_response;
-
-                assert(length >= sizeof(NameInfoResponse));
-                assert(q->type == REQUEST_NAMEINFO);
-
-                q->ret = ni_resp->ret;
-                q->_errno = ni_resp->_errno;
-                q->_h_errno = ni_resp->_h_errno;
-
-                if (ni_resp->hostlen)
-                        if (!(q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1)))
-                                q->ret = EAI_MEMORY;
-
-                if (ni_resp->servlen)
-                        if (!(q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1)))
-                                q->ret = EAI_MEMORY;
-
-                complete_query(resolve, q);
-                break;
-        }
-
-        case RESPONSE_RES: {
-                const ResResponse *res_resp = &packet->res_response;
-
-                assert(length >= sizeof(ResResponse));
-                assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
-
-                q->ret = res_resp->ret;
-                q->_errno = res_resp->_errno;
-                q->_h_errno = res_resp->_h_errno;
-
-                if (res_resp->ret >= 0)  {
-                        if (!(q->serv = malloc(res_resp->ret))) {
-                                q->ret = -1;
-                                q->_errno = ENOMEM;
-                        } else
-                                memcpy(q->serv, (const char *)resp + sizeof(ResResponse), res_resp->ret);
-                }
-
-                complete_query(resolve, q);
-                break;
-        }
-
-        default:
-                ;
-        }
-
-        return 0;
-}
-
-_public_ int sd_resolve_wait(sd_resolve *resolve, int block) {
-        int handled = 0;
-        assert(resolve);
-
-        for (;;) {
-                Packet buf[BUFSIZE/sizeof(Packet) + 1];
-                ssize_t l;
-
-                if (resolve->dead) {
-                        errno = ECHILD;
-                        return -1;
-                }
-
-                l = recv(resolve->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0);
-                if (l < 0) {
-                        fd_set fds;
-
-                        if (errno != EAGAIN)
-                                return -1;
-
-                        if (!block || handled)
-                                return 0;
-
-                        FD_ZERO(&fds);
-                        FD_SET(resolve->fds[RESPONSE_RECV_FD], &fds);
-
-                        if (select(resolve->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
-                                return -1;
-
-                        continue;
-                }
-
-                if (handle_response(resolve, buf, (size_t) l) < 0)
-                        return -1;
-
-                handled = 1;
-        }
-}
-
-static sd_resolve_query *alloc_query(sd_resolve *resolve) {
-        sd_resolve_query *q;
-        assert(resolve);
-
-        if (resolve->n_queries >= MAX_QUERIES) {
-                errno = ENOMEM;
-                return NULL;
-        }
-
-        while (resolve->queries[resolve->current_index]) {
-                resolve->current_index++;
-                resolve->current_id++;
-
-                while (resolve->current_index >= MAX_QUERIES)
-                        resolve->current_index -= MAX_QUERIES;
-        }
-
-        q = resolve->queries[resolve->current_index] = new(sd_resolve_query, 1);
-        if (!q) {
-                errno = ENOMEM;
-                return NULL;
-        }
-
-        resolve->n_queries++;
-
-        q->resolve = resolve;
-        q->done = 0;
-        q->id = resolve->current_id;
-        q->done_next = q->done_prev = NULL;
-        q->ret = 0;
-        q->_errno = 0;
-        q->_h_errno = 0;
-        q->addrinfo = NULL;
-        q->userdata = NULL;
-        q->host = q->serv = NULL;
-
-        return q;
-}
-
-_public_ sd_resolve_query* sd_resolve_getaddrinfo(sd_resolve *resolve, const char *node, const char *service, const struct addrinfo *hints) {
-        AddrInfoRequest data[BUFSIZE/sizeof(AddrInfoRequest) + 1] = {};
-        AddrInfoRequest *req = data;
-        sd_resolve_query *q;
-        assert(resolve);
-        assert(node || service);
-
-        if (resolve->dead) {
-                errno = ECHILD;
-                return NULL;
-        }
-
-        q = alloc_query(resolve);
-        if (!q)
-                return NULL;
-
-        req->node_len = node ? strlen(node)+1 : 0;
-        req->service_len = service ? strlen(service)+1 : 0;
-
-        req->header.id = q->id;
-        req->header.type = q->type = REQUEST_ADDRINFO;
-        req->header.length = sizeof(AddrInfoRequest) + req->node_len + req->service_len;
-
-        if (req->header.length > BUFSIZE) {
-                errno = ENOMEM;
-                goto fail;
-        }
-
-        if (!(req->hints_is_null = !hints)) {
-                req->ai_flags = hints->ai_flags;
-                req->ai_family = hints->ai_family;
-                req->ai_socktype = hints->ai_socktype;
-                req->ai_protocol = hints->ai_protocol;
-        }
-
-        if (node)
-                strcpy((char*) req + sizeof(AddrInfoRequest), node);
-
-        if (service)
-                strcpy((char*) req + sizeof(AddrInfoRequest) + req->node_len, service);
-
-        if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
-                goto fail;
-
-        return q;
-
-fail:
-        if (q)
-                sd_resolve_cancel(resolve, q);
-
-        return NULL;
-}
-
-_public_ int sd_resolve_getaddrinfo_done(sd_resolve *resolve, sd_resolve_query* q, struct addrinfo **ret_res) {
-        int ret;
-        assert(resolve);
-        assert(q);
-        assert(q->resolve == resolve);
-        assert(q->type == REQUEST_ADDRINFO);
-
-        if (resolve->dead) {
-                errno = ECHILD;
-                return EAI_SYSTEM;
-        }
-
-        if (!q->done)
-                return EAI_AGAIN;
-
-        *ret_res = q->addrinfo;
-        q->addrinfo = NULL;
-
-        ret = q->ret;
-
-        if (ret == EAI_SYSTEM)
-                errno = q->_errno;
-
-        if (ret != 0)
-                h_errno = q->_h_errno;
-
-        sd_resolve_cancel(resolve, q);
-
-        return ret;
-}
-
-_public_ sd_resolve_query* sd_resolve_getnameinfo(sd_resolve *resolve, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
-        NameInfoRequest data[BUFSIZE/sizeof(NameInfoRequest) + 1] = {};
-        NameInfoRequest *req = data;
-        sd_resolve_query *q;
-
-        assert(resolve);
-        assert(sa);
-        assert(salen > 0);
-
-        if (resolve->dead) {
-                errno = ECHILD;
-                return NULL;
-        }
-
-        q = alloc_query(resolve);
-        if (!q)
-                return NULL;
-
-        req->header.id = q->id;
-        req->header.type = q->type = REQUEST_NAMEINFO;
-        req->header.length = sizeof(NameInfoRequest) + salen;
-
-        if (req->header.length > BUFSIZE) {
-                errno = ENOMEM;
-                goto fail;
-        }
-
-        req->flags = flags;
-        req->sockaddr_len = salen;
-        req->gethost = gethost;
-        req->getserv = getserv;
-
-        memcpy((uint8_t*) req + sizeof(NameInfoRequest), sa, salen);
-
-        if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
-                goto fail;
-
-        return q;
-
-fail:
-        if (q)
-                sd_resolve_cancel(resolve, q);
-
-        return NULL;
-}
-
-_public_ int sd_resolve_getnameinfo_done(sd_resolve *resolve, sd_resolve_query* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
-        int ret;
-        assert(resolve);
-        assert(q);
-        assert(q->resolve == resolve);
-        assert(q->type == REQUEST_NAMEINFO);
-        assert(!ret_host || hostlen);
-        assert(!ret_serv || servlen);
-
-        if (resolve->dead) {
-                errno = ECHILD;
-                return EAI_SYSTEM;
-        }
-
-        if (!q->done)
-                return EAI_AGAIN;
-
-        if (ret_host && q->host) {
-                strncpy(ret_host, q->host, hostlen);
-                ret_host[hostlen-1] = 0;
-        }
-
-        if (ret_serv && q->serv) {
-                strncpy(ret_serv, q->serv, servlen);
-                ret_serv[servlen-1] = 0;
-        }
-
-        ret = q->ret;
-
-        if (ret == EAI_SYSTEM)
-                errno = q->_errno;
-
-        if (ret != 0)
-                h_errno = q->_h_errno;
-
-        sd_resolve_cancel(resolve, q);
-
-        return ret;
-}
-
-static sd_resolve_query * resolve_res(sd_resolve *resolve, QueryType qtype, const char *dname, int class, int type) {
-        ResRequest data[BUFSIZE/sizeof(ResRequest) + 1];
-        ResRequest *req = data;
-        sd_resolve_query *q;
-
-        assert(resolve);
-        assert(dname);
-
-        if (resolve->dead) {
-                errno = ECHILD;
-                return NULL;
-        }
-
-        q = alloc_query(resolve);
-        if (!q)
-                return NULL;
-
-        req->dname_len = strlen(dname) + 1;
-
-        req->header.id = q->id;
-        req->header.type = q->type = qtype;
-        req->header.length = sizeof(ResRequest) + req->dname_len;
-
-        if (req->header.length > BUFSIZE) {
-                errno = ENOMEM;
-                goto fail;
-        }
-
-        req->class = class;
-        req->type = type;
-
-        strcpy((char*) req + sizeof(ResRequest), dname);
-
-        if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
-                goto fail;
-
-        return q;
-
-fail:
-        if (q)
-                sd_resolve_cancel(resolve, q);
-
-        return NULL;
-}
-
-_public_ sd_resolve_query* sd_resolve_res_query(sd_resolve *resolve, const char *dname, int class, int type) {
-        return resolve_res(resolve, REQUEST_RES_QUERY, dname, class, type);
-}
-
-_public_ sd_resolve_query* sd_resolve_res_search(sd_resolve *resolve, const char *dname, int class, int type) {
-        return resolve_res(resolve, REQUEST_RES_SEARCH, dname, class, type);
-}
-
-_public_ int sd_resolve_res_done(sd_resolve *resolve, sd_resolve_query* q, unsigned char **answer) {
-        int ret;
-        assert(resolve);
-        assert(q);
-        assert(q->resolve == resolve);
-        assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
-        assert(answer);
-
-        if (resolve->dead) {
-                errno = ECHILD;
-                return -ECHILD;
-        }
-
-        if (!q->done) {
-                errno = EAGAIN;
-                return -EAGAIN;
-        }
-
-        *answer = (unsigned char *)q->serv;
-        q->serv = NULL;
-
-        ret = q->ret;
-
-        if (ret < 0) {
-                errno = q->_errno;
-                h_errno = q->_h_errno;
-        }
-
-        sd_resolve_cancel(resolve, q);
-
-        return ret < 0 ? -errno : ret;
-}
-
-_public_ sd_resolve_query* sd_resolve_get_next(sd_resolve *resolve) {
-        assert(resolve);
-        return resolve->done_head;
-}
-
-_public_ int sd_resolve_get_n_queries(sd_resolve *resolve) {
-        assert(resolve);
-        return resolve->n_queries;
-}
-
-_public_ void sd_resolve_cancel(sd_resolve *resolve, sd_resolve_query* q) {
-        int i;
-        int saved_errno = errno;
-
-        assert(resolve);
-        assert(q);
-        assert(q->resolve == resolve);
-        assert(resolve->n_queries > 0);
-
-        if (q->done) {
-
-                if (q->done_prev)
-                        q->done_prev->done_next = q->done_next;
-                else
-                        resolve->done_head = q->done_next;
-
-                if (q->done_next)
-                        q->done_next->done_prev = q->done_prev;
-                else
-                        resolve->done_tail = q->done_prev;
-        }
-
-        i = q->id % MAX_QUERIES;
-        assert(resolve->queries[i] == q);
-        resolve->queries[i] = NULL;
-
-        sd_resolve_freeaddrinfo(q->addrinfo);
-        free(q->host);
-        free(q->serv);
-
-        resolve->n_queries--;
-        free(q);
-
-        errno = saved_errno;
-}
-
-_public_ void sd_resolve_freeaddrinfo(struct addrinfo *ai) {
-        int saved_errno = errno;
-
-        while (ai) {
-                struct addrinfo *next = ai->ai_next;
-
-                free(ai->ai_addr);
-                free(ai->ai_canonname);
-                free(ai);
-
-                ai = next;
-        }
-
-        errno = saved_errno;
-}
-
-_public_ int sd_resolve_isdone(sd_resolve *resolve, sd_resolve_query*q) {
-        assert(resolve);
-        assert(q);
-        assert(q->resolve == resolve);
-
-        return q->done;
-}
-
-_public_ void sd_resolve_setuserdata(sd_resolve *resolve, sd_resolve_query *q, void *userdata) {
-        assert(q);
-        assert(resolve);
-        assert(q->resolve = resolve);
-
-        q->userdata = userdata;
-}
-
-_public_ void* sd_resolve_getuserdata(sd_resolve *resolve, sd_resolve_query *q) {
-        assert(q);
-        assert(resolve);
-        assert(q->resolve = resolve);
-
-        return q->userdata;
-}
diff --git a/src/libsystemd/sd-resolve/Makefile b/src/libsystemd/sd-resolve/Makefile
new file mode 120000
index 0000000..94aaae2
--- /dev/null
+++ b/src/libsystemd/sd-resolve/Makefile
@@ -0,0 +1 @@
+../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-resolve/resolve-util.h b/src/libsystemd/sd-resolve/resolve-util.h
new file mode 100644
index 0000000..58df738
--- /dev/null
+++ b/src/libsystemd/sd-resolve/resolve-util.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Daniel Buch
+
+  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_resolve*, sd_resolve_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo*, sd_resolve_freeaddrinfo);
+#define _cleanup_resolve_free_ _cleanup_(sd_resolve_freep)
+#define _cleanup_resolve_addrinfo_free_ _cleanup_(sd_resolve_freeaddrinfop)
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
new file mode 100644
index 0000000..464967b
--- /dev/null
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -0,0 +1,1130 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2005-2008 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 <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#include "sd-resolve.h"
+#include "util.h"
+
+#define MAX_WORKERS 16
+#define MAX_QUERIES 256
+#define BUFSIZE (10240)
+
+typedef enum {
+        REQUEST_ADDRINFO,
+        RESPONSE_ADDRINFO,
+        REQUEST_NAMEINFO,
+        RESPONSE_NAMEINFO,
+        REQUEST_RES_QUERY,
+        REQUEST_RES_SEARCH,
+        RESPONSE_RES,
+        REQUEST_TERMINATE,
+        RESPONSE_DIED
+} QueryType;
+
+enum {
+        REQUEST_RECV_FD = 0,
+        REQUEST_SEND_FD = 1,
+        RESPONSE_RECV_FD = 2,
+        RESPONSE_SEND_FD = 3,
+        MESSAGE_FD_MAX = 4
+};
+
+struct sd_resolve {
+        int fds[MESSAGE_FD_MAX];
+
+        pthread_t workers[MAX_WORKERS];
+        unsigned valid_workers;
+
+        unsigned current_id, current_index;
+        sd_resolve_query* queries[MAX_QUERIES];
+
+        sd_resolve_query *done_head, *done_tail;
+
+        int n_queries;
+        int dead;
+};
+
+struct sd_resolve_query {
+        sd_resolve *resolve;
+        int done;
+        unsigned id;
+        QueryType type;
+        sd_resolve_query *done_next, *done_prev;
+        int ret;
+        int _errno;
+        int _h_errno;
+        struct addrinfo *addrinfo;
+        char *serv, *host;
+        void *userdata;
+};
+
+typedef struct RHeader {
+        QueryType type;
+        unsigned id;
+        size_t length;
+} RHeader;
+
+typedef struct AddrInfoRequest {
+        struct RHeader header;
+        int hints_is_null;
+        int ai_flags;
+        int ai_family;
+        int ai_socktype;
+        int ai_protocol;
+        size_t node_len, service_len;
+} AddrInfoRequest;
+
+typedef struct AddrInfoResponse {
+        struct RHeader header;
+        int ret;
+        int _errno;
+        int _h_errno;
+        /* followed by addrinfo_serialization[] */
+} AddrInfoResponse;
+
+typedef struct AddrInfoSerialization {
+        int ai_flags;
+        int ai_family;
+        int ai_socktype;
+        int ai_protocol;
+        size_t ai_addrlen;
+        size_t canonname_len;
+        /* Followed by ai_addr amd ai_canonname with variable lengths */
+} AddrInfoSerialization;
+
+typedef struct NameInfoRequest {
+        struct RHeader header;
+        int flags;
+        socklen_t sockaddr_len;
+        int gethost, getserv;
+} NameInfoRequest;
+
+typedef struct NameInfoResponse {
+        struct RHeader header;
+        size_t hostlen, servlen;
+        int ret;
+        int _errno;
+        int _h_errno;
+} NameInfoResponse;
+
+typedef struct ResRequest {
+        struct RHeader header;
+        int class;
+        int type;
+        size_t dname_len;
+} ResRequest;
+
+typedef struct ResResponse {
+        struct RHeader header;
+        int ret;
+        int _errno;
+        int _h_errno;
+} ResResponse;
+
+typedef union Packet {
+        RHeader rheader;
+        AddrInfoRequest addrinfo_request;
+        AddrInfoResponse addrinfo_response;
+        NameInfoRequest nameinfo_request;
+        NameInfoResponse nameinfo_response;
+        ResRequest res_request;
+        ResResponse res_response;
+} Packet;
+
+static int send_died(int out_fd) {
+        RHeader rh = {};
+        assert(out_fd > 0);
+
+        rh.type = RESPONSE_DIED;
+        rh.id = 0;
+        rh.length = sizeof(rh);
+
+        return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
+}
+
+static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
+        AddrInfoSerialization s;
+        size_t cnl, l;
+        assert(p);
+        assert(ai);
+        assert(length);
+        assert(*length <= maxlength);
+
+        cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
+        l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
+
+        if (*length + l > maxlength)
+                return NULL;
+
+        s.ai_flags = ai->ai_flags;
+        s.ai_family = ai->ai_family;
+        s.ai_socktype = ai->ai_socktype;
+        s.ai_protocol = ai->ai_protocol;
+        s.ai_addrlen = ai->ai_addrlen;
+        s.canonname_len = cnl;
+
+        memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
+        memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
+
+        if (ai->ai_canonname)
+                strcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname);
+
+        *length += l;
+        return (uint8_t*) p + l;
+}
+
+static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
+        AddrInfoResponse data[BUFSIZE/sizeof(AddrInfoResponse) + 1] = {};
+        AddrInfoResponse *resp = data;
+        assert(out_fd >= 0);
+
+        resp->header.type = RESPONSE_ADDRINFO;
+        resp->header.id = id;
+        resp->header.length = sizeof(AddrInfoResponse);
+        resp->ret = ret;
+        resp->_errno = _errno;
+        resp->_h_errno = _h_errno;
+
+        if (ret == 0 && ai) {
+                void *p = data + 1;
+                struct addrinfo *k;
+
+                for (k = ai; k; k = k->ai_next) {
+                        p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p);
+                        if (!p) {
+                                resp->ret = EAI_MEMORY;
+                                break;
+                        }
+                }
+        }
+
+        if (ai)
+                freeaddrinfo(ai);
+
+        return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
+}
+
+static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
+        NameInfoResponse data[BUFSIZE/sizeof(NameInfoResponse) + 1] = {};
+        size_t hl, sl;
+        NameInfoResponse *resp = data;
+
+        assert(out_fd >= 0);
+
+        sl = serv ? strlen(serv)+1 : 0;
+        hl = host ? strlen(host)+1 : 0;
+
+        resp->header.type = RESPONSE_NAMEINFO;
+        resp->header.id = id;
+        resp->header.length = sizeof(NameInfoResponse) + hl + sl;
+        resp->ret = ret;
+        resp->_errno = _errno;
+        resp->_h_errno = _h_errno;
+        resp->hostlen = hl;
+        resp->servlen = sl;
+
+        assert(sizeof(data) >= resp->header.length);
+
+        if (host)
+                memcpy((uint8_t *)data + sizeof(NameInfoResponse), host, hl);
+
+        if (serv)
+                memcpy((uint8_t *)data + sizeof(NameInfoResponse) + hl, serv, sl);
+
+        return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
+}
+
+static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
+        ResResponse data[BUFSIZE/sizeof(ResResponse) + 1] = {};
+        ResResponse *resp = data;
+
+        assert(out_fd >= 0);
+
+        resp->header.type = RESPONSE_RES;
+        resp->header.id = id;
+        resp->header.length = sizeof(ResResponse) + (ret < 0 ? 0 : ret);
+        resp->ret = ret;
+        resp->_errno = _errno;
+        resp->_h_errno = _h_errno;
+
+        assert(sizeof(data) >= resp->header.length);
+
+        if (ret > 0)
+                memcpy((uint8_t *)data + sizeof(ResResponse), answer, ret);
+
+        return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
+}
+
+static int handle_request(int out_fd, const Packet *packet, size_t length) {
+        const RHeader *req;
+        assert(out_fd >= 0);
+
+        req = &packet->rheader;
+        assert(req);
+        assert(length >= sizeof(RHeader));
+        assert(length == req->length);
+
+        switch (req->type) {
+        case REQUEST_ADDRINFO: {
+               struct addrinfo ai = {}, *result = NULL;
+               const AddrInfoRequest *ai_req = &packet->addrinfo_request;
+               const char *node, *service;
+               int ret;
+
+               assert(length >= sizeof(AddrInfoRequest));
+               assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len);
+
+               ai.ai_flags = ai_req->ai_flags;
+               ai.ai_family = ai_req->ai_family;
+               ai.ai_socktype = ai_req->ai_socktype;
+               ai.ai_protocol = ai_req->ai_protocol;
+
+               node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
+               service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
+
+               ret = getaddrinfo(node, service,
+                               ai_req->hints_is_null ? NULL : &ai,
+                               &result);
+
+               /* send_addrinfo_reply() frees result */
+               return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
+        }
+
+        case REQUEST_NAMEINFO: {
+               int ret;
+               const NameInfoRequest *ni_req = &packet->nameinfo_request;
+               char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
+               struct sockaddr_storage sa;
+
+               assert(length >= sizeof(NameInfoRequest));
+               assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len);
+
+               memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
+
+               ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
+                               ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
+                               ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
+                               ni_req->flags);
+
+               return send_nameinfo_reply(out_fd, req->id, ret,
+                               ret == 0 && ni_req->gethost ? hostbuf : NULL,
+                               ret == 0 && ni_req->getserv ? servbuf : NULL,
+                               errno, h_errno);
+        }
+
+        case REQUEST_RES_QUERY:
+        case REQUEST_RES_SEARCH: {
+                 int ret;
+                 HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
+                 const ResRequest *res_req = &packet->res_request;
+                 const char *dname;
+
+                 assert(length >= sizeof(ResRequest));
+                 assert(length == sizeof(ResRequest) + res_req->dname_len);
+
+                 dname = (const char *) req + sizeof(ResRequest);
+
+                 if (req->type == REQUEST_RES_QUERY)
+                         ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
+                 else
+                         ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
+
+                 return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
+        }
+
+        case REQUEST_TERMINATE:
+                 /* Quit */
+                 return -1;
+
+        default:
+                 ;
+        }
+
+        return 0;
+}
+
+static void* thread_worker(void *p) {
+        sd_resolve *resolve = p;
+        sigset_t fullset;
+
+        /* No signals in this thread please */
+        sigfillset(&fullset);
+        pthread_sigmask(SIG_BLOCK, &fullset, NULL);
+
+        while (!resolve->dead) {
+                Packet buf[BUFSIZE/sizeof(Packet) + 1];
+                ssize_t length;
+
+                length = recv(resolve->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0);
+
+                if (length <= 0) {
+                        if (length < 0 && (errno == EAGAIN || errno == EINTR))
+                                continue;
+                        break;
+                }
+
+                if (resolve->dead)
+                        break;
+
+                if (handle_request(resolve->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
+                        break;
+        }
+
+        send_died(resolve->fds[RESPONSE_SEND_FD]);
+
+        return NULL;
+}
+
+_public_ sd_resolve* sd_resolve_new(unsigned n_proc) {
+        sd_resolve *resolve = NULL;
+        int i, r;
+
+        assert(n_proc >= 1);
+
+        if (n_proc > MAX_WORKERS)
+                n_proc = MAX_WORKERS;
+
+        resolve = new(sd_resolve, 1);
+        if (!resolve) {
+                errno = ENOMEM;
+                goto fail;
+        }
+
+        resolve->dead = 0;
+        resolve->valid_workers = 0;
+
+        for (i = 0; i < MESSAGE_FD_MAX; i++)
+                resolve->fds[i] = -1;
+
+        memset(resolve->queries, 0, sizeof(resolve->queries));
+
+        r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds);
+        if (r < 0)
+                goto fail;
+
+        r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds+2);
+        if (r < 0)
+                goto fail;
+
+        for (resolve->valid_workers = 0; resolve->valid_workers < n_proc; resolve->valid_workers++) {
+                r = pthread_create(&resolve->workers[resolve->valid_workers], NULL, thread_worker, resolve);
+                if (r) {
+                        errno = r;
+                        goto fail;
+                }
+        }
+
+        resolve->current_index = resolve->current_id = 0;
+        resolve->done_head = resolve->done_tail = NULL;
+        resolve->n_queries = 0;
+
+        fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
+
+        return resolve;
+
+fail:
+        if (resolve)
+                sd_resolve_free(resolve);
+
+        return NULL;
+}
+
+_public_ void sd_resolve_free(sd_resolve *resolve) {
+        int i;
+        int saved_errno = errno;
+        unsigned p;
+
+        assert(resolve);
+
+        resolve->dead = 1;
+
+        if (resolve->fds[REQUEST_SEND_FD] >= 0) {
+                RHeader req = {};
+
+                req.type = REQUEST_TERMINATE;
+                req.length = sizeof(req);
+                req.id = 0;
+
+                /* Send one termination packet for each worker */
+                for (p = 0; p < resolve->valid_workers; p++)
+                        send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
+        }
+
+        /* Now terminate them and wait until they are gone. */
+        for (p = 0; p < resolve->valid_workers; p++) {
+                for (;;) {
+                        if (pthread_join(resolve->workers[p], NULL) != EINTR)
+                                break;
+                }
+        }
+
+        /* Close all communication channels */
+        for (i = 0; i < MESSAGE_FD_MAX; i++)
+                if (resolve->fds[i] >= 0)
+                        close(resolve->fds[i]);
+
+        for (p = 0; p < MAX_QUERIES; p++)
+                if (resolve->queries[p])
+                        sd_resolve_cancel(resolve, resolve->queries[p]);
+
+        free(resolve);
+
+        errno = saved_errno;
+}
+
+_public_ int sd_resolve_fd(sd_resolve *resolve) {
+        assert(resolve);
+
+        return resolve->fds[RESPONSE_RECV_FD];
+}
+
+static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
+        sd_resolve_query *q;
+        assert(resolve);
+
+        q = resolve->queries[id % MAX_QUERIES];
+        if (q)
+                if (q->id == id)
+                        return q;
+
+        return NULL;
+}
+
+static void complete_query(sd_resolve *resolve, sd_resolve_query *q) {
+        assert(resolve);
+        assert(q);
+        assert(!q->done);
+
+        q->done = 1;
+
+        if ((q->done_prev = resolve->done_tail))
+                resolve->done_tail->done_next = q;
+        else
+                resolve->done_head = q;
+
+        resolve->done_tail = q;
+        q->done_next = NULL;
+}
+
+static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
+        AddrInfoSerialization s;
+        size_t l;
+        struct addrinfo *ai;
+        assert(p);
+        assert(ret_ai);
+        assert(length);
+
+        if (*length < sizeof(AddrInfoSerialization))
+                return NULL;
+
+        memcpy(&s, p, sizeof(s));
+
+        l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
+        if (*length < l)
+                return NULL;
+
+        ai = new(struct addrinfo, 1);
+        if (!ai)
+                goto fail;
+
+        ai->ai_addr = NULL;
+        ai->ai_canonname = NULL;
+        ai->ai_next = NULL;
+
+        if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
+                goto fail;
+
+        if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
+                goto fail;
+
+        ai->ai_flags = s.ai_flags;
+        ai->ai_family = s.ai_family;
+        ai->ai_socktype = s.ai_socktype;
+        ai->ai_protocol = s.ai_protocol;
+        ai->ai_addrlen = s.ai_addrlen;
+
+        if (ai->ai_addr)
+                memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(AddrInfoSerialization), s.ai_addrlen);
+
+        if (ai->ai_canonname)
+                memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
+
+        *length -= l;
+        *ret_ai = ai;
+
+        return (const uint8_t*) p + l;
+
+
+fail:
+        if (ai)
+                sd_resolve_freeaddrinfo(ai);
+
+        return NULL;
+}
+
+static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
+        const RHeader *resp;
+        sd_resolve_query *q;
+
+        assert(resolve);
+
+        resp = &packet->rheader;
+        assert(resp);
+        assert(length >= sizeof(RHeader));
+        assert(length == resp->length);
+
+        if (resp->type == RESPONSE_DIED) {
+                resolve->dead = 1;
+                return 0;
+        }
+
+        q = lookup_query(resolve, resp->id);
+        if (!q)
+                return 0;
+
+        switch (resp->type) {
+        case RESPONSE_ADDRINFO: {
+                const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
+                const void *p;
+                size_t l;
+                struct addrinfo *prev = NULL;
+
+                assert(length >= sizeof(AddrInfoResponse));
+                assert(q->type == REQUEST_ADDRINFO);
+
+                q->ret = ai_resp->ret;
+                q->_errno = ai_resp->_errno;
+                q->_h_errno = ai_resp->_h_errno;
+                l = length - sizeof(AddrInfoResponse);
+                p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
+
+                while (l > 0 && p) {
+                        struct addrinfo *ai = NULL;
+                        p = unserialize_addrinfo(p, &ai, &l);
+
+                        if (!p || !ai) {
+                                q->ret = EAI_MEMORY;
+                                break;
+                        }
+
+                        if (prev)
+                                prev->ai_next = ai;
+                        else
+                                q->addrinfo = ai;
+
+                        prev = ai;
+                }
+
+                complete_query(resolve, q);
+                break;
+        }
+
+        case RESPONSE_NAMEINFO: {
+                const NameInfoResponse *ni_resp = &packet->nameinfo_response;
+
+                assert(length >= sizeof(NameInfoResponse));
+                assert(q->type == REQUEST_NAMEINFO);
+
+                q->ret = ni_resp->ret;
+                q->_errno = ni_resp->_errno;
+                q->_h_errno = ni_resp->_h_errno;
+
+                if (ni_resp->hostlen)
+                        if (!(q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1)))
+                                q->ret = EAI_MEMORY;
+
+                if (ni_resp->servlen)
+                        if (!(q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1)))
+                                q->ret = EAI_MEMORY;
+
+                complete_query(resolve, q);
+                break;
+        }
+
+        case RESPONSE_RES: {
+                const ResResponse *res_resp = &packet->res_response;
+
+                assert(length >= sizeof(ResResponse));
+                assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
+
+                q->ret = res_resp->ret;
+                q->_errno = res_resp->_errno;
+                q->_h_errno = res_resp->_h_errno;
+
+                if (res_resp->ret >= 0)  {
+                        if (!(q->serv = malloc(res_resp->ret))) {
+                                q->ret = -1;
+                                q->_errno = ENOMEM;
+                        } else
+                                memcpy(q->serv, (const char *)resp + sizeof(ResResponse), res_resp->ret);
+                }
+
+                complete_query(resolve, q);
+                break;
+        }
+
+        default:
+                ;
+        }
+
+        return 0;
+}
+
+_public_ int sd_resolve_wait(sd_resolve *resolve, int block) {
+        int handled = 0;
+        assert(resolve);
+
+        for (;;) {
+                Packet buf[BUFSIZE/sizeof(Packet) + 1];
+                ssize_t l;
+
+                if (resolve->dead) {
+                        errno = ECHILD;
+                        return -1;
+                }
+
+                l = recv(resolve->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0);
+                if (l < 0) {
+                        fd_set fds;
+
+                        if (errno != EAGAIN)
+                                return -1;
+
+                        if (!block || handled)
+                                return 0;
+
+                        FD_ZERO(&fds);
+                        FD_SET(resolve->fds[RESPONSE_RECV_FD], &fds);
+
+                        if (select(resolve->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
+                                return -1;
+
+                        continue;
+                }
+
+                if (handle_response(resolve, buf, (size_t) l) < 0)
+                        return -1;
+
+                handled = 1;
+        }
+}
+
+static sd_resolve_query *alloc_query(sd_resolve *resolve) {
+        sd_resolve_query *q;
+        assert(resolve);
+
+        if (resolve->n_queries >= MAX_QUERIES) {
+                errno = ENOMEM;
+                return NULL;
+        }
+
+        while (resolve->queries[resolve->current_index]) {
+                resolve->current_index++;
+                resolve->current_id++;
+
+                while (resolve->current_index >= MAX_QUERIES)
+                        resolve->current_index -= MAX_QUERIES;
+        }
+
+        q = resolve->queries[resolve->current_index] = new(sd_resolve_query, 1);
+        if (!q) {
+                errno = ENOMEM;
+                return NULL;
+        }
+
+        resolve->n_queries++;
+
+        q->resolve = resolve;
+        q->done = 0;
+        q->id = resolve->current_id;
+        q->done_next = q->done_prev = NULL;
+        q->ret = 0;
+        q->_errno = 0;
+        q->_h_errno = 0;
+        q->addrinfo = NULL;
+        q->userdata = NULL;
+        q->host = q->serv = NULL;
+
+        return q;
+}
+
+_public_ sd_resolve_query* sd_resolve_getaddrinfo(sd_resolve *resolve, const char *node, const char *service, const struct addrinfo *hints) {
+        AddrInfoRequest data[BUFSIZE/sizeof(AddrInfoRequest) + 1] = {};
+        AddrInfoRequest *req = data;
+        sd_resolve_query *q;
+        assert(resolve);
+        assert(node || service);
+
+        if (resolve->dead) {
+                errno = ECHILD;
+                return NULL;
+        }
+
+        q = alloc_query(resolve);
+        if (!q)
+                return NULL;
+
+        req->node_len = node ? strlen(node)+1 : 0;
+        req->service_len = service ? strlen(service)+1 : 0;
+
+        req->header.id = q->id;
+        req->header.type = q->type = REQUEST_ADDRINFO;
+        req->header.length = sizeof(AddrInfoRequest) + req->node_len + req->service_len;
+
+        if (req->header.length > BUFSIZE) {
+                errno = ENOMEM;
+                goto fail;
+        }
+
+        if (!(req->hints_is_null = !hints)) {
+                req->ai_flags = hints->ai_flags;
+                req->ai_family = hints->ai_family;
+                req->ai_socktype = hints->ai_socktype;
+                req->ai_protocol = hints->ai_protocol;
+        }
+
+        if (node)
+                strcpy((char*) req + sizeof(AddrInfoRequest), node);
+
+        if (service)
+                strcpy((char*) req + sizeof(AddrInfoRequest) + req->node_len, service);
+
+        if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
+                goto fail;
+
+        return q;
+
+fail:
+        if (q)
+                sd_resolve_cancel(resolve, q);
+
+        return NULL;
+}
+
+_public_ int sd_resolve_getaddrinfo_done(sd_resolve *resolve, sd_resolve_query* q, struct addrinfo **ret_res) {
+        int ret;
+        assert(resolve);
+        assert(q);
+        assert(q->resolve == resolve);
+        assert(q->type == REQUEST_ADDRINFO);
+
+        if (resolve->dead) {
+                errno = ECHILD;
+                return EAI_SYSTEM;
+        }
+
+        if (!q->done)
+                return EAI_AGAIN;
+
+        *ret_res = q->addrinfo;
+        q->addrinfo = NULL;
+
+        ret = q->ret;
+
+        if (ret == EAI_SYSTEM)
+                errno = q->_errno;
+
+        if (ret != 0)
+                h_errno = q->_h_errno;
+
+        sd_resolve_cancel(resolve, q);
+
+        return ret;
+}
+
+_public_ sd_resolve_query* sd_resolve_getnameinfo(sd_resolve *resolve, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
+        NameInfoRequest data[BUFSIZE/sizeof(NameInfoRequest) + 1] = {};
+        NameInfoRequest *req = data;
+        sd_resolve_query *q;
+
+        assert(resolve);
+        assert(sa);
+        assert(salen > 0);
+
+        if (resolve->dead) {
+                errno = ECHILD;
+                return NULL;
+        }
+
+        q = alloc_query(resolve);
+        if (!q)
+                return NULL;
+
+        req->header.id = q->id;
+        req->header.type = q->type = REQUEST_NAMEINFO;
+        req->header.length = sizeof(NameInfoRequest) + salen;
+
+        if (req->header.length > BUFSIZE) {
+                errno = ENOMEM;
+                goto fail;
+        }
+
+        req->flags = flags;
+        req->sockaddr_len = salen;
+        req->gethost = gethost;
+        req->getserv = getserv;
+
+        memcpy((uint8_t*) req + sizeof(NameInfoRequest), sa, salen);
+
+        if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
+                goto fail;
+
+        return q;
+
+fail:
+        if (q)
+                sd_resolve_cancel(resolve, q);
+
+        return NULL;
+}
+
+_public_ int sd_resolve_getnameinfo_done(sd_resolve *resolve, sd_resolve_query* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
+        int ret;
+        assert(resolve);
+        assert(q);
+        assert(q->resolve == resolve);
+        assert(q->type == REQUEST_NAMEINFO);
+        assert(!ret_host || hostlen);
+        assert(!ret_serv || servlen);
+
+        if (resolve->dead) {
+                errno = ECHILD;
+                return EAI_SYSTEM;
+        }
+
+        if (!q->done)
+                return EAI_AGAIN;
+
+        if (ret_host && q->host) {
+                strncpy(ret_host, q->host, hostlen);
+                ret_host[hostlen-1] = 0;
+        }
+
+        if (ret_serv && q->serv) {
+                strncpy(ret_serv, q->serv, servlen);
+                ret_serv[servlen-1] = 0;
+        }
+
+        ret = q->ret;
+
+        if (ret == EAI_SYSTEM)
+                errno = q->_errno;
+
+        if (ret != 0)
+                h_errno = q->_h_errno;
+
+        sd_resolve_cancel(resolve, q);
+
+        return ret;
+}
+
+static sd_resolve_query * resolve_res(sd_resolve *resolve, QueryType qtype, const char *dname, int class, int type) {
+        ResRequest data[BUFSIZE/sizeof(ResRequest) + 1];
+        ResRequest *req = data;
+        sd_resolve_query *q;
+
+        assert(resolve);
+        assert(dname);
+
+        if (resolve->dead) {
+                errno = ECHILD;
+                return NULL;
+        }
+
+        q = alloc_query(resolve);
+        if (!q)
+                return NULL;
+
+        req->dname_len = strlen(dname) + 1;
+
+        req->header.id = q->id;
+        req->header.type = q->type = qtype;
+        req->header.length = sizeof(ResRequest) + req->dname_len;
+
+        if (req->header.length > BUFSIZE) {
+                errno = ENOMEM;
+                goto fail;
+        }
+
+        req->class = class;
+        req->type = type;
+
+        strcpy((char*) req + sizeof(ResRequest), dname);
+
+        if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
+                goto fail;
+
+        return q;
+
+fail:
+        if (q)
+                sd_resolve_cancel(resolve, q);
+
+        return NULL;
+}
+
+_public_ sd_resolve_query* sd_resolve_res_query(sd_resolve *resolve, const char *dname, int class, int type) {
+        return resolve_res(resolve, REQUEST_RES_QUERY, dname, class, type);
+}
+
+_public_ sd_resolve_query* sd_resolve_res_search(sd_resolve *resolve, const char *dname, int class, int type) {
+        return resolve_res(resolve, REQUEST_RES_SEARCH, dname, class, type);
+}
+
+_public_ int sd_resolve_res_done(sd_resolve *resolve, sd_resolve_query* q, unsigned char **answer) {
+        int ret;
+        assert(resolve);
+        assert(q);
+        assert(q->resolve == resolve);
+        assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
+        assert(answer);
+
+        if (resolve->dead) {
+                errno = ECHILD;
+                return -ECHILD;
+        }
+
+        if (!q->done) {
+                errno = EAGAIN;
+                return -EAGAIN;
+        }
+
+        *answer = (unsigned char *)q->serv;
+        q->serv = NULL;
+
+        ret = q->ret;
+
+        if (ret < 0) {
+                errno = q->_errno;
+                h_errno = q->_h_errno;
+        }
+
+        sd_resolve_cancel(resolve, q);
+
+        return ret < 0 ? -errno : ret;
+}
+
+_public_ sd_resolve_query* sd_resolve_get_next(sd_resolve *resolve) {
+        assert(resolve);
+        return resolve->done_head;
+}
+
+_public_ int sd_resolve_get_n_queries(sd_resolve *resolve) {
+        assert(resolve);
+        return resolve->n_queries;
+}
+
+_public_ void sd_resolve_cancel(sd_resolve *resolve, sd_resolve_query* q) {
+        int i;
+        int saved_errno = errno;
+
+        assert(resolve);
+        assert(q);
+        assert(q->resolve == resolve);
+        assert(resolve->n_queries > 0);
+
+        if (q->done) {
+
+                if (q->done_prev)
+                        q->done_prev->done_next = q->done_next;
+                else
+                        resolve->done_head = q->done_next;
+
+                if (q->done_next)
+                        q->done_next->done_prev = q->done_prev;
+                else
+                        resolve->done_tail = q->done_prev;
+        }
+
+        i = q->id % MAX_QUERIES;
+        assert(resolve->queries[i] == q);
+        resolve->queries[i] = NULL;
+
+        sd_resolve_freeaddrinfo(q->addrinfo);
+        free(q->host);
+        free(q->serv);
+
+        resolve->n_queries--;
+        free(q);
+
+        errno = saved_errno;
+}
+
+_public_ void sd_resolve_freeaddrinfo(struct addrinfo *ai) {
+        int saved_errno = errno;
+
+        while (ai) {
+                struct addrinfo *next = ai->ai_next;
+
+                free(ai->ai_addr);
+                free(ai->ai_canonname);
+                free(ai);
+
+                ai = next;
+        }
+
+        errno = saved_errno;
+}
+
+_public_ int sd_resolve_isdone(sd_resolve *resolve, sd_resolve_query*q) {
+        assert(resolve);
+        assert(q);
+        assert(q->resolve == resolve);
+
+        return q->done;
+}
+
+_public_ void sd_resolve_setuserdata(sd_resolve *resolve, sd_resolve_query *q, void *userdata) {
+        assert(q);
+        assert(resolve);
+        assert(q->resolve = resolve);
+
+        q->userdata = userdata;
+}
+
+_public_ void* sd_resolve_getuserdata(sd_resolve *resolve, sd_resolve_query *q) {
+        assert(q);
+        assert(resolve);
+        assert(q->resolve = resolve);
+
+        return q->userdata;
+}
diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c
new file mode 100644
index 0000000..3903e64
--- /dev/null
+++ b/src/libsystemd/sd-resolve/test-resolve.c
@@ -0,0 +1,160 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2005-2008 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 <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "sd-resolve.h"
+#include "resolve-util.h"
+#include "macro.h"
+
+int main(int argc, char *argv[]) {
+        int r = 1, ret;
+        _cleanup_resolve_free_ sd_resolve *resolve = NULL;
+        _cleanup_resolve_addrinfo_free_ struct addrinfo *ai = NULL;
+        _cleanup_free_ unsigned char *srv = NULL;
+        sd_resolve_query *q1, *q2, *q3;
+        struct addrinfo hints = {};
+        struct sockaddr_in sa = {};
+        char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
+
+        signal(SIGCHLD, SIG_IGN);
+
+        resolve = sd_resolve_new(2);
+        if (!resolve)
+                log_oom();
+
+        /* Make a name -> address query */
+        hints.ai_family = PF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+
+        q1 = sd_resolve_getaddrinfo(resolve, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints);
+        if (!q1)
+                fprintf(stderr, "sd_resolve_getaddrinfo(): %s\n", strerror(errno));
+
+        /* Make an address -> name query */
+        sa.sin_family = AF_INET;
+        sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
+        sa.sin_port = htons(80);
+
+        q2 = sd_resolve_getnameinfo(resolve, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1);
+        if (!q2)
+                fprintf(stderr, "sd_resolve_getnameinfo(): %s\n", strerror(errno));
+
+        /* Make a res_query() call */
+        q3 = sd_resolve_res_query(resolve, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV);
+        if (!q3)
+                fprintf(stderr, "sd_resolve_res_query(): %s\n", strerror(errno));
+
+        /* Wait until the three queries are completed */
+        while (!sd_resolve_isdone(resolve, q1) ||
+               !sd_resolve_isdone(resolve, q2) ||
+               !sd_resolve_isdone(resolve, q3)) {
+                if (sd_resolve_wait(resolve, 1) < 0)
+                        fprintf(stderr, "sd_resolve_wait(): %s\n", strerror(errno));
+        }
+
+        /* Interpret the result of the name -> addr query */
+        ret = sd_resolve_getaddrinfo_done(resolve, q1, &ai);
+        if (ret)
+                fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
+        else {
+                struct addrinfo *i;
+
+                for (i = ai; i; i = i->ai_next) {
+                        char t[256];
+                        const char *p = NULL;
+
+                        if (i->ai_family == PF_INET)
+                                p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
+                        else if (i->ai_family == PF_INET6)
+                                p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));
+
+                        printf("%s\n", p);
+                }
+        }
+
+        /* Interpret the result of the addr -> name query */
+        ret = sd_resolve_getnameinfo_done(resolve, q2, host, sizeof(host), serv, sizeof(serv));
+        if (ret)
+                fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
+        else
+                printf("%s -- %s\n", host, serv);
+
+        /* Interpret the result of the SRV lookup */
+        ret = sd_resolve_res_done(resolve, q3, &srv);
+        if (ret < 0) {
+                fprintf(stderr, "error: %s %i\n", strerror(errno), ret);
+        } else if (ret == 0) {
+                fprintf(stderr, "No reply for SRV lookup\n");
+        } else {
+                int qdcount;
+                int ancount;
+                int len;
+                const unsigned char *pos = srv + sizeof(HEADER);
+                unsigned char *end = srv + ret;
+                HEADER *head = (HEADER *)srv;
+                char name[256];
+
+                qdcount = ntohs(head->qdcount);
+                ancount = ntohs(head->ancount);
+
+                printf("%d answers for srv lookup:\n", ancount);
+
+                /* Ignore the questions */
+                while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
+                        assert(len >= 0);
+                        pos += len + QFIXEDSZ;
+                }
+
+                /* Parse the answers */
+                while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
+                        /* Ignore the initial string */
+                        uint16_t pref, weight, port;
+                        assert(len >= 0);
+                        pos += len;
+                        /* Ignore type, ttl, class and dlen */
+                        pos += 10;
+
+                        GETSHORT(pref, pos);
+                        GETSHORT(weight, pos);
+                        GETSHORT(port, pos);
+                        len = dn_expand(srv, end, pos, name, 255);
+                        printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
+                                        pref, weight, port, name);
+
+                        pos += len;
+                }
+        }
+
+        r = 0;
+
+        return r;
+}
diff --git a/src/libsystemd/sd-rtnl.c b/src/libsystemd/sd-rtnl.c
deleted file mode 100644
index 08b82ab..0000000
--- a/src/libsystemd/sd-rtnl.c
+++ /dev/null
@@ -1,870 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  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 <sys/socket.h>
-#include <poll.h>
-
-#include "macro.h"
-#include "util.h"
-#include "hashmap.h"
-
-#include "sd-rtnl.h"
-#include "rtnl-internal.h"
-#include "rtnl-util.h"
-
-static int sd_rtnl_new(sd_rtnl **ret) {
-        sd_rtnl *rtnl;
-
-        assert_return(ret, -EINVAL);
-
-        rtnl = new0(sd_rtnl, 1);
-        if (!rtnl)
-                return -ENOMEM;
-
-        rtnl->n_ref = REFCNT_INIT;
-
-        rtnl->fd = -1;
-
-        rtnl->sockaddr.nl.nl_family = AF_NETLINK;
-
-        rtnl->original_pid = getpid();
-
-        LIST_HEAD_INIT(rtnl->match_callbacks);
-
-        /* We guarantee that wqueue always has space for at least
-         * one entry */
-        rtnl->wqueue = new(sd_rtnl_message*, 1);
-        if (!rtnl->wqueue) {
-                free(rtnl);
-                return -ENOMEM;
-        }
-
-        *ret = rtnl;
-        return 0;
-}
-
-static bool rtnl_pid_changed(sd_rtnl *rtnl) {
-        assert(rtnl);
-
-        /* We don't support people creating an rtnl connection and
-         * keeping it around over a fork(). Let's complain. */
-
-        return rtnl->original_pid != getpid();
-}
-
-int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) {
-        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        socklen_t addrlen;
-        int r;
-
-        assert_return(ret, -EINVAL);
-
-        r = sd_rtnl_new(&rtnl);
-        if (r < 0)
-                return r;
-
-        rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
-        if (rtnl->fd < 0)
-                return -errno;
-
-        rtnl->sockaddr.nl.nl_groups = groups;
-
-        addrlen = sizeof(rtnl->sockaddr);
-
-        r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
-        if (r < 0)
-                return -errno;
-
-        r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
-        if (r < 0)
-                return r;
-
-        *ret = rtnl;
-        rtnl = NULL;
-
-        return 0;
-}
-
-sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
-        if (rtnl)
-                assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
-
-        return rtnl;
-}
-
-sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
-
-        if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) {
-                struct match_callback *f;
-                unsigned i;
-
-                for (i = 0; i < rtnl->rqueue_size; i++)
-                        sd_rtnl_message_unref(rtnl->rqueue[i]);
-                free(rtnl->rqueue);
-
-                for (i = 0; i < rtnl->wqueue_size; i++)
-                        sd_rtnl_message_unref(rtnl->wqueue[i]);
-                free(rtnl->wqueue);
-
-                hashmap_free_free(rtnl->reply_callbacks);
-                prioq_free(rtnl->reply_callbacks_prioq);
-
-                while ((f = rtnl->match_callbacks)) {
-                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
-                        free(f);
-                }
-
-                if (rtnl->fd >= 0)
-                        close_nointr_nofail(rtnl->fd);
-
-                free(rtnl);
-        }
-
-        return NULL;
-}
-
-int sd_rtnl_send(sd_rtnl *nl,
-                 sd_rtnl_message *message,
-                 uint32_t *serial) {
-        int r;
-
-        assert_return(nl, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-        assert_return(message, -EINVAL);
-
-        r = message_seal(nl, message);
-        if (r < 0)
-                return r;
-
-        if (nl->wqueue_size <= 0) {
-                /* send directly */
-                r = socket_write_message(nl, message);
-                if (r < 0)
-                        return r;
-                else if (r == 0) {
-                        /* nothing was sent, so let's put it on
-                         * the queue */
-                        nl->wqueue[0] = sd_rtnl_message_ref(message);
-                        nl->wqueue_size = 1;
-                }
-        } else {
-                sd_rtnl_message **q;
-
-                /* append to queue */
-                if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
-                        return -ENOBUFS;
-
-                q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
-                if (!q)
-                        return -ENOMEM;
-
-                nl->wqueue = q;
-                q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
-        }
-
-        if (serial)
-                *serial = message_get_serial(message);
-
-        return 1;
-}
-
-static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
-        sd_rtnl_message *z = NULL;
-        int r;
-
-        assert(rtnl);
-        assert(message);
-
-        if (rtnl->rqueue_size > 0) {
-                /* Dispatch a queued message */
-
-                *message = rtnl->rqueue[0];
-                rtnl->rqueue_size --;
-                memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
-
-                return 1;
-        }
-
-        /* Try to read a new message */
-        r = socket_read_message(rtnl, &z);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return 0;
-
-        *message = z;
-
-        return 1;
-}
-
-static int dispatch_wqueue(sd_rtnl *rtnl) {
-        int r, ret = 0;
-
-        assert(rtnl);
-
-        while (rtnl->wqueue_size > 0) {
-                r = socket_write_message(rtnl, rtnl->wqueue[0]);
-                if (r < 0)
-                        return r;
-                else if (r == 0)
-                        /* Didn't do anything this time */
-                        return ret;
-                else {
-                        /* see equivalent in sd-bus.c */
-                        sd_rtnl_message_unref(rtnl->wqueue[0]);
-                        rtnl->wqueue_size --;
-                        memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
-
-                        ret = 1;
-                }
-        }
-
-        return ret;
-}
-
-static int process_timeout(sd_rtnl *rtnl) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        struct reply_callback *c;
-        usec_t n;
-        int r;
-
-        assert(rtnl);
-
-        c = prioq_peek(rtnl->reply_callbacks_prioq);
-        if (!c)
-                return 0;
-
-        n = now(CLOCK_MONOTONIC);
-        if (c->timeout > n)
-                return 0;
-
-        r = message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
-        if (r < 0)
-                return r;
-
-        assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
-        hashmap_remove(rtnl->reply_callbacks, &c->serial);
-
-        r = c->callback(rtnl, m, c->userdata);
-        free(c);
-
-        return r < 0 ? r : 1;
-}
-
-static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
-        struct reply_callback *c;
-        uint64_t serial;
-        int r;
-
-        assert(rtnl);
-        assert(m);
-
-        serial = message_get_serial(m);
-        c = hashmap_remove(rtnl->reply_callbacks, &serial);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
-
-        r = c->callback(rtnl, m, c->userdata);
-        free(c);
-
-        return r;
-}
-
-static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
-        struct match_callback *c;
-        uint16_t type;
-        int r;
-
-        assert(rtnl);
-        assert(m);
-
-        r = sd_rtnl_message_get_type(m, &type);
-        if (r < 0)
-                return r;
-
-        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
-                if (type == c->type) {
-                        r = c->callback(rtnl, m, c->userdata);
-                        if (r != 0)
-                                return r;
-                }
-        }
-
-        return 0;
-}
-
-static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        int r;
-
-        assert(rtnl);
-
-        r = process_timeout(rtnl);
-        if (r != 0)
-                goto null_message;
-
-        r = dispatch_wqueue(rtnl);
-        if (r != 0)
-                goto null_message;
-
-        r = dispatch_rqueue(rtnl, &m);
-        if (r < 0)
-                return r;
-        if (!m)
-                goto null_message;
-
-        r = process_reply(rtnl, m);
-        if (r != 0)
-                goto null_message;
-
-        r = process_match(rtnl, m);
-        if (r != 0)
-                goto null_message;
-
-        if (ret) {
-                *ret = m;
-                m = NULL;
-
-                return 1;
-        }
-
-        return 1;
-
-null_message:
-        if (r >= 0 && ret)
-                *ret = NULL;
-
-        return r;
-}
-
-int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
-        RTNL_DONT_DESTROY(rtnl);
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-        assert_return(!rtnl->processing, -EBUSY);
-
-        rtnl->processing = true;
-        r = process_running(rtnl, ret);
-        rtnl->processing = false;
-
-        return r;
-}
-
-static usec_t calc_elapse(uint64_t usec) {
-        if (usec == (uint64_t) -1)
-                return 0;
-
-        if (usec == 0)
-                usec = RTNL_DEFAULT_TIMEOUT;
-
-        return now(CLOCK_MONOTONIC) + usec;
-}
-
-static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
-        struct pollfd p[1] = {};
-        struct timespec ts;
-        usec_t m = (usec_t) -1;
-        int r, e;
-
-        assert(rtnl);
-
-        e = sd_rtnl_get_events(rtnl);
-        if (e < 0)
-                return e;
-
-        if (need_more)
-                /* Caller wants more data, and doesn't care about
-                 * what's been read or any other timeouts. */
-                return e |= POLLIN;
-        else {
-                usec_t until;
-                /* Caller wants to process if there is something to
-                 * process, but doesn't care otherwise */
-
-                r = sd_rtnl_get_timeout(rtnl, &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))
-                m = timeout_usec;
-
-        p[0].fd = rtnl->fd;
-        p[0].events = e;
-
-        r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
-        if (r < 0)
-                return -errno;
-
-        return r > 0 ? 1 : 0;
-}
-
-int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
-        assert_return(nl, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
-        if (nl->rqueue_size > 0)
-                return 0;
-
-        return rtnl_poll(nl, false, timeout_usec);
-}
-
-static int timeout_compare(const void *a, const void *b) {
-        const struct reply_callback *x = a, *y = b;
-
-        if (x->timeout != 0 && y->timeout == 0)
-                return -1;
-
-        if (x->timeout == 0 && y->timeout != 0)
-                return 1;
-
-        if (x->timeout < y->timeout)
-                return -1;
-
-        if (x->timeout > y->timeout)
-                return 1;
-
-        return 0;
-}
-
-int sd_rtnl_call_async(sd_rtnl *nl,
-                       sd_rtnl_message *m,
-                       sd_rtnl_message_handler_t callback,
-                       void *userdata,
-                       uint64_t usec,
-                       uint32_t *serial) {
-        struct reply_callback *c;
-        uint32_t s;
-        int r, k;
-
-        assert_return(nl, -EINVAL);
-        assert_return(m, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
-        r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
-        if (r < 0)
-                return r;
-
-        if (usec != (uint64_t) -1) {
-                r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
-                if (r < 0)
-                        return r;
-        }
-
-        c = new0(struct reply_callback, 1);
-        if (!c)
-                return -ENOMEM;
-
-        c->callback = callback;
-        c->userdata = userdata;
-        c->timeout = calc_elapse(usec);
-
-        k = sd_rtnl_send(nl, m, &s);
-        if (k < 0) {
-                free(c);
-                return k;
-        }
-
-        c->serial = s;
-
-        r = hashmap_put(nl->reply_callbacks, &c->serial, c);
-        if (r < 0) {
-                free(c);
-                return r;
-        }
-
-        if (c->timeout != 0) {
-                r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
-                if (r > 0) {
-                        c->timeout = 0;
-                        sd_rtnl_call_async_cancel(nl, c->serial);
-                        return r;
-                }
-        }
-
-        if (serial)
-                *serial = s;
-
-        return k;
-}
-
-int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
-        struct reply_callback *c;
-        uint64_t s = serial;
-
-        assert_return(nl, -EINVAL);
-        assert_return(serial != 0, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
-        c = hashmap_remove(nl->reply_callbacks, &s);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
-
-        free(c);
-        return 1;
-}
-
-int sd_rtnl_call(sd_rtnl *nl,
-                sd_rtnl_message *message,
-                uint64_t usec,
-                sd_rtnl_message **ret) {
-        usec_t timeout;
-        uint32_t serial;
-        bool room = false;
-        int r;
-
-        assert_return(nl, -EINVAL);
-        assert_return(!rtnl_pid_changed(nl), -ECHILD);
-        assert_return(message, -EINVAL);
-
-        r = sd_rtnl_send(nl, message, &serial);
-        if (r < 0)
-                return r;
-
-        timeout = calc_elapse(usec);
-
-        for (;;) {
-                usec_t left;
-                _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
-
-                if (!room) {
-                        sd_rtnl_message **q;
-
-                        if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
-                                return -ENOBUFS;
-
-                        /* Make sure there's room for queueing this
-                         * locally, before we read the message */
-
-                        q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
-                        if (!q)
-                                return -ENOMEM;
-
-                        nl->rqueue = q;
-                        room = true;
-                }
-
-                r = socket_read_message(nl, &incoming);
-                if (r < 0)
-                        return r;
-                if (incoming) {
-                        uint32_t received_serial = message_get_serial(incoming);
-
-                        if (received_serial == serial) {
-                                r = sd_rtnl_message_get_errno(incoming);
-                                if (r < 0)
-                                        return r;
-
-                                if (ret) {
-                                        *ret = incoming;
-                                        incoming = NULL;
-                                }
-
-                                return 1;
-                        }
-
-                        /* Room was allocated on the queue above */
-                        nl->rqueue[nl->rqueue_size ++] = incoming;
-                        incoming = NULL;
-                        room = false;
-
-                        /* Try to read more, right away */
-                        continue;
-                }
-                if (r != 0)
-                        continue;
-
-                if (timeout > 0) {
-                        usec_t n;
-
-                        n = now(CLOCK_MONOTONIC);
-                        if (n >= timeout)
-                                return -ETIMEDOUT;
-
-                        left = timeout - n;
-                } else
-                        left = (uint64_t) -1;
-
-                r = rtnl_poll(nl, true, left);
-                if (r < 0)
-                        return r;
-
-                r = dispatch_wqueue(nl);
-                if (r < 0)
-                        return r;
-        }
-}
-
-int sd_rtnl_flush(sd_rtnl *rtnl) {
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->wqueue_size <= 0)
-                return 0;
-
-        for (;;) {
-                r = dispatch_wqueue(rtnl);
-                if (r < 0)
-                        return r;
-
-                if (rtnl->wqueue_size <= 0)
-                        return 0;
-
-                r = rtnl_poll(rtnl, false, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-int sd_rtnl_get_events(sd_rtnl *rtnl) {
-        int flags = 0;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->rqueue_size <= 0)
-                flags |= POLLIN;
-        if (rtnl->wqueue_size > 0)
-                flags |= POLLOUT;
-
-        return flags;
-}
-
-int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
-        struct reply_callback *c;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(timeout_usec, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        if (rtnl->rqueue_size > 0) {
-                *timeout_usec = 0;
-                return 1;
-        }
-
-        c = prioq_peek(rtnl->reply_callbacks_prioq);
-        if (!c) {
-                *timeout_usec = (uint64_t) -1;
-                return 0;
-        }
-
-        *timeout_usec = c->timeout;
-
-        return 1;
-}
-
-static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-        int r;
-
-        assert(rtnl);
-
-        r = sd_rtnl_process(rtnl, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-        int r;
-
-        assert(rtnl);
-
-        r = sd_rtnl_process(rtnl, NULL);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int prepare_callback(sd_event_source *s, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-        int r, e;
-        usec_t until;
-
-        assert(s);
-        assert(rtnl);
-
-        e = sd_rtnl_get_events(rtnl);
-        if (e < 0)
-                return e;
-
-        r = sd_event_source_set_io_events(rtnl->io_event_source, e);
-        if (r < 0)
-                return r;
-
-        r = sd_rtnl_get_timeout(rtnl, &until);
-        if (r < 0)
-                return r;
-        if (r > 0) {
-                int j;
-
-                j = sd_event_source_set_time(rtnl->time_event_source, until);
-                if (j < 0)
-                        return j;
-        }
-
-        r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static int exit_callback(sd_event_source *event, void *userdata) {
-        sd_rtnl *rtnl = userdata;
-
-        assert(event);
-
-        sd_rtnl_flush(rtnl);
-
-        return 1;
-}
-
-int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
-        int r;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(!rtnl->event, -EBUSY);
-
-        assert(!rtnl->io_event_source);
-        assert(!rtnl->time_event_source);
-
-        if (event)
-                rtnl->event = sd_event_ref(event);
-        else {
-                r = sd_event_default(&rtnl->event);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_event_add_io(rtnl->event, rtnl->fd, 0, io_callback, rtnl, &rtnl->io_event_source);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_priority(rtnl->io_event_source, priority);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_add_monotonic(rtnl->event, 0, 0, time_callback, rtnl, &rtnl->time_event_source);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_priority(rtnl->time_event_source, priority);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_add_exit(rtnl->event, exit_callback, rtnl, &rtnl->exit_event_source);
-        if (r < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        sd_rtnl_detach_event(rtnl);
-        return r;
-}
-
-int sd_rtnl_detach_event(sd_rtnl *rtnl) {
-        assert_return(rtnl, -EINVAL);
-        assert_return(rtnl->event, -ENXIO);
-
-        if (rtnl->io_event_source)
-                rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
-
-        if (rtnl->time_event_source)
-                rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
-
-        if (rtnl->exit_event_source)
-                rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
-
-        if (rtnl->event)
-                rtnl->event = sd_event_unref(rtnl->event);
-
-        return 0;
-}
-
-int sd_rtnl_add_match(sd_rtnl *rtnl,
-                      uint16_t type,
-                      sd_rtnl_message_handler_t callback,
-                      void *userdata) {
-        struct match_callback *c;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-        assert_return(message_type_is_link(type) || message_type_is_addr(type) || message_type_is_route(type), -ENOTSUP);
-
-        c = new0(struct match_callback, 1);
-        if (!c)
-                return -ENOMEM;
-
-        c->callback = callback;
-        c->type = type;
-        c->userdata = userdata;
-
-        LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
-
-        return 0;
-}
-
-int sd_rtnl_remove_match(sd_rtnl *rtnl,
-                         uint16_t type,
-                         sd_rtnl_message_handler_t callback,
-                         void *userdata) {
-        struct match_callback *c;
-
-        assert_return(rtnl, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
-        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
-                if (c->callback == callback && c->type == type && c->userdata == userdata) {
-                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
-                        free(c);
-
-                        return 1;
-                }
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-rtnl/Makefile b/src/libsystemd/sd-rtnl/Makefile
new file mode 120000
index 0000000..94aaae2
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/Makefile
@@ -0,0 +1 @@
+../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h
new file mode 100644
index 0000000..2e0b7b8
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/rtnl-internal.h
@@ -0,0 +1,99 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  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 <linux/netlink.h>
+
+#include "refcnt.h"
+#include "prioq.h"
+#include "list.h"
+
+#include "sd-rtnl.h"
+
+struct reply_callback {
+        sd_rtnl_message_handler_t callback;
+        void *userdata;
+        usec_t timeout;
+        uint64_t serial;
+        unsigned prioq_idx;
+};
+
+struct match_callback {
+        sd_rtnl_message_handler_t callback;
+        uint16_t type;
+        void *userdata;
+
+        LIST_FIELDS(struct match_callback, match_callbacks);
+};
+
+struct sd_rtnl {
+        RefCount n_ref;
+
+        int fd;
+
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sockaddr;
+
+        sd_rtnl_message **rqueue;
+        unsigned rqueue_size;
+
+        sd_rtnl_message **wqueue;
+        unsigned wqueue_size;
+
+        bool processing:1;
+
+        uint32_t serial;
+
+        struct Prioq *reply_callbacks_prioq;
+        Hashmap *reply_callbacks;
+
+        LIST_HEAD(struct match_callback, match_callbacks);
+
+        pid_t original_pid;
+
+        sd_event_source *io_event_source;
+        sd_event_source *time_event_source;
+        sd_event_source *exit_event_source;
+        sd_event *event;
+};
+
+#define RTNL_DEFAULT_TIMEOUT ((usec_t) (10 * USEC_PER_SEC))
+
+#define RTNL_WQUEUE_MAX 1024
+#define RTNL_RQUEUE_MAX 64*1024
+
+int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret);
+uint32_t message_get_serial(sd_rtnl_message *m);
+int message_seal(sd_rtnl *nl, sd_rtnl_message *m);
+
+bool message_type_is_link(uint16_t type);
+bool message_type_is_addr(uint16_t type);
+bool message_type_is_route(uint16_t type);
+
+int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m);
+int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret);
+
+/* Make sure callbacks don't destroy the rtnl connection */
+#define RTNL_DONT_DESTROY(rtnl) \
+        _cleanup_sd_rtnl_unref_ _unused_ sd_rtnl *_dont_destroy_##rtnl = sd_rtnl_ref(rtnl)
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
new file mode 100644
index 0000000..984115c
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -0,0 +1,887 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  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 <linux/rtnetlink.h>
+#include <netinet/in.h>
+#include <netinet/ether.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "refcnt.h"
+
+#include "sd-rtnl.h"
+#include "rtnl-internal.h"
+
+struct sd_rtnl_message {
+        RefCount n_ref;
+
+        struct nlmsghdr *hdr;
+        size_t container_offset; /* offset from hdr to container start */
+        size_t next_rta_offset; /* offset from hdr to next rta */
+
+        bool sealed:1;
+};
+
+#define CURRENT_CONTAINER(m) ((m)->container_offset ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offset) : NULL)
+#define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
+#define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
+
+static int message_new(sd_rtnl_message **ret, size_t initial_size) {
+        sd_rtnl_message *m;
+
+        assert_return(ret, -EINVAL);
+        assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
+
+        m = new0(sd_rtnl_message, 1);
+        if (!m)
+                return -ENOMEM;
+
+        m->hdr = malloc0(initial_size);
+        if (!m->hdr) {
+                free(m);
+                return -ENOMEM;
+        }
+
+        m->n_ref = REFCNT_INIT;
+
+        m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+        m->sealed = false;
+
+        *ret = m;
+
+        return 0;
+}
+
+int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
+        struct nlmsgerr *err;
+        int r;
+
+        assert(error <= 0);
+
+        r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+        (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
+        (*ret)->hdr->nlmsg_seq = serial;
+
+        err = NLMSG_DATA((*ret)->hdr);
+
+        err->error = error;
+
+        return 0;
+}
+
+bool message_type_is_route(uint16_t type) {
+        switch (type) {
+                case RTM_NEWROUTE:
+                case RTM_GETROUTE:
+                case RTM_DELROUTE:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+bool message_type_is_link(uint16_t type) {
+        switch (type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+bool message_type_is_addr(uint16_t type) {
+        switch (type) {
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        return true;
+                default:
+                        return false;
+        }
+}
+
+int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
+        struct rtmsg *rtm;
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        rtm->rtm_dst_len = prefixlen;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
+                              sd_rtnl_message **ret) {
+        struct rtmsg *rtm;
+        int r;
+
+        assert_return(message_type_is_route(nlmsg_type), -EINVAL);
+        assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+        (*ret)->hdr->nlmsg_type = nlmsg_type;
+        if (nlmsg_type == RTM_NEWROUTE)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+
+        rtm = NLMSG_DATA((*ret)->hdr);
+
+        UPDATE_RTA(*ret, RTM_RTA(rtm));
+
+        rtm->rtm_family = rtm_family;
+        rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+        rtm->rtm_type = RTN_UNICAST;
+        rtm->rtm_table = RT_TABLE_MAIN;
+        rtm->rtm_protocol = RTPROT_BOOT;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags) {
+        struct ifinfomsg *ifi;
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_flags = flags;
+        ifi->ifi_change = 0xffffffff;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
+        struct ifinfomsg *ifi;
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        ifi->ifi_type = type;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
+        struct ifinfomsg *ifi;
+        int r;
+
+        assert_return(message_type_is_link(nlmsg_type), -EINVAL);
+        assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+        (*ret)->hdr->nlmsg_type = nlmsg_type;
+        if (nlmsg_type == RTM_NEWLINK)
+                (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
+
+        ifi = NLMSG_DATA((*ret)->hdr);
+
+        ifi->ifi_family = AF_UNSPEC;
+        ifi->ifi_index = index;
+
+        UPDATE_RTA(*ret, IFLA_RTA(ifi));
+
+        return 0;
+}
+
+int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
+        struct ifaddrmsg *ifa;
+        int r;
+
+        assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
+        assert_return(index > 0, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
+        if (r < 0)
+                return r;
+
+        (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        (*ret)->hdr->nlmsg_type = nlmsg_type;
+
+        ifa = NLMSG_DATA((*ret)->hdr);
+
+        ifa->ifa_family = family;
+        ifa->ifa_prefixlen = prefixlen;
+        ifa->ifa_flags = flags;
+        ifa->ifa_scope = scope;
+        ifa->ifa_index = index;
+
+        UPDATE_RTA(*ret, IFA_RTA(ifa));
+
+        return 0;
+}
+
+sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
+        if (m)
+                assert_se(REFCNT_INC(m->n_ref) >= 2);
+
+        return m;
+}
+
+sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
+        if (m && REFCNT_DEC(m->n_ref) <= 0) {
+                free(m->hdr);
+                free(m);
+        }
+
+        return NULL;
+}
+
+int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
+        assert_return(m, -EINVAL);
+        assert_return(type, -EINVAL);
+
+        *type = m->hdr->nlmsg_type;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(ifindex, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *ifindex = ifi->ifi_index;
+
+        return 0;
+}
+
+int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
+        struct ifinfomsg *ifi;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        ifi = NLMSG_DATA(m->hdr);
+
+        *flags = ifi->ifi_flags;
+
+        return 0;
+}
+
+/* If successful the updated message will be correctly aligned, if
+   unsuccessful the old message is untouched. */
+static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
+        uint32_t rta_length, message_length;
+        struct nlmsghdr *new_hdr;
+        struct rtattr *rta;
+        char *padding;
+
+        assert(m);
+        assert(m->hdr);
+        assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
+        assert(!data || data_length > 0);
+
+        /* get the size of the new rta attribute (with padding at the end) */
+        rta_length = RTA_LENGTH(data_length);
+
+        /* get the new message size (with padding at the end) */
+        message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
+
+        /* realloc to fit the new attribute */
+        new_hdr = realloc(m->hdr, message_length);
+        if (!new_hdr)
+                return -ENOMEM;
+        m->hdr = new_hdr;
+
+        /* get pointer to the attribute we are about to add */
+        rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
+
+        /* if we are inside a container, extend it */
+        if (CURRENT_CONTAINER(m))
+                CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
+
+        /* fill in the attribute */
+        rta->rta_type = type;
+        rta->rta_len = rta_length;
+        if (!data) {
+                /* this is the start of a new container */
+                m->container_offset = m->hdr->nlmsg_len;
+        } else {
+                /* we don't deal with the case where the user lies about the type
+                 * and gives us too little data (so don't do that)
+                */
+                padding = mempcpy(RTA_DATA(rta), data, data_length);
+                /* make sure also the padding at the end of the message is initialized */
+                memzero(padding,
+                        (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
+        }
+
+        /* update message size */
+        m->hdr->nlmsg_len = message_length;
+
+        return 0;
+}
+
+int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
+        uint16_t rtm_type;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(data, -EINVAL);
+
+        r = sd_rtnl_message_get_type(m, &rtm_type);
+        if (r < 0)
+                return r;
+
+        /* check that the type is correct */
+        switch (rtm_type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        if (CURRENT_CONTAINER(m)) {
+                                if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
+                                    type != IFLA_INFO_KIND)
+                                        return -ENOTSUP;
+                        } else {
+                                switch (type) {
+                                        case IFLA_IFNAME:
+                                        case IFLA_IFALIAS:
+                                        case IFLA_QDISC:
+                                                break;
+                                        default:
+                                                return -ENOTSUP;
+                                }
+                        }
+                        break;
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        if (type != IFA_LABEL)
+                                return -ENOTSUP;
+                        break;
+                default:
+                        return -ENOTSUP;
+        }
+
+        r = add_rtattr(m, type, data, strlen(data) + 1);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
+        uint16_t rtm_type;
+        int r;
+
+        assert_return(m, -EINVAL);
+
+        r = sd_rtnl_message_get_type(m, &rtm_type);
+        if (r < 0)
+                return r;
+
+        /* check that the type is correct */
+        switch (rtm_type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        switch (type) {
+                                case IFLA_MASTER:
+                                case IFLA_MTU:
+                                case IFLA_LINK:
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                        break;
+                case RTM_NEWROUTE:
+                case RTM_GETROUTE:
+                case RTM_DELROUTE:
+                        switch (type) {
+                                case RTA_TABLE:
+                                case RTA_PRIORITY:
+                                case RTA_IIF:
+                                case RTA_OIF:
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                        break;
+                default:
+                        return -ENOTSUP;
+        }
+
+        r = add_rtattr(m, type, &data, sizeof(uint32_t));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
+        struct ifaddrmsg *ifa;
+        struct rtmsg *rtm;
+        uint16_t rtm_type;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(data, -EINVAL);
+
+        r = sd_rtnl_message_get_type(m, &rtm_type);
+        if (r < 0)
+                return r;
+
+        /* check that the type is correct */
+        switch (rtm_type) {
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        switch (type) {
+                                case IFA_ADDRESS:
+                                case IFA_LOCAL:
+                                case IFA_BROADCAST:
+                                case IFA_ANYCAST:
+                                        ifa = NLMSG_DATA(m->hdr);
+
+                                        if (ifa->ifa_family != AF_INET)
+                                                return -EINVAL;
+
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                        break;
+                case RTM_NEWROUTE:
+                case RTM_GETROUTE:
+                case RTM_DELROUTE:
+                        switch (type) {
+                                case RTA_DST:
+                                case RTA_SRC:
+                                case RTA_GATEWAY:
+                                        rtm = NLMSG_DATA(m->hdr);
+
+                                        if (rtm->rtm_family != AF_INET)
+                                                return -EINVAL;
+
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                        break;
+                default:
+                        return -ENOTSUP;
+        }
+
+        r = add_rtattr(m, type, data, sizeof(struct in_addr));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
+        struct ifaddrmsg *ifa;
+        struct rtmsg *rtm;
+        uint16_t rtm_type;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(data, -EINVAL);
+
+        r = sd_rtnl_message_get_type(m, &rtm_type);
+        if (r < 0)
+                return r;
+
+        /* check that the type is correct */
+        switch (rtm_type) {
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        switch (type) {
+                                case IFA_ADDRESS:
+                                case IFA_LOCAL:
+                                case IFA_BROADCAST:
+                                case IFA_ANYCAST:
+                                        ifa = NLMSG_DATA(m->hdr);
+
+                                        if (ifa->ifa_family != AF_INET6)
+                                                return -EINVAL;
+
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                        break;
+                case RTM_NEWROUTE:
+                case RTM_GETROUTE:
+                case RTM_DELROUTE:
+                        switch (type) {
+                                case RTA_DST:
+                                case RTA_SRC:
+                                case RTA_GATEWAY:
+                                        rtm = NLMSG_DATA(m->hdr);
+
+                                        if (rtm->rtm_family != AF_INET6)
+                                                return -EINVAL;
+
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                default:
+                        return -ENOTSUP;
+        }
+
+        r = add_rtattr(m, type, data, sizeof(struct in6_addr));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
+        uint16_t rtm_type;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(data, -EINVAL);
+
+        sd_rtnl_message_get_type(m, &rtm_type);
+
+        switch (rtm_type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_DELLINK:
+                case RTM_GETLINK:
+                        switch (type) {
+                                case IFLA_ADDRESS:
+                                case IFLA_BROADCAST:
+                                        break;
+                                default:
+                                        return -ENOTSUP;
+                        }
+                        break;
+                default:
+                        return -ENOTSUP;
+        }
+
+        r = add_rtattr(m, type, data, ETH_ALEN);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
+        uint16_t rtm_type;
+
+        assert_return(m, -EINVAL);
+        assert_return(!CURRENT_CONTAINER(m), -EINVAL);
+
+        sd_rtnl_message_get_type(m, &rtm_type);
+
+        if (message_type_is_link(rtm_type)) {
+                if (type == IFLA_LINKINFO)
+                        return add_rtattr(m, type, NULL, 0);
+                else
+                        return -ENOTSUP;
+        } else
+                return -ENOTSUP;
+
+        return 0;
+}
+
+int sd_rtnl_message_close_container(sd_rtnl_message *m) {
+        assert_return(m, -EINVAL);
+        assert_return(CURRENT_CONTAINER(m), -EINVAL);
+
+        m->container_offset = 0;
+
+        return 0;
+}
+
+int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
+        size_t remaining_size;
+        uint16_t rtm_type;
+        int r;
+
+        assert(m);
+        assert(m->next_rta_offset);
+        assert(type);
+        assert(data);
+
+        remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
+
+        if (!RTA_OK(NEXT_RTA(m), remaining_size))
+                return 0;
+
+        /* make sure we don't try to read a container
+         * TODO: add support for entering containers for reading */
+        r = sd_rtnl_message_get_type(m, &rtm_type);
+        if (r < 0)
+                return r;
+
+        if (message_type_is_link(rtm_type) &&
+            NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
+               return -EINVAL;
+
+        *data = RTA_DATA(NEXT_RTA(m));
+        *type = NEXT_RTA(m)->rta_type;
+
+        UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
+
+        return 1;
+}
+
+uint32_t message_get_serial(sd_rtnl_message *m) {
+        assert(m);
+        assert(m->hdr);
+
+        return m->hdr->nlmsg_seq;
+}
+
+int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
+        struct nlmsgerr *err;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+
+        if (m->hdr->nlmsg_type != NLMSG_ERROR)
+                return 0;
+
+        err = NLMSG_DATA(m->hdr);
+
+        return err->error;
+}
+
+int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
+        assert(nl);
+        assert(m);
+        assert(m->hdr);
+
+        if (m->sealed)
+                return -EPERM;
+
+        m->hdr->nlmsg_seq = nl->serial++;
+        m->sealed = true;
+
+        return 0;
+}
+
+static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
+        assert(rtnl);
+        assert(need);
+
+        /* ioctl(rtnl->fd, FIONREAD, &need)
+           Does not appear to work on netlink sockets. libnl uses
+           MSG_PEEK instead. I don't know if that is worth the
+           extra roundtrip.
+
+           For now we simply use the maximum message size the kernel
+           may use (NLMSG_GOODSIZE), and then realloc to the actual
+           size after reading the message (hence avoiding huge memory
+           usage in case many small messages are kept around) */
+        *need = page_size();
+        if (*need > 8192UL)
+                *need = 8192UL;
+
+        return 0;
+}
+
+/* returns the number of bytes sent, or a negative error code */
+int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } addr = {
+                .nl.nl_family = AF_NETLINK,
+        };
+        ssize_t k;
+
+        assert(nl);
+        assert(m);
+        assert(m->hdr);
+
+        k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
+                        0, &addr.sa, sizeof(addr));
+        if (k < 0)
+                return (errno == EAGAIN) ? 0 : -errno;
+
+        return k;
+}
+
+/* On success, the number of bytes received is returned and *ret points to the received message
+ * which has a valid header and the correct size.
+ * If nothing useful was received 0 is returned.
+ * On failure, a negative error code is returned.
+ */
+int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
+        sd_rtnl_message *m;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } addr;
+        socklen_t addr_len;
+        int r;
+        ssize_t k;
+        size_t need;
+
+        assert(nl);
+        assert(ret);
+
+        r = message_receive_need(nl, &need);
+        if (r < 0)
+                return r;
+
+        r = message_new(&m, need);
+        if (r < 0)
+                return r;
+
+        addr_len = sizeof(addr);
+
+        k = recvfrom(nl->fd, m->hdr, need,
+                        0, &addr.sa, &addr_len);
+        if (k < 0)
+                k = (errno == EAGAIN) ? 0 : -errno; /* no data */
+        else if (k == 0)
+                k = -ECONNRESET; /* connection was closed by the kernel */
+        else if (addr_len != sizeof(addr.nl) ||
+                        addr.nl.nl_family != AF_NETLINK)
+                k = -EIO; /* not a netlink message */
+        else if (addr.nl.nl_pid != 0)
+                k = 0; /* not from the kernel */
+        else if ((size_t) k < sizeof(struct nlmsghdr) ||
+                        (size_t) k < m->hdr->nlmsg_len)
+                k = -EIO; /* too small (we do accept too big though) */
+        else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
+                k = 0; /* not broadcast and not for us */
+
+        if (k > 0)
+                switch (m->hdr->nlmsg_type) {
+                        struct ifinfomsg *ifi;
+                        struct ifaddrmsg *ifa;
+                        struct rtmsg *rtm;
+
+                        /* check that the size matches the message type */
+                        case NLMSG_ERROR:
+                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+                                        k = -EIO;
+                                break;
+                        case RTM_NEWLINK:
+                        case RTM_SETLINK:
+                        case RTM_DELLINK:
+                        case RTM_GETLINK:
+                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
+                                        k = -EIO;
+                                else {
+                                        ifi = NLMSG_DATA(m->hdr);
+                                        UPDATE_RTA(m, IFLA_RTA(ifi));
+                                }
+                                break;
+                        case RTM_NEWADDR:
+                        case RTM_DELADDR:
+                        case RTM_GETADDR:
+                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
+                                        k = -EIO;
+                                else {
+                                        ifa = NLMSG_DATA(m->hdr);
+                                        UPDATE_RTA(m, IFA_RTA(ifa));
+                                }
+                                break;
+                        case RTM_NEWROUTE:
+                        case RTM_DELROUTE:
+                        case RTM_GETROUTE:
+                                if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
+                                        k = -EIO;
+                                else {
+                                        rtm = NLMSG_DATA(m->hdr);
+                                        UPDATE_RTA(m, RTM_RTA(rtm));
+                                }
+                                break;
+                        case NLMSG_NOOP:
+                                k = 0;
+                                break;
+                        default:
+                                k = 0; /* ignoring message of unknown type */
+                }
+
+        if (k <= 0)
+                sd_rtnl_message_unref(m);
+        else {
+                /* we probably allocated way too much memory, give it back */
+                m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
+                *ret = m;
+        }
+
+        return k;
+}
+
+int sd_rtnl_message_rewind(sd_rtnl_message *m) {
+        struct ifinfomsg *ifi;
+        struct ifaddrmsg *ifa;
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+
+        switch(m->hdr->nlmsg_type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        ifi = NLMSG_DATA(m->hdr);
+                        UPDATE_RTA(m, IFLA_RTA(ifi));
+
+                        break;
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        ifa = NLMSG_DATA(m->hdr);
+                        UPDATE_RTA(m, IFA_RTA(ifa));
+
+                        break;
+                case RTM_NEWROUTE:
+                case RTM_GETROUTE:
+                case RTM_DELROUTE:
+                        rtm = NLMSG_DATA(m->hdr);
+                        UPDATE_RTA(m, RTM_RTA(rtm));
+
+                        break;
+                default:
+                        return -ENOTSUP;
+        }
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c
new file mode 100644
index 0000000..dfc0050
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/rtnl-util.c
@@ -0,0 +1,100 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
+
+  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 <linux/rtnetlink.h>
+#include <netinet/ether.h>
+
+#include "sd-rtnl.h"
+
+#include "rtnl-util.h"
+
+int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message = NULL;
+        int r;
+
+        assert(rtnl);
+        assert(ifindex > 0);
+        assert(name);
+
+        r = sd_rtnl_message_link_new(RTM_SETLINK, ifindex, &message);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_message_append_string(message, IFLA_IFNAME, name);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_call(rtnl, message, 0, NULL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias,
+                             const struct ether_addr *mac, unsigned mtu) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message = NULL;
+        bool need_update = false;
+        int r;
+
+        assert(rtnl);
+        assert(ifindex > 0);
+
+        if (!alias && !mac && mtu == 0)
+                return 0;
+
+        r = sd_rtnl_message_link_new(RTM_SETLINK, ifindex, &message);
+        if (r < 0)
+                return r;
+
+        if (alias) {
+                r = sd_rtnl_message_append_string(message, IFLA_IFALIAS, alias);
+                if (r < 0)
+                        return r;
+
+                need_update = true;
+
+        }
+
+        if (mac) {
+                r = sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, mac);
+                if (r < 0)
+                        return r;
+
+                need_update = true;
+        }
+
+        if (mtu > 0) {
+                r = sd_rtnl_message_append_u32(message, IFLA_MTU, mtu);
+                if (r < 0)
+                        return r;
+
+                need_update = true;
+        }
+
+        if  (need_update) {
+                r = sd_rtnl_call(rtnl, message, 0, NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h
new file mode 100644
index 0000000..013002d
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/rtnl-util.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg at jklm.no>
+
+  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 <netinet/ether.h>
+
+#include "util.h"
+#include "sd-rtnl.h"
+
+int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name);
+int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl*, sd_rtnl_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl_message*, sd_rtnl_message_unref);
+
+#define _cleanup_sd_rtnl_unref_ _cleanup_(sd_rtnl_unrefp)
+#define _cleanup_sd_rtnl_message_unref_ _cleanup_(sd_rtnl_message_unrefp)
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
new file mode 100644
index 0000000..08b82ab
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/sd-rtnl.c
@@ -0,0 +1,870 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  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 <sys/socket.h>
+#include <poll.h>
+
+#include "macro.h"
+#include "util.h"
+#include "hashmap.h"
+
+#include "sd-rtnl.h"
+#include "rtnl-internal.h"
+#include "rtnl-util.h"
+
+static int sd_rtnl_new(sd_rtnl **ret) {
+        sd_rtnl *rtnl;
+
+        assert_return(ret, -EINVAL);
+
+        rtnl = new0(sd_rtnl, 1);
+        if (!rtnl)
+                return -ENOMEM;
+
+        rtnl->n_ref = REFCNT_INIT;
+
+        rtnl->fd = -1;
+
+        rtnl->sockaddr.nl.nl_family = AF_NETLINK;
+
+        rtnl->original_pid = getpid();
+
+        LIST_HEAD_INIT(rtnl->match_callbacks);
+
+        /* We guarantee that wqueue always has space for at least
+         * one entry */
+        rtnl->wqueue = new(sd_rtnl_message*, 1);
+        if (!rtnl->wqueue) {
+                free(rtnl);
+                return -ENOMEM;
+        }
+
+        *ret = rtnl;
+        return 0;
+}
+
+static bool rtnl_pid_changed(sd_rtnl *rtnl) {
+        assert(rtnl);
+
+        /* We don't support people creating an rtnl connection and
+         * keeping it around over a fork(). Let's complain. */
+
+        return rtnl->original_pid != getpid();
+}
+
+int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) {
+        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        socklen_t addrlen;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        r = sd_rtnl_new(&rtnl);
+        if (r < 0)
+                return r;
+
+        rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
+        if (rtnl->fd < 0)
+                return -errno;
+
+        rtnl->sockaddr.nl.nl_groups = groups;
+
+        addrlen = sizeof(rtnl->sockaddr);
+
+        r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
+        if (r < 0)
+                return -errno;
+
+        r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
+        if (r < 0)
+                return r;
+
+        *ret = rtnl;
+        rtnl = NULL;
+
+        return 0;
+}
+
+sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
+        if (rtnl)
+                assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
+
+        return rtnl;
+}
+
+sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
+
+        if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) {
+                struct match_callback *f;
+                unsigned i;
+
+                for (i = 0; i < rtnl->rqueue_size; i++)
+                        sd_rtnl_message_unref(rtnl->rqueue[i]);
+                free(rtnl->rqueue);
+
+                for (i = 0; i < rtnl->wqueue_size; i++)
+                        sd_rtnl_message_unref(rtnl->wqueue[i]);
+                free(rtnl->wqueue);
+
+                hashmap_free_free(rtnl->reply_callbacks);
+                prioq_free(rtnl->reply_callbacks_prioq);
+
+                while ((f = rtnl->match_callbacks)) {
+                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
+                        free(f);
+                }
+
+                if (rtnl->fd >= 0)
+                        close_nointr_nofail(rtnl->fd);
+
+                free(rtnl);
+        }
+
+        return NULL;
+}
+
+int sd_rtnl_send(sd_rtnl *nl,
+                 sd_rtnl_message *message,
+                 uint32_t *serial) {
+        int r;
+
+        assert_return(nl, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+        assert_return(message, -EINVAL);
+
+        r = message_seal(nl, message);
+        if (r < 0)
+                return r;
+
+        if (nl->wqueue_size <= 0) {
+                /* send directly */
+                r = socket_write_message(nl, message);
+                if (r < 0)
+                        return r;
+                else if (r == 0) {
+                        /* nothing was sent, so let's put it on
+                         * the queue */
+                        nl->wqueue[0] = sd_rtnl_message_ref(message);
+                        nl->wqueue_size = 1;
+                }
+        } else {
+                sd_rtnl_message **q;
+
+                /* append to queue */
+                if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
+                        return -ENOBUFS;
+
+                q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
+                if (!q)
+                        return -ENOMEM;
+
+                nl->wqueue = q;
+                q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
+        }
+
+        if (serial)
+                *serial = message_get_serial(message);
+
+        return 1;
+}
+
+static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
+        sd_rtnl_message *z = NULL;
+        int r;
+
+        assert(rtnl);
+        assert(message);
+
+        if (rtnl->rqueue_size > 0) {
+                /* Dispatch a queued message */
+
+                *message = rtnl->rqueue[0];
+                rtnl->rqueue_size --;
+                memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
+
+                return 1;
+        }
+
+        /* Try to read a new message */
+        r = socket_read_message(rtnl, &z);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 0;
+
+        *message = z;
+
+        return 1;
+}
+
+static int dispatch_wqueue(sd_rtnl *rtnl) {
+        int r, ret = 0;
+
+        assert(rtnl);
+
+        while (rtnl->wqueue_size > 0) {
+                r = socket_write_message(rtnl, rtnl->wqueue[0]);
+                if (r < 0)
+                        return r;
+                else if (r == 0)
+                        /* Didn't do anything this time */
+                        return ret;
+                else {
+                        /* see equivalent in sd-bus.c */
+                        sd_rtnl_message_unref(rtnl->wqueue[0]);
+                        rtnl->wqueue_size --;
+                        memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
+
+                        ret = 1;
+                }
+        }
+
+        return ret;
+}
+
+static int process_timeout(sd_rtnl *rtnl) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+        struct reply_callback *c;
+        usec_t n;
+        int r;
+
+        assert(rtnl);
+
+        c = prioq_peek(rtnl->reply_callbacks_prioq);
+        if (!c)
+                return 0;
+
+        n = now(CLOCK_MONOTONIC);
+        if (c->timeout > n)
+                return 0;
+
+        r = message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
+        if (r < 0)
+                return r;
+
+        assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
+        hashmap_remove(rtnl->reply_callbacks, &c->serial);
+
+        r = c->callback(rtnl, m, c->userdata);
+        free(c);
+
+        return r < 0 ? r : 1;
+}
+
+static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
+        struct reply_callback *c;
+        uint64_t serial;
+        int r;
+
+        assert(rtnl);
+        assert(m);
+
+        serial = message_get_serial(m);
+        c = hashmap_remove(rtnl->reply_callbacks, &serial);
+        if (!c)
+                return 0;
+
+        if (c->timeout != 0)
+                prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
+
+        r = c->callback(rtnl, m, c->userdata);
+        free(c);
+
+        return r;
+}
+
+static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
+        struct match_callback *c;
+        uint16_t type;
+        int r;
+
+        assert(rtnl);
+        assert(m);
+
+        r = sd_rtnl_message_get_type(m, &type);
+        if (r < 0)
+                return r;
+
+        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
+                if (type == c->type) {
+                        r = c->callback(rtnl, m, c->userdata);
+                        if (r != 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
+
+static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+        int r;
+
+        assert(rtnl);
+
+        r = process_timeout(rtnl);
+        if (r != 0)
+                goto null_message;
+
+        r = dispatch_wqueue(rtnl);
+        if (r != 0)
+                goto null_message;
+
+        r = dispatch_rqueue(rtnl, &m);
+        if (r < 0)
+                return r;
+        if (!m)
+                goto null_message;
+
+        r = process_reply(rtnl, m);
+        if (r != 0)
+                goto null_message;
+
+        r = process_match(rtnl, m);
+        if (r != 0)
+                goto null_message;
+
+        if (ret) {
+                *ret = m;
+                m = NULL;
+
+                return 1;
+        }
+
+        return 1;
+
+null_message:
+        if (r >= 0 && ret)
+                *ret = NULL;
+
+        return r;
+}
+
+int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
+        RTNL_DONT_DESTROY(rtnl);
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+        assert_return(!rtnl->processing, -EBUSY);
+
+        rtnl->processing = true;
+        r = process_running(rtnl, ret);
+        rtnl->processing = false;
+
+        return r;
+}
+
+static usec_t calc_elapse(uint64_t usec) {
+        if (usec == (uint64_t) -1)
+                return 0;
+
+        if (usec == 0)
+                usec = RTNL_DEFAULT_TIMEOUT;
+
+        return now(CLOCK_MONOTONIC) + usec;
+}
+
+static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
+        struct pollfd p[1] = {};
+        struct timespec ts;
+        usec_t m = (usec_t) -1;
+        int r, e;
+
+        assert(rtnl);
+
+        e = sd_rtnl_get_events(rtnl);
+        if (e < 0)
+                return e;
+
+        if (need_more)
+                /* Caller wants more data, and doesn't care about
+                 * what's been read or any other timeouts. */
+                return e |= POLLIN;
+        else {
+                usec_t until;
+                /* Caller wants to process if there is something to
+                 * process, but doesn't care otherwise */
+
+                r = sd_rtnl_get_timeout(rtnl, &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))
+                m = timeout_usec;
+
+        p[0].fd = rtnl->fd;
+        p[0].events = e;
+
+        r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
+        if (r < 0)
+                return -errno;
+
+        return r > 0 ? 1 : 0;
+}
+
+int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
+        assert_return(nl, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+
+        if (nl->rqueue_size > 0)
+                return 0;
+
+        return rtnl_poll(nl, false, timeout_usec);
+}
+
+static int timeout_compare(const void *a, const void *b) {
+        const struct reply_callback *x = a, *y = b;
+
+        if (x->timeout != 0 && y->timeout == 0)
+                return -1;
+
+        if (x->timeout == 0 && y->timeout != 0)
+                return 1;
+
+        if (x->timeout < y->timeout)
+                return -1;
+
+        if (x->timeout > y->timeout)
+                return 1;
+
+        return 0;
+}
+
+int sd_rtnl_call_async(sd_rtnl *nl,
+                       sd_rtnl_message *m,
+                       sd_rtnl_message_handler_t callback,
+                       void *userdata,
+                       uint64_t usec,
+                       uint32_t *serial) {
+        struct reply_callback *c;
+        uint32_t s;
+        int r, k;
+
+        assert_return(nl, -EINVAL);
+        assert_return(m, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+
+        r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
+        if (r < 0)
+                return r;
+
+        if (usec != (uint64_t) -1) {
+                r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
+                if (r < 0)
+                        return r;
+        }
+
+        c = new0(struct reply_callback, 1);
+        if (!c)
+                return -ENOMEM;
+
+        c->callback = callback;
+        c->userdata = userdata;
+        c->timeout = calc_elapse(usec);
+
+        k = sd_rtnl_send(nl, m, &s);
+        if (k < 0) {
+                free(c);
+                return k;
+        }
+
+        c->serial = s;
+
+        r = hashmap_put(nl->reply_callbacks, &c->serial, c);
+        if (r < 0) {
+                free(c);
+                return r;
+        }
+
+        if (c->timeout != 0) {
+                r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
+                if (r > 0) {
+                        c->timeout = 0;
+                        sd_rtnl_call_async_cancel(nl, c->serial);
+                        return r;
+                }
+        }
+
+        if (serial)
+                *serial = s;
+
+        return k;
+}
+
+int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
+        struct reply_callback *c;
+        uint64_t s = serial;
+
+        assert_return(nl, -EINVAL);
+        assert_return(serial != 0, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+
+        c = hashmap_remove(nl->reply_callbacks, &s);
+        if (!c)
+                return 0;
+
+        if (c->timeout != 0)
+                prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
+
+        free(c);
+        return 1;
+}
+
+int sd_rtnl_call(sd_rtnl *nl,
+                sd_rtnl_message *message,
+                uint64_t usec,
+                sd_rtnl_message **ret) {
+        usec_t timeout;
+        uint32_t serial;
+        bool room = false;
+        int r;
+
+        assert_return(nl, -EINVAL);
+        assert_return(!rtnl_pid_changed(nl), -ECHILD);
+        assert_return(message, -EINVAL);
+
+        r = sd_rtnl_send(nl, message, &serial);
+        if (r < 0)
+                return r;
+
+        timeout = calc_elapse(usec);
+
+        for (;;) {
+                usec_t left;
+                _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
+
+                if (!room) {
+                        sd_rtnl_message **q;
+
+                        if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
+                                return -ENOBUFS;
+
+                        /* Make sure there's room for queueing this
+                         * locally, before we read the message */
+
+                        q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
+                        if (!q)
+                                return -ENOMEM;
+
+                        nl->rqueue = q;
+                        room = true;
+                }
+
+                r = socket_read_message(nl, &incoming);
+                if (r < 0)
+                        return r;
+                if (incoming) {
+                        uint32_t received_serial = message_get_serial(incoming);
+
+                        if (received_serial == serial) {
+                                r = sd_rtnl_message_get_errno(incoming);
+                                if (r < 0)
+                                        return r;
+
+                                if (ret) {
+                                        *ret = incoming;
+                                        incoming = NULL;
+                                }
+
+                                return 1;
+                        }
+
+                        /* Room was allocated on the queue above */
+                        nl->rqueue[nl->rqueue_size ++] = incoming;
+                        incoming = NULL;
+                        room = false;
+
+                        /* Try to read more, right away */
+                        continue;
+                }
+                if (r != 0)
+                        continue;
+
+                if (timeout > 0) {
+                        usec_t n;
+
+                        n = now(CLOCK_MONOTONIC);
+                        if (n >= timeout)
+                                return -ETIMEDOUT;
+
+                        left = timeout - n;
+                } else
+                        left = (uint64_t) -1;
+
+                r = rtnl_poll(nl, true, left);
+                if (r < 0)
+                        return r;
+
+                r = dispatch_wqueue(nl);
+                if (r < 0)
+                        return r;
+        }
+}
+
+int sd_rtnl_flush(sd_rtnl *rtnl) {
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        if (rtnl->wqueue_size <= 0)
+                return 0;
+
+        for (;;) {
+                r = dispatch_wqueue(rtnl);
+                if (r < 0)
+                        return r;
+
+                if (rtnl->wqueue_size <= 0)
+                        return 0;
+
+                r = rtnl_poll(rtnl, false, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+int sd_rtnl_get_events(sd_rtnl *rtnl) {
+        int flags = 0;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        if (rtnl->rqueue_size <= 0)
+                flags |= POLLIN;
+        if (rtnl->wqueue_size > 0)
+                flags |= POLLOUT;
+
+        return flags;
+}
+
+int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
+        struct reply_callback *c;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(timeout_usec, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        if (rtnl->rqueue_size > 0) {
+                *timeout_usec = 0;
+                return 1;
+        }
+
+        c = prioq_peek(rtnl->reply_callbacks_prioq);
+        if (!c) {
+                *timeout_usec = (uint64_t) -1;
+                return 0;
+        }
+
+        *timeout_usec = c->timeout;
+
+        return 1;
+}
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        sd_rtnl *rtnl = userdata;
+        int r;
+
+        assert(rtnl);
+
+        r = sd_rtnl_process(rtnl, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
+        sd_rtnl *rtnl = userdata;
+        int r;
+
+        assert(rtnl);
+
+        r = sd_rtnl_process(rtnl, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int prepare_callback(sd_event_source *s, void *userdata) {
+        sd_rtnl *rtnl = userdata;
+        int r, e;
+        usec_t until;
+
+        assert(s);
+        assert(rtnl);
+
+        e = sd_rtnl_get_events(rtnl);
+        if (e < 0)
+                return e;
+
+        r = sd_event_source_set_io_events(rtnl->io_event_source, e);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_get_timeout(rtnl, &until);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                int j;
+
+                j = sd_event_source_set_time(rtnl->time_event_source, until);
+                if (j < 0)
+                        return j;
+        }
+
+        r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int exit_callback(sd_event_source *event, void *userdata) {
+        sd_rtnl *rtnl = userdata;
+
+        assert(event);
+
+        sd_rtnl_flush(rtnl);
+
+        return 1;
+}
+
+int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
+        int r;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(!rtnl->event, -EBUSY);
+
+        assert(!rtnl->io_event_source);
+        assert(!rtnl->time_event_source);
+
+        if (event)
+                rtnl->event = sd_event_ref(event);
+        else {
+                r = sd_event_default(&rtnl->event);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_event_add_io(rtnl->event, rtnl->fd, 0, io_callback, rtnl, &rtnl->io_event_source);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_priority(rtnl->io_event_source, priority);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_add_monotonic(rtnl->event, 0, 0, time_callback, rtnl, &rtnl->time_event_source);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_priority(rtnl->time_event_source, priority);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_add_exit(rtnl->event, exit_callback, rtnl, &rtnl->exit_event_source);
+        if (r < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        sd_rtnl_detach_event(rtnl);
+        return r;
+}
+
+int sd_rtnl_detach_event(sd_rtnl *rtnl) {
+        assert_return(rtnl, -EINVAL);
+        assert_return(rtnl->event, -ENXIO);
+
+        if (rtnl->io_event_source)
+                rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
+
+        if (rtnl->time_event_source)
+                rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
+
+        if (rtnl->exit_event_source)
+                rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
+
+        if (rtnl->event)
+                rtnl->event = sd_event_unref(rtnl->event);
+
+        return 0;
+}
+
+int sd_rtnl_add_match(sd_rtnl *rtnl,
+                      uint16_t type,
+                      sd_rtnl_message_handler_t callback,
+                      void *userdata) {
+        struct match_callback *c;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+        assert_return(message_type_is_link(type) || message_type_is_addr(type) || message_type_is_route(type), -ENOTSUP);
+
+        c = new0(struct match_callback, 1);
+        if (!c)
+                return -ENOMEM;
+
+        c->callback = callback;
+        c->type = type;
+        c->userdata = userdata;
+
+        LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
+
+        return 0;
+}
+
+int sd_rtnl_remove_match(sd_rtnl *rtnl,
+                         uint16_t type,
+                         sd_rtnl_message_handler_t callback,
+                         void *userdata) {
+        struct match_callback *c;
+
+        assert_return(rtnl, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+        LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
+                if (c->callback == callback && c->type == type && c->userdata == userdata) {
+                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
+                        free(c);
+
+                        return 1;
+                }
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c
new file mode 100644
index 0000000..58654e9
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/test-rtnl.c
@@ -0,0 +1,330 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg at jklm.no>
+
+  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 <linux/rtnetlink.h>
+#include <netinet/ether.h>
+
+#include "util.h"
+#include "macro.h"
+#include "sd-rtnl.h"
+#include "socket-util.h"
+#include "rtnl-util.h"
+#include "event-util.h"
+
+static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
+        uint16_t type;
+        const char *mac = "98:fe:94:3f:c6:18", *name = "test";
+        unsigned int mtu = 1450;
+        void *data;
+
+        /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &message) >= 0);
+        assert(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
+        assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
+        assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
+
+        assert(sd_rtnl_message_read(message, &type, &data) > 0);
+        assert(type == IFLA_IFNAME);
+        assert(streq(name, (char *) data));
+
+        assert(sd_rtnl_message_read(message, &type, &data) > 0);
+        assert(type == IFLA_ADDRESS);
+        assert(streq(mac, ether_ntoa(data)));
+
+        assert(sd_rtnl_message_read(message, &type, &data) > 0);
+        assert(type == IFLA_MTU);
+        assert(mtu == *(unsigned int *) data);
+
+        assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
+}
+
+static void test_route(void) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
+        struct in_addr addr;
+        uint32_t index = 2;
+        uint16_t type;
+        void *data;
+        int r;
+
+        r = sd_rtnl_message_route_new(RTM_NEWROUTE, AF_INET, &req);
+        if (r < 0) {
+                log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
+                return;
+        }
+
+        addr.s_addr = htonl(INADDR_LOOPBACK);
+
+        r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
+        if (r < 0) {
+                log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
+                return;
+        }
+
+        r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
+        if (r < 0) {
+                log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
+                return;
+        }
+
+        assert(sd_rtnl_message_read(req, &type, &data) > 0);
+        assert(type == RTA_GATEWAY);
+        assert(((struct in_addr *)data)->s_addr == addr.s_addr);
+
+        assert(sd_rtnl_message_read(req, &type, &data) > 0);
+        assert(type == RTA_OIF);
+        assert(*(uint32_t *) data == index);
+}
+
+static void test_multiple(void) {
+        sd_rtnl *rtnl1, *rtnl2;
+
+        assert(sd_rtnl_open(0, &rtnl1) >= 0);
+        assert(sd_rtnl_open(0, &rtnl2) >= 0);
+
+        rtnl1 = sd_rtnl_unref(rtnl1);
+        rtnl2 = sd_rtnl_unref(rtnl2);
+}
+
+static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+        void *data;
+        uint16_t type;
+        char *ifname = userdata;
+
+        assert(rtnl);
+        assert(m);
+
+        log_info("got link info about %s", ifname);
+        free(ifname);
+
+        while (sd_rtnl_message_read(m, &type, &data) > 0) {
+                switch (type) {
+//                        case IFLA_MTU:
+//                                assert(*(unsigned int *) data == 65536);
+//                                break;
+//                        case IFLA_QDISC:
+//                                assert(streq((char *) data, "noqueue"));
+//                                break;
+                        case IFLA_IFNAME:
+                                assert(streq((char *) data, "lo"));
+                                break;
+                }
+        }
+
+        return 1;
+}
+
+static void test_event_loop(int ifindex) {
+        _cleanup_event_unref_ sd_event *event = NULL;
+        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+        char *ifname;
+
+        ifname = strdup("lo2");
+        assert(ifname);
+
+        assert(sd_rtnl_open(0, &rtnl) >= 0);
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
+
+        assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
+
+        assert(sd_event_default(&event) >= 0);
+
+        assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
+
+        assert(sd_event_run(event, 0) >= 0);
+
+        assert(sd_rtnl_detach_event(rtnl) >= 0);
+}
+
+static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+        int *counter = userdata;
+
+        (*counter) --;
+
+        log_info("got reply, %d left in pipe", *counter);
+
+        return sd_rtnl_message_get_errno(m);
+}
+
+static void test_async(int ifindex) {
+        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
+        uint32_t serial;
+        char *ifname;
+
+        ifname = strdup("lo");
+        assert(ifname);
+
+        assert(sd_rtnl_open(0, &rtnl) >= 0);
+
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
+
+        assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
+
+        assert(sd_rtnl_wait(rtnl, 0) >= 0);
+        assert(sd_rtnl_process(rtnl, &r) >= 0);
+}
+
+static void test_pipe(int ifindex) {
+        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
+        int counter = 0;
+
+        assert(sd_rtnl_open(0, &rtnl) >= 0);
+
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m1) >= 0);
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m2) >= 0);
+
+        counter ++;
+        assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
+
+        counter ++;
+        assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
+
+        while (counter > 0) {
+                assert(sd_rtnl_wait(rtnl, 0) >= 0);
+                assert(sd_rtnl_process(rtnl, NULL) >= 0);
+        }
+}
+
+static void test_container(void) {
+        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
+        uint16_t type;
+        void *data;
+
+        assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, &m) >= 0);
+
+        assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
+        assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -EINVAL);
+        assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
+        assert(sd_rtnl_message_close_container(m) >= 0);
+        assert(sd_rtnl_message_close_container(m) == -EINVAL);
+
+        assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
+
+/* TODO: add support for entering containers
+        assert(sd_rtnl_message_read(m, &type, &data) > 0);
+        assert(type == IFLA_INFO_KIND);
+        assert(streq("kind", (char *) data));
+
+        assert(sd_rtnl_message_read(m, &type, &data) == 0);
+*/
+}
+
+static void test_match(void) {
+        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
+
+        assert(sd_rtnl_open(0, &rtnl) >= 0);
+
+        assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+        assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+
+        assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
+        assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
+        assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
+}
+
+int main(void) {
+        sd_rtnl *rtnl;
+        sd_rtnl_message *m;
+        sd_rtnl_message *r;
+        void *data;
+        int if_loopback;
+        uint16_t type;
+        unsigned int mtu = 0;
+        unsigned int *mtu_reply;
+
+        test_match();
+
+        test_multiple();
+
+        test_route();
+
+        test_container();
+
+        assert(sd_rtnl_open(0, &rtnl) >= 0);
+        assert(rtnl);
+
+        if_loopback = (int) if_nametoindex("lo");
+        assert(if_loopback > 0);
+
+        test_async(if_loopback);
+
+        test_pipe(if_loopback);
+
+        test_event_loop(if_loopback);
+
+        test_link_configure(rtnl, if_loopback);
+
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
+        assert(m);
+
+        assert(sd_rtnl_message_get_type(m, &type) >= 0);
+        assert(type == RTM_GETLINK);
+
+        assert(sd_rtnl_message_read(m, &type, &data) == 0);
+
+        assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
+        assert(sd_rtnl_message_get_type(r, &type) >= 0);
+        assert(type == RTM_NEWLINK);
+
+        assert(sd_rtnl_message_read(m, &type, &data) == 0);
+        assert((r = sd_rtnl_message_unref(r)) == NULL);
+
+        assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
+        assert((m = sd_rtnl_message_unref(m)) == NULL);
+        assert((r = sd_rtnl_message_unref(r)) == NULL);
+
+        assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
+        assert(m);
+
+        assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
+        assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
+
+        assert(type == IFLA_MTU);
+        assert(*mtu_reply == 0);
+
+        assert(sd_rtnl_message_read(m, &type, &data) == 0);
+
+        assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
+        while (sd_rtnl_message_read(r, &type, &data) > 0) {
+                switch (type) {
+//                        case IFLA_MTU:
+//                                assert(*(unsigned int *) data == 65536);
+//                                break;
+//                        case IFLA_QDISC:
+//                                assert(streq((char *) data, "noqueue"));
+//                                break;
+                        case IFLA_IFNAME:
+                                assert(streq((char *) data, "lo"));
+                                break;
+                }
+        }
+
+        assert(sd_rtnl_flush(rtnl) >= 0);
+
+        assert((m = sd_rtnl_message_unref(m)) == NULL);
+        assert((r = sd_rtnl_message_unref(r)) == NULL);
+        assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
+
+        return EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-utf8.c b/src/libsystemd/sd-utf8.c
deleted file mode 100644
index 6f2aa60..0000000
--- a/src/libsystemd/sd-utf8.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- 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 "util.h"
-#include "utf8.h"
-#include "sd-utf8.h"
-
-_public_ const char *sd_utf8_is_valid(const char *s) {
-        assert_return(s, NULL);
-
-        return utf8_is_valid(s);
-}
-
-_public_ const char *sd_ascii_is_valid(const char *s) {
-        assert_return(s, NULL);
-
-        return ascii_is_valid(s);
-}
diff --git a/src/libsystemd/sd-utf8/Makefile b/src/libsystemd/sd-utf8/Makefile
new file mode 120000
index 0000000..94aaae2
--- /dev/null
+++ b/src/libsystemd/sd-utf8/Makefile
@@ -0,0 +1 @@
+../../Makefile
\ No newline at end of file
diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c
new file mode 100644
index 0000000..6f2aa60
--- /dev/null
+++ b/src/libsystemd/sd-utf8/sd-utf8.c
@@ -0,0 +1,36 @@
+/*-*- 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 "util.h"
+#include "utf8.h"
+#include "sd-utf8.h"
+
+_public_ const char *sd_utf8_is_valid(const char *s) {
+        assert_return(s, NULL);
+
+        return utf8_is_valid(s);
+}
+
+_public_ const char *sd_ascii_is_valid(const char *s) {
+        assert_return(s, NULL);
+
+        return ascii_is_valid(s);
+}
diff --git a/src/libsystemd/test-bus-chat.c b/src/libsystemd/test-bus-chat.c
deleted file mode 100644
index 021379f..0000000
--- a/src/libsystemd/test-bus-chat.c
+++ /dev/null
@@ -1,581 +0,0 @@
-/*-*- 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 <assert.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#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, sd_bus_error *ret_error) {
-        log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
-        return 0;
-}
-
-static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        int r;
-
-        assert(bus);
-
-        if (sd_bus_message_is_method_error(m, NULL))
-                return 0;
-
-        if (sd_bus_message_is_method_call(m, "org.object.test", "Foobar")) {
-                log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m));
-
-                r = sd_bus_reply_method_return(m, NULL);
-                if (r < 0) {
-                        log_error("Failed to send reply: %s", strerror(-r));
-                        return r;
-                }
-
-                return 1;
-        }
-
-        return 0;
-}
-
-static int server_init(sd_bus **_bus) {
-        sd_bus *bus = NULL;
-        sd_id128_t id;
-        int r;
-        const char *unique;
-
-        assert(_bus);
-
-        r = sd_bus_open_user(&bus);
-        if (r < 0) {
-                log_error("Failed to connect to user bus: %s", strerror(-r));
-                goto fail;
-        }
-
-        r = sd_bus_get_server_id(bus, &id);
-        if (r < 0) {
-                log_error("Failed to get server ID: %s", strerror(-r));
-                goto fail;
-        }
-
-        r = sd_bus_get_unique_name(bus, &unique);
-        if (r < 0) {
-                log_error("Failed to get unique name: %s", strerror(-r));
-                goto fail;
-        }
-
-        log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
-        log_info("Unique ID: %s", unique);
-        log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
-
-        r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
-        if (r < 0) {
-                log_error("Failed to acquire name: %s", strerror(-r));
-                goto fail;
-        }
-
-        r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL);
-        if (r < 0) {
-                log_error("Failed to add object: %s", strerror(-r));
-                goto fail;
-        }
-
-        r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
-        if (r < 0) {
-                log_error("Failed to add match: %s", strerror(-r));
-                goto fail;
-        }
-
-        r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
-        if (r < 0) {
-                log_error("Failed to add match: %s", strerror(-r));
-                goto fail;
-        }
-
-        bus_match_dump(&bus->match_callbacks, 0);
-
-        *_bus = bus;
-        return 0;
-
-fail:
-        if (bus)
-                sd_bus_unref(bus);
-
-        return r;
-}
-
-static int server(sd_bus *bus) {
-        int r;
-        bool client1_gone = false, client2_gone = false;
-
-        while (!client1_gone || !client2_gone) {
-                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-                pid_t pid = 0;
-                const char *label = NULL;
-
-                r = sd_bus_process(bus, &m);
-                if (r < 0) {
-                        log_error("Failed to process requests: %s", strerror(-r));
-                        goto fail;
-                }
-
-                if (r == 0) {
-                        r = sd_bus_wait(bus, (uint64_t) -1);
-                        if (r < 0) {
-                                log_error("Failed to wait: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        continue;
-                }
-
-                if (!m)
-                        continue;
-
-                sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
-                sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
-                log_info("Got message! member=%s pid=%lu label=%s",
-                         strna(sd_bus_message_get_member(m)),
-                         (unsigned long) pid,
-                         strna(label));
-                /* bus_message_dump(m); */
-                /* sd_bus_message_rewind(m, true); */
-
-                if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
-                        const char *hello;
-                        _cleanup_free_ char *lowercase = NULL;
-
-                        r = sd_bus_message_read(m, "s", &hello);
-                        if (r < 0) {
-                                log_error("Failed to get parameter: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        lowercase = strdup(hello);
-                        if (!lowercase) {
-                                r = log_oom();
-                                goto fail;
-                        }
-
-                        ascii_strlower(lowercase);
-
-                        r = sd_bus_reply_method_return(m, "s", lowercase);
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
-
-                        r = sd_bus_reply_method_return(m, NULL);
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        client1_gone = true;
-                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
-
-                        r = sd_bus_reply_method_return(m, NULL);
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        client2_gone = true;
-                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
-
-                        sleep(1);
-
-                        r = sd_bus_reply_method_return(m, NULL);
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) {
-                        int fd;
-                        static const char x = 'X';
-
-                        r = sd_bus_message_read(m, "h", &fd);
-                        if (r < 0) {
-                                log_error("Failed to get parameter: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        log_info("Received fd=%d", fd);
-
-                        if (write(fd, &x, 1) < 0) {
-                                log_error("Failed to write to fd: %m");
-                                close_nointr_nofail(fd);
-                                goto fail;
-                        }
-
-                        r = sd_bus_reply_method_return(m, NULL);
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
-
-                        r = sd_bus_reply_method_error(
-                                        m,
-                                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-                }
-        }
-
-        r = 0;
-
-fail:
-        if (bus) {
-                sd_bus_flush(bus);
-                sd_bus_unref(bus);
-        }
-
-        return r;
-}
-
-static void* client1(void*p) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        sd_bus *bus = NULL;
-        sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *hello;
-        int r;
-        int pp[2] = { -1, -1 };
-        char x;
-
-        r = sd_bus_open_user(&bus);
-        if (r < 0) {
-                log_error("Failed to connect to user bus: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/",
-                        "org.freedesktop.systemd.test",
-                        "LowerCase",
-                        &error,
-                        &reply,
-                        "s",
-                        "HELLO");
-        if (r < 0) {
-                log_error("Failed to issue method call: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_message_read(reply, "s", &hello);
-        if (r < 0) {
-                log_error("Failed to get string: %s", strerror(-r));
-                goto finish;
-        }
-
-        assert(streq(hello, "hello"));
-
-        if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
-                log_error("Failed to allocate pipe: %m");
-                r = -errno;
-                goto finish;
-        }
-
-        log_info("Sending fd=%d", pp[1]);
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/",
-                        "org.freedesktop.systemd.test",
-                        "FileDescriptor",
-                        &error,
-                        NULL,
-                        "h",
-                        pp[1]);
-        if (r < 0) {
-                log_error("Failed to issue method call: %s", strerror(-r));
-                goto finish;
-        }
-
-        errno = 0;
-        if (read(pp[0], &x, 1) <= 0) {
-                log_error("Failed to read from pipe: %s", errno ? strerror(errno) : "early read");
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        if (bus) {
-                _cleanup_bus_message_unref_ sd_bus_message *q;
-
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                "org.freedesktop.systemd.test",
-                                "/",
-                                "org.freedesktop.systemd.test",
-                                "ExitClient1",
-                                &q);
-                if (r < 0)
-                        log_error("Failed to allocate method call: %s", strerror(-r));
-                else
-                        sd_bus_send(bus, q, NULL);
-
-                sd_bus_flush(bus);
-                sd_bus_unref(bus);
-        }
-
-        sd_bus_error_free(&error);
-
-        close_pipe(pp);
-
-        return INT_TO_PTR(r);
-}
-
-static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        bool *x = userdata;
-
-        log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m)));
-
-        *x = 1;
-        return 1;
-}
-
-static void* client2(void*p) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
-        sd_bus *bus = NULL;
-        sd_bus_error error = SD_BUS_ERROR_NULL;
-        bool quit = false;
-        const char *mid;
-        int r;
-
-        r = sd_bus_open_user(&bus);
-        if (r < 0) {
-                log_error("Failed to connect to user bus: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/foo/bar/waldo/piep",
-                        "org.object.test",
-                        "Foobar",
-                        &m);
-        if (r < 0) {
-                log_error("Failed to allocate method call: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_send(bus, m, NULL);
-        if (r < 0) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
-                goto finish;
-        }
-
-        sd_bus_message_unref(m);
-        m = NULL;
-
-        r = sd_bus_message_new_signal(
-                        bus,
-                        "/foobar",
-                        "foo.bar",
-                        "Notify",
-                        &m);
-        if (r < 0) {
-                log_error("Failed to allocate signal: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_send(bus, m, NULL);
-        if (r < 0) {
-                log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
-                goto finish;
-        }
-
-        sd_bus_message_unref(m);
-        m = NULL;
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/",
-                        "org.freedesktop.DBus.Peer",
-                        "GetMachineId",
-                        &m);
-        if (r < 0) {
-                log_error("Failed to allocate method call: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_call(bus, m, 0, &error, &reply);
-        if (r < 0) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
-                goto finish;
-        }
-
-        r = sd_bus_message_read(reply, "s", &mid);
-        if (r < 0) {
-                log_error("Failed to parse machine ID: %s", strerror(-r));
-                goto finish;
-        }
-
-        log_info("Machine ID is %s.", mid);
-
-        sd_bus_message_unref(m);
-        m = NULL;
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/",
-                        "org.freedesktop.systemd.test",
-                        "Slow",
-                        &m);
-        if (r < 0) {
-                log_error("Failed to allocate method call: %s", strerror(-r));
-                goto finish;
-        }
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
-        if (r < 0)
-                log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
-        else
-                log_info("Slow call succeed.");
-
-        sd_bus_message_unref(m);
-        m = NULL;
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/",
-                        "org.freedesktop.systemd.test",
-                        "Slow",
-                        &m);
-        if (r < 0) {
-                log_error("Failed to allocate method call: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = sd_bus_call_async(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
-        if (r < 0) {
-                log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
-                goto finish;
-        }
-
-        while (!quit) {
-                r = sd_bus_process(bus, NULL);
-                if (r < 0) {
-                        log_error("Failed to process requests: %s", strerror(-r));
-                        goto finish;
-                }
-                if (r == 0) {
-                        r = sd_bus_wait(bus, (uint64_t) -1);
-                        if (r < 0) {
-                                log_error("Failed to wait: %s", strerror(-r));
-                                goto finish;
-                        }
-                }
-        }
-
-        r = 0;
-
-finish:
-        if (bus) {
-                _cleanup_bus_message_unref_ sd_bus_message *q;
-
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                "org.freedesktop.systemd.test",
-                                "/",
-                                "org.freedesktop.systemd.test",
-                                "ExitClient2",
-                                &q);
-                if (r < 0) {
-                        log_error("Failed to allocate method call: %s", strerror(-r));
-                        goto finish;
-                }
-
-                sd_bus_send(bus, q, NULL);
-                sd_bus_flush(bus);
-                sd_bus_unref(bus);
-        }
-
-        sd_bus_error_free(&error);
-        return INT_TO_PTR(r);
-}
-
-int main(int argc, char *argv[]) {
-        pthread_t c1, c2;
-        sd_bus *bus;
-        void *p;
-        int q, r;
-
-        r = server_init(&bus);
-        if (r < 0) {
-                log_info("Failed to connect to bus, skipping tests.");
-                return EXIT_TEST_SKIP;
-        }
-
-        log_info("Initialized...");
-
-        r = pthread_create(&c1, NULL, client1, bus);
-        if (r != 0)
-                return EXIT_FAILURE;
-
-        r = pthread_create(&c2, NULL, client2, bus);
-        if (r != 0)
-                return EXIT_FAILURE;
-
-        r = server(bus);
-
-        q = pthread_join(c1, &p);
-        if (q != 0)
-                return EXIT_FAILURE;
-        if (PTR_TO_INT(p) < 0)
-                return EXIT_FAILURE;
-
-        q = pthread_join(c2, &p);
-        if (q != 0)
-                return EXIT_FAILURE;
-        if (PTR_TO_INT(p) < 0)
-                return EXIT_FAILURE;
-
-        if (r < 0)
-                return EXIT_FAILURE;
-
-        return EXIT_SUCCESS;
-}
diff --git a/src/libsystemd/test-bus-cleanup.c b/src/libsystemd/test-bus-cleanup.c
deleted file mode 100644
index d8ddb84..0000000
--- a/src/libsystemd/test-bus-cleanup.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Zbigniew Jędrzejewski-Szmek
-
-  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 <stdio.h>
-
-#include "sd-bus.h"
-#include "bus-util.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "refcnt.h"
-
-static void test_bus_new(void) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-
-        assert_se(sd_bus_new(&bus) == 0);
-        printf("after new: refcount %u\n", REFCNT_GET(bus->n_ref));
-}
-
-static void test_bus_open(void) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-
-        assert_se(sd_bus_open_system(&bus) >= 0);
-        printf("after open: refcount %u\n", REFCNT_GET(bus->n_ref));
-}
-
-static void test_bus_new_method_call(void) {
-        sd_bus *bus = NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
-        assert_se(sd_bus_open_system(&bus) >= 0);
-
-        assert_se(sd_bus_message_new_method_call(bus, "a.service.name", "/an/object/path", "an.interface.name", "AMethodName", &m) >= 0);
-
-        printf("after message_new_method_call: refcount %u\n", REFCNT_GET(bus->n_ref));
-
-        sd_bus_unref(bus);
-        printf("after bus_unref: refcount %u\n", m->n_ref);
-}
-
-static void test_bus_new_signal(void) {
-        sd_bus *bus = NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
-        assert_se(sd_bus_open_system(&bus) >= 0);
-
-        assert_se(sd_bus_message_new_signal(bus, "/an/object/path", "an.interface.name", "Name", &m) >= 0);
-
-        printf("after message_new_signal: refcount %u\n", REFCNT_GET(bus->n_ref));
-
-        sd_bus_unref(bus);
-        printf("after bus_unref: refcount %u\n", m->n_ref);
-}
-
-int main(int argc, char **argv) {
-        log_parse_environment();
-        log_open();
-
-        test_bus_new();
-        test_bus_open();
-        test_bus_new_method_call();
-        test_bus_new_signal();
-}
diff --git a/src/libsystemd/test-bus-creds.c b/src/libsystemd/test-bus-creds.c
deleted file mode 100644
index 966b84c..0000000
--- a/src/libsystemd/test-bus-creds.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-*- 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-bus.h"
-#include "bus-dump.h"
-#include "bus-util.h"
-#include "util.h"
-
-int main(int argc, char *argv[]) {
-        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-        int r;
-
-        r = sd_bus_creds_new_from_pid(0, _SD_BUS_CREDS_ALL, &creds);
-        assert_se(r >= 0);
-
-        bus_creds_dump(creds, NULL);
-
-        creds = sd_bus_creds_unref(creds);
-
-        r = sd_bus_creds_new_from_pid(1, _SD_BUS_CREDS_ALL, &creds);
-        if (r != -EACCES) {
-                assert_se(r >= 0);
-                putchar('\n');
-                bus_creds_dump(creds, NULL);
-        }
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-error.c b/src/libsystemd/test-bus-error.c
deleted file mode 100644
index b78be54..0000000
--- a/src/libsystemd/test-bus-error.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-*- 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-bus.h"
-#include "bus-error.h"
-#include "bus-util.h"
-
-int main(int argc, char *argv[]) {
-
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL;
-        const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error");
-        const sd_bus_error temporarily_const_error = {
-                .name = SD_BUS_ERROR_ACCESS_DENIED,
-                .message = "oh! no",
-                ._need_free = -1
-        };
-
-        assert_se(!sd_bus_error_is_set(&error));
-        assert_se(sd_bus_error_set(&error, SD_BUS_ERROR_NOT_SUPPORTED, "xxx") == -ENOTSUP);
-        assert_se(streq(error.name, SD_BUS_ERROR_NOT_SUPPORTED));
-        assert_se(streq(error.message, "xxx"));
-        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_NOT_SUPPORTED));
-        assert_se(sd_bus_error_get_errno(&error) == ENOTSUP);
-        assert_se(sd_bus_error_is_set(&error));
-        sd_bus_error_free(&error);
-
-        assert_se(!sd_bus_error_is_set(&error));
-        assert_se(sd_bus_error_setf(&error, SD_BUS_ERROR_FILE_NOT_FOUND, "yyy %i", -1) == -ENOENT);
-        assert_se(streq(error.name, SD_BUS_ERROR_FILE_NOT_FOUND));
-        assert_se(streq(error.message, "yyy -1"));
-        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND));
-        assert_se(sd_bus_error_get_errno(&error) == ENOENT);
-        assert_se(sd_bus_error_is_set(&error));
-
-        assert_se(!sd_bus_error_is_set(&second));
-        assert_se(second._need_free == 0);
-        assert_se(error._need_free > 0);
-        assert_se(sd_bus_error_copy(&second, &error) == -ENOENT);
-        assert_se(second._need_free > 0);
-        assert_se(streq(error.name, second.name));
-        assert_se(streq(error.message, second.message));
-        assert_se(sd_bus_error_get_errno(&second) == ENOENT);
-        assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_NOT_FOUND));
-        assert_se(sd_bus_error_is_set(&second));
-
-        sd_bus_error_free(&error);
-        sd_bus_error_free(&second);
-
-        assert_se(!sd_bus_error_is_set(&second));
-        assert_se(const_error._need_free == 0);
-        assert_se(sd_bus_error_copy(&second, &const_error) == -EEXIST);
-        assert_se(second._need_free == 0);
-        assert_se(streq(const_error.name, second.name));
-        assert_se(streq(const_error.message, second.message));
-        assert_se(sd_bus_error_get_errno(&second) == EEXIST);
-        assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_EXISTS));
-        assert_se(sd_bus_error_is_set(&second));
-        sd_bus_error_free(&second);
-
-        assert_se(!sd_bus_error_is_set(&second));
-        assert_se(temporarily_const_error._need_free < 0);
-        assert_se(sd_bus_error_copy(&second, &temporarily_const_error) == -EACCES);
-        assert_se(second._need_free > 0);
-        assert_se(streq(temporarily_const_error.name, second.name));
-        assert_se(streq(temporarily_const_error.message, second.message));
-        assert_se(sd_bus_error_get_errno(&second) == EACCES);
-        assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_ACCESS_DENIED));
-        assert_se(sd_bus_error_is_set(&second));
-
-        assert_se(!sd_bus_error_is_set(&error));
-        assert_se(sd_bus_error_set_const(&error, "System.Error.EUCLEAN", "Hallo") == -EUCLEAN);
-        assert_se(streq(error.name, "System.Error.EUCLEAN"));
-        assert_se(streq(error.message, "Hallo"));
-        assert_se(sd_bus_error_has_name(&error, "System.Error.EUCLEAN"));
-        assert_se(sd_bus_error_get_errno(&error) == EUCLEAN);
-        assert_se(sd_bus_error_is_set(&error));
-        sd_bus_error_free(&error);
-
-        assert_se(!sd_bus_error_is_set(&error));
-        assert_se(sd_bus_error_set_errno(&error, EBUSY) == -EBUSY);
-        assert_se(streq(error.name, "System.Error.EBUSY"));
-        assert_se(streq(error.message, strerror(EBUSY)));
-        assert_se(sd_bus_error_has_name(&error, "System.Error.EBUSY"));
-        assert_se(sd_bus_error_get_errno(&error) == EBUSY);
-        assert_se(sd_bus_error_is_set(&error));
-        sd_bus_error_free(&error);
-
-        assert_se(!sd_bus_error_is_set(&error));
-        assert_se(sd_bus_error_set_errnof(&error, EIO, "Waldi %c", 'X') == -EIO);
-        assert_se(streq(error.name, SD_BUS_ERROR_IO_ERROR));
-        assert_se(streq(error.message, "Waldi X"));
-        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR));
-        assert_se(sd_bus_error_get_errno(&error) == EIO);
-        assert_se(sd_bus_error_is_set(&error));
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-gvariant.c b/src/libsystemd/test-bus-gvariant.c
deleted file mode 100644
index cb07c96..0000000
--- a/src/libsystemd/test-bus-gvariant.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*-*- 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/>.
-***/
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
-#include "util.h"
-#include "sd-bus.h"
-#include "bus-gvariant.h"
-#include "bus-util.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-dump.h"
-
-static void test_bus_gvariant_is_fixed_size(void) {
-        assert(bus_gvariant_is_fixed_size("") > 0);
-        assert(bus_gvariant_is_fixed_size("()") > 0);
-        assert(bus_gvariant_is_fixed_size("y") > 0);
-        assert(bus_gvariant_is_fixed_size("u") > 0);
-        assert(bus_gvariant_is_fixed_size("b") > 0);
-        assert(bus_gvariant_is_fixed_size("n") > 0);
-        assert(bus_gvariant_is_fixed_size("q") > 0);
-        assert(bus_gvariant_is_fixed_size("i") > 0);
-        assert(bus_gvariant_is_fixed_size("t") > 0);
-        assert(bus_gvariant_is_fixed_size("d") > 0);
-        assert(bus_gvariant_is_fixed_size("s") == 0);
-        assert(bus_gvariant_is_fixed_size("o") == 0);
-        assert(bus_gvariant_is_fixed_size("g") == 0);
-        assert(bus_gvariant_is_fixed_size("h") > 0);
-        assert(bus_gvariant_is_fixed_size("ay") == 0);
-        assert(bus_gvariant_is_fixed_size("v") == 0);
-        assert(bus_gvariant_is_fixed_size("(u)") > 0);
-        assert(bus_gvariant_is_fixed_size("(uuuuy)") > 0);
-        assert(bus_gvariant_is_fixed_size("(uusuuy)") == 0);
-        assert(bus_gvariant_is_fixed_size("a{ss}") == 0);
-        assert(bus_gvariant_is_fixed_size("((u)yyy(b(iiii)))") > 0);
-        assert(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0);
-}
-
-static void test_bus_gvariant_get_size(void) {
-        assert(bus_gvariant_get_size("") == 0);
-        assert(bus_gvariant_get_size("()") == 0);
-        assert(bus_gvariant_get_size("y") == 1);
-        assert(bus_gvariant_get_size("u") == 4);
-        assert(bus_gvariant_get_size("b") == 1);
-        assert(bus_gvariant_get_size("n") == 2);
-        assert(bus_gvariant_get_size("q") == 2);
-        assert(bus_gvariant_get_size("i") == 4);
-        assert(bus_gvariant_get_size("t") == 8);
-        assert(bus_gvariant_get_size("d") == 8);
-        assert(bus_gvariant_get_size("s") < 0);
-        assert(bus_gvariant_get_size("o") < 0);
-        assert(bus_gvariant_get_size("g") < 0);
-        assert(bus_gvariant_get_size("h") == 4);
-        assert(bus_gvariant_get_size("ay") < 0);
-        assert(bus_gvariant_get_size("v") < 0);
-        assert(bus_gvariant_get_size("(u)") == 4);
-        assert(bus_gvariant_get_size("(uuuuy)") == 20);
-        assert(bus_gvariant_get_size("(uusuuy)") < 0);
-        assert(bus_gvariant_get_size("a{ss}") < 0);
-        assert(bus_gvariant_get_size("((u)yyy(b(iiii)))") == 28);
-        assert(bus_gvariant_get_size("((u)yyy(b(iiivi)))") < 0);
-        assert(bus_gvariant_get_size("((b)(t))") == 16);
-        assert(bus_gvariant_get_size("((b)(b)(t))") == 16);
-        assert(bus_gvariant_get_size("(bt)") == 16);
-        assert(bus_gvariant_get_size("((t)(b))") == 16);
-        assert(bus_gvariant_get_size("(tb)") == 16);
-        assert(bus_gvariant_get_size("((b)(b))") == 2);
-        assert(bus_gvariant_get_size("((t)(t))") == 16);
-}
-
-static void test_bus_gvariant_get_alignment(void) {
-        assert(bus_gvariant_get_alignment("") == 1);
-        assert(bus_gvariant_get_alignment("()") == 1);
-        assert(bus_gvariant_get_alignment("y") == 1);
-        assert(bus_gvariant_get_alignment("b") == 1);
-        assert(bus_gvariant_get_alignment("u") == 4);
-        assert(bus_gvariant_get_alignment("s") == 1);
-        assert(bus_gvariant_get_alignment("o") == 1);
-        assert(bus_gvariant_get_alignment("g") == 1);
-        assert(bus_gvariant_get_alignment("v") == 8);
-        assert(bus_gvariant_get_alignment("h") == 4);
-        assert(bus_gvariant_get_alignment("i") == 4);
-        assert(bus_gvariant_get_alignment("t") == 8);
-        assert(bus_gvariant_get_alignment("x") == 8);
-        assert(bus_gvariant_get_alignment("q") == 2);
-        assert(bus_gvariant_get_alignment("n") == 2);
-        assert(bus_gvariant_get_alignment("d") == 8);
-        assert(bus_gvariant_get_alignment("ay") == 1);
-        assert(bus_gvariant_get_alignment("as") == 1);
-        assert(bus_gvariant_get_alignment("au") == 4);
-        assert(bus_gvariant_get_alignment("an") == 2);
-        assert(bus_gvariant_get_alignment("ans") == 2);
-        assert(bus_gvariant_get_alignment("ant") == 8);
-        assert(bus_gvariant_get_alignment("(ss)") == 1);
-        assert(bus_gvariant_get_alignment("(ssu)") == 4);
-        assert(bus_gvariant_get_alignment("a(ssu)") == 4);
-        assert(bus_gvariant_get_alignment("(u)") == 4);
-        assert(bus_gvariant_get_alignment("(uuuuy)") == 4);
-        assert(bus_gvariant_get_alignment("(uusuuy)") == 4);
-        assert(bus_gvariant_get_alignment("a{ss}") == 1);
-        assert(bus_gvariant_get_alignment("((u)yyy(b(iiii)))") == 4);
-        assert(bus_gvariant_get_alignment("((u)yyy(b(iiivi)))") == 8);
-        assert(bus_gvariant_get_alignment("((b)(t))") == 8);
-        assert(bus_gvariant_get_alignment("((b)(b)(t))") == 8);
-        assert(bus_gvariant_get_alignment("(bt)") == 8);
-        assert(bus_gvariant_get_alignment("((t)(b))") == 8);
-        assert(bus_gvariant_get_alignment("(tb)") == 8);
-        assert(bus_gvariant_get_alignment("((b)(b))") == 1);
-        assert(bus_gvariant_get_alignment("((t)(t))") == 8);
-}
-
-static void test_marshal(void) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL;
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-        _cleanup_free_ void *blob;
-        size_t sz;
-
-        assert_se(sd_bus_open_system(&bus) >= 0);
-        bus->message_version = 2; /* dirty hack to enable gvariant*/
-
-        assert_se(sd_bus_message_new_method_call(bus, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName", &m) >= 0);
-
-        assert_se(sd_bus_message_append(m,
-                                        "a(usv)", 3,
-                                        4711, "first-string-parameter", "(st)", "X", (uint64_t) 1111,
-                                        4712, "second-string-parameter", "(a(si))", 2, "Y", 5, "Z", 6,
-                                        4713, "third-string-parameter", "(uu)", 1, 2) >= 0);
-
-        assert_se(bus_message_seal(m, 4711, 0) >= 0);
-
-#ifdef HAVE_GLIB
-        {
-                GVariant *v;
-                char *t;
-
-#if !defined(GLIB_VERSION_2_36)
-                g_type_init();
-#endif
-
-                v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuuua(yv))"), m->header, sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m), false, NULL, NULL);
-                t = g_variant_print(v, TRUE);
-                printf("%s\n", t);
-                g_free(t);
-                g_variant_unref(v);
-
-                v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, BUS_MESSAGE_BODY_SIZE(m), false, NULL, NULL);
-                t = g_variant_print(v, TRUE);
-                printf("%s\n", t);
-                g_free(t);
-                g_variant_unref(v);
-        }
-#endif
-
-        assert_se(bus_message_dump(m, NULL, true) >= 0);
-
-        assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
-
-        assert_se(bus_message_from_malloc(NULL, blob, sz, NULL, 0, NULL, NULL, &n) >= 0);
-        blob = NULL;
-
-        assert_se(bus_message_dump(n, NULL, true) >= 0);
-
-        m = sd_bus_message_unref(m);
-
-        assert_se(sd_bus_message_new_method_call(bus, "a.x", "/a/x", "a.x", "Ax", &m) >= 0);
-
-        assert_se(sd_bus_message_append(m, "as", 0) >= 0);
-
-        assert_se(bus_message_seal(m, 4712, 0) >= 0);
-        assert_se(bus_message_dump(m, NULL, true) >= 0);
-}
-
-int main(int argc, char *argv[]) {
-
-        test_bus_gvariant_is_fixed_size();
-        test_bus_gvariant_get_size();
-        test_bus_gvariant_get_alignment();
-        test_marshal();
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-introspect.c b/src/libsystemd/test-bus-introspect.c
deleted file mode 100644
index 67b6461..0000000
--- a/src/libsystemd/test-bus-introspect.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*-*- 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 "util.h"
-#include "log.h"
-#include "bus-introspect.h"
-
-static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
-        return -EINVAL;
-}
-
-static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
-        return -EINVAL;
-}
-
-static const sd_bus_vtable vtable[] = {
-        SD_BUS_VTABLE_START(0),
-        SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0),
-        SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED),
-        SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY),
-        SD_BUS_SIGNAL("Wowza", "sss", 0),
-        SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
-        SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0),
-        SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED),
-        SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
-        SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_VTABLE_END
-};
-
-int main(int argc, char *argv[]) {
-        struct introspect intro;
-
-        log_set_max_level(LOG_DEBUG);
-
-        assert_se(introspect_begin(&intro, false) >= 0);
-
-        fprintf(intro.f, " <interface name=\"org.foo\">\n");
-        assert_se(introspect_write_interface(&intro, vtable) >= 0);
-        fputs(" </interface>\n", intro.f);
-
-        fflush(intro.f);
-        fputs(intro.introspection, stdout);
-
-        introspect_free(&intro);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-kernel-benchmark.c b/src/libsystemd/test-bus-kernel-benchmark.c
deleted file mode 100644
index 04627d9..0000000
--- a/src/libsystemd/test-bus-kernel-benchmark.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*-*- 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 <ctype.h>
-#include <sys/wait.h>
-
-#include "util.h"
-#include "log.h"
-#include "time-util.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-error.h"
-#include "bus-kernel.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-
-#define MAX_SIZE (4*1024*1024)
-
-static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
-
-static void server(sd_bus *b, size_t *result) {
-        int r;
-
-        for (;;) {
-                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
-                r = sd_bus_process(b, &m);
-                assert_se(r >= 0);
-
-                if (r == 0)
-                        assert_se(sd_bus_wait(b, (usec_t) -1) >= 0);
-                if (!m)
-                        continue;
-
-                if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping"))
-                        assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
-                else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) {
-                        const void *p;
-                        size_t sz;
-
-                        /* Make sure the mmap is mapped */
-                        assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
-
-                        assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
-                } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
-                        uint64_t res;
-                        assert_se(sd_bus_message_read(m, "t", &res) > 0);
-
-                        *result = res;
-                        return;
-
-                } else
-                        assert_not_reached("Unknown method");
-        }
-}
-
-static void transaction(sd_bus *b, size_t sz) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
-        uint8_t *p;
-
-        assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Work", &m) >= 0);
-        assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
-
-        memset(p, 0x80, sz);
-
-        assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0);
-}
-
-static void client_bisect(const char *address) {
-        _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
-        size_t lsize, rsize, csize;
-        sd_bus *b;
-        int r;
-
-        r = sd_bus_new(&b);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(b, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(b);
-        assert_se(r >= 0);
-
-        assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
-
-        lsize = 1;
-        rsize = MAX_SIZE;
-
-        printf("SIZE\tCOPY\tMEMFD\n");
-
-        for (;;) {
-                usec_t t;
-                unsigned n_copying, n_memfd;
-
-                csize = (lsize + rsize) / 2;
-
-                if (csize <= lsize)
-                        break;
-
-                if (csize <= 0)
-                        break;
-
-                printf("%zu\t", csize);
-
-                b->use_memfd = 0;
-
-                t = now(CLOCK_MONOTONIC);
-                for (n_copying = 0;; n_copying++) {
-                        transaction(b, csize);
-                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
-                                break;
-                }
-                printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
-
-                b->use_memfd = -1;
-
-                t = now(CLOCK_MONOTONIC);
-                for (n_memfd = 0;; n_memfd++) {
-                        transaction(b, csize);
-                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
-                                break;
-                }
-                printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
-
-                if (n_copying == n_memfd)
-                        break;
-
-                if (n_copying > n_memfd)
-                        lsize = csize;
-                else
-                        rsize = csize;
-        }
-
-        b->use_memfd = 1;
-        assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
-        assert_se(sd_bus_message_append(x, "t", csize) >= 0);
-        assert_se(sd_bus_send(b, x, NULL) >= 0);
-
-        sd_bus_unref(b);
-}
-
-static void client_chart(const char *address) {
-        _cleanup_bus_message_unref_ sd_bus_message *x = NULL;
-        size_t csize;
-        sd_bus *b;
-        int r;
-
-        r = sd_bus_new(&b);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(b, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(b);
-        assert_se(r >= 0);
-
-        assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
-
-        printf("SIZE\tCOPY\tMEMFD\n");
-
-        for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
-                usec_t t;
-                unsigned n_copying, n_memfd;
-
-                printf("%zu\t", csize);
-
-                b->use_memfd = 0;
-
-                t = now(CLOCK_MONOTONIC);
-                for (n_copying = 0;; n_copying++) {
-                        transaction(b, csize);
-                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
-                                break;
-                }
-
-                printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
-
-                b->use_memfd = -1;
-
-                t = now(CLOCK_MONOTONIC);
-                for (n_memfd = 0;; n_memfd++) {
-                        transaction(b, csize);
-                        if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
-                                break;
-                }
-
-                printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec));
-        }
-
-        b->use_memfd = 1;
-        assert_se(sd_bus_message_new_method_call(b, ":1.1", "/", "benchmark.server", "Exit", &x) >= 0);
-        assert_se(sd_bus_message_append(x, "t", csize) >= 0);
-        assert_se(sd_bus_send(b, x, NULL) >= 0);
-
-        sd_bus_unref(b);
-}
-
-int main(int argc, char *argv[]) {
-        enum {
-                MODE_BISECT,
-                MODE_CHART,
-        } mode = MODE_BISECT;
-        int i;
-        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
-        _cleanup_close_ int bus_ref = -1;
-        cpu_set_t cpuset;
-        size_t result;
-        sd_bus *b;
-        pid_t pid;
-        int r;
-
-        for (i = 1; i < argc; i++) {
-                if (streq(argv[i], "chart")) {
-                        mode = MODE_CHART;
-                        continue;
-                }
-
-                assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
-        }
-
-        assert_se(arg_loop_usec > 0);
-
-        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
-
-        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
-        if (bus_ref == -ENOENT)
-                exit(EXIT_TEST_SKIP);
-
-        assert_se(bus_ref >= 0);
-
-        address = strappend("kernel:path=", bus_name);
-        assert_se(address);
-
-        r = sd_bus_new(&b);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(b, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(b);
-        assert_se(r >= 0);
-
-        sync();
-        setpriority(PRIO_PROCESS, 0, -19);
-
-        pid = fork();
-        assert_se(pid >= 0);
-
-        if (pid == 0) {
-                CPU_ZERO(&cpuset);
-                CPU_SET(0, &cpuset);
-                pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-
-                close_nointr_nofail(bus_ref);
-                sd_bus_unref(b);
-
-                switch (mode) {
-                case MODE_BISECT:
-                        client_bisect(address);
-                        break;
-
-                case MODE_CHART:
-                        client_chart(address);
-                        break;
-                }
-
-                _exit(0);
-        }
-
-        CPU_ZERO(&cpuset);
-        CPU_SET(1, &cpuset);
-        pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
-
-        server(b, &result);
-
-        if (mode == MODE_BISECT)
-                printf("Copying/memfd are equally fast at %zu bytes\n", result);
-
-        assert_se(waitpid(pid, NULL, 0) == pid);
-
-        sd_bus_unref(b);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-kernel-bloom.c b/src/libsystemd/test-bus-kernel-bloom.c
deleted file mode 100644
index 0ecad18..0000000
--- a/src/libsystemd/test-bus-kernel-bloom.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-*- 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 "util.h"
-#include "log.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-error.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-
-static void test_one(
-                const char *path,
-                const char *interface,
-                const char *member,
-                const char *arg0,
-                const char *match,
-                bool good) {
-
-        _cleanup_close_ int bus_ref = -1;
-        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        sd_bus *a, *b;
-        int r;
-
-        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
-
-        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
-        if (bus_ref == -ENOENT)
-                exit(EXIT_TEST_SKIP);
-
-        assert_se(bus_ref >= 0);
-
-        address = strappend("kernel:path=", bus_name);
-        assert_se(address);
-
-        r = sd_bus_new(&a);
-        assert_se(r >= 0);
-
-        r = sd_bus_new(&b);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(a, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(b, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(a);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(b);
-        assert_se(r >= 0);
-
-        log_debug("match");
-        r = sd_bus_add_match(b, match, NULL, NULL);
-        assert_se(r >= 0);
-
-        log_debug("signal");
-        r = sd_bus_emit_signal(a, path, interface, member, "s", arg0);
-        assert_se(r >= 0);
-
-        r = sd_bus_process(b, &m);
-        assert_se(r >= 0 && (good == !!m));
-
-        sd_bus_unref(a);
-        sd_bus_unref(b);
-}
-
-int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/tuut'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "interface='waldo.com'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Piep'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Pi_ep'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foobar'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foo_bar'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
-
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/quux'", false);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar/waldo'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/'", true);
-        test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/quux'", false);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-kernel.c b/src/libsystemd/test-bus-kernel.c
deleted file mode 100644
index 9b17a35..0000000
--- a/src/libsystemd/test-bus-kernel.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*-*- 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 <fcntl.h>
-
-#include "util.h"
-#include "log.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-error.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-
-int main(int argc, char *argv[]) {
-        _cleanup_close_ int bus_ref = -1;
-        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *ua = NULL, *ub = NULL, *the_string = NULL;
-        sd_bus *a, *b;
-        int r, pipe_fds[2];
-
-        log_set_max_level(LOG_DEBUG);
-
-        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
-
-        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
-        if (bus_ref == -ENOENT)
-                return EXIT_TEST_SKIP;
-
-        assert_se(bus_ref >= 0);
-
-        address = strappend("kernel:path=", bus_name);
-        assert_se(address);
-
-        r = sd_bus_new(&a);
-        assert_se(r >= 0);
-
-        r = sd_bus_new(&b);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(a, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(b, address);
-        assert_se(r >= 0);
-
-        assert_se(sd_bus_negotiate_attach_timestamp(a, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_creds(a, _SD_BUS_CREDS_ALL) >= 0);
-
-        assert_se(sd_bus_negotiate_attach_timestamp(b, 1) >= 0);
-        assert_se(sd_bus_negotiate_attach_creds(b, _SD_BUS_CREDS_ALL) >= 0);
-
-        r = sd_bus_start(a);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(b);
-        assert_se(r >= 0);
-
-        r = sd_bus_get_unique_name(a, &ua);
-        assert_se(r >= 0);
-
-        printf("unique a: %s\n", ua);
-
-        r = sd_bus_get_unique_name(b, &ub);
-        assert_se(r >= 0);
-
-        printf("unique b: %s\n", ub);
-
-        r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay");
-        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
-        assert_se(r == -EHOSTUNREACH);
-
-        r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL);
-        assert_se(r >= 0);
-
-        r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name");
-        assert_se(r >= 0);
-
-        r = sd_bus_try_close(b);
-        assert_se(r == -EBUSY);
-
-        r = sd_bus_process(b, &m);
-        assert_se(r > 0);
-        assert_se(m);
-
-        bus_message_dump(m, stdout, true);
-        assert_se(sd_bus_message_rewind(m, true) >= 0);
-
-        r = sd_bus_message_read(m, "s", &the_string);
-        assert_se(r >= 0);
-        assert_se(streq(the_string, "I am a string"));
-
-        sd_bus_message_unref(m);
-        m = NULL;
-
-        r = sd_bus_request_name(a, "net.x0pointer.foobar", 0);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_new_method_call(b, "net.x0pointer.foobar", "/a/path", "an.inter.face", "AMethod", &m);
-        assert_se(r >= 0);
-
-        assert_se(pipe2(pipe_fds, O_CLOEXEC) >= 0);
-
-        assert_se(write(pipe_fds[1], "x", 1) == 1);
-
-        close_nointr_nofail(pipe_fds[1]);
-        pipe_fds[1] = -1;
-
-        r = sd_bus_message_append(m, "h", pipe_fds[0]);
-        assert_se(r >= 0);
-
-        close_nointr_nofail(pipe_fds[0]);
-        pipe_fds[0] = -1;
-
-        r = sd_bus_send(b, m, NULL);
-        assert_se(r >= 0);
-
-        for (;;) {
-                sd_bus_message_unref(m);
-                m = NULL;
-                r = sd_bus_process(a, &m);
-                assert_se(r > 0);
-                assert_se(m);
-
-                bus_message_dump(m, stdout, true);
-                assert_se(sd_bus_message_rewind(m, true) >= 0);
-
-                if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) {
-                        int fd;
-                        char x;
-
-                        r = sd_bus_message_read(m, "h", &fd);
-                        assert_se(r >= 0);
-
-                        assert_se(read(fd, &x, 1) == 1);
-                        assert_se(x == 'x');
-                        break;
-                }
-        }
-
-        r = sd_bus_release_name(a, "net.x0pointer.foobar");
-        assert_se(r >= 0);
-
-        r = sd_bus_release_name(a, "net.x0pointer.foobar");
-        assert_se(r == -ESRCH);
-
-        r = sd_bus_try_close(a);
-        assert_se(r >= 0);
-
-        sd_bus_unref(a);
-        sd_bus_unref(b);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-marshal.c b/src/libsystemd/test-bus-marshal.c
deleted file mode 100644
index 4fad049..0000000
--- a/src/libsystemd/test-bus-marshal.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*-*- 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 <assert.h>
-#include <stdlib.h>
-#include <byteswap.h>
-
-#ifdef HAVE_GLIB
-#include <gio/gio.h>
-#endif
-
-#ifdef HAVE_DBUS
-#include <dbus/dbus.h>
-#endif
-
-#include "log.h"
-#include "util.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-
-static void test_bus_label_escape_one(const char *a, const char *b) {
-        _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
-
-        assert_se(t = sd_bus_label_escape(a));
-        assert_se(streq(t, b));
-
-        assert_se(x = sd_bus_label_unescape(t));
-        assert_se(streq(a, x));
-
-        assert_se(y = sd_bus_label_unescape(b));
-        assert_se(streq(a, y));
-}
-
-static void test_bus_label_escape(void) {
-        test_bus_label_escape_one("foo123bar", "foo123bar");
-        test_bus_label_escape_one("foo.bar", "foo_2ebar");
-        test_bus_label_escape_one("foo_2ebar", "foo_5f2ebar");
-        test_bus_label_escape_one("", "_");
-        test_bus_label_escape_one("_", "_5f");
-        test_bus_label_escape_one("1", "_31");
-        test_bus_label_escape_one(":1", "_3a1");
-}
-
-int main(int argc, char *argv[]) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *copy = NULL;
-        int r, boolean;
-        const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature;
-        uint8_t u, v;
-        void *buffer = NULL;
-        size_t sz;
-        char *h;
-        const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
-        char *s;
-        _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
-        _cleanup_fclose_ FILE *ms = NULL;
-        size_t first_size = 0, second_size = 0, third_size = 0;
-
-        r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &m);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "s", "a string");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "s", NULL);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "asg", 2, "string #1", "string #2", "sba(tt)ss");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_open_container(m, 'a', "s");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append_basic(m, 's', "foobar");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append_basic(m, 's', "waldo");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_close_container(m);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append_string_space(m, 5, &s);
-        assert_se(r >= 0);
-        strcpy(s, "hallo");
-
-        r = sd_bus_message_append_array(m, 'i', integer_array, sizeof(integer_array));
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append_array(m, 'u', NULL, 0);
-        assert_se(r >= 0);
-
-        r = bus_message_seal(m, 4711, 0);
-        assert_se(r >= 0);
-
-        bus_message_dump(m, stdout, true);
-
-        ms = open_memstream(&first, &first_size);
-        bus_message_dump(m, ms, false);
-        fflush(ms);
-        assert_se(!ferror(ms));
-
-        r = bus_message_get_blob(m, &buffer, &sz);
-        assert_se(r >= 0);
-
-        h = hexmem(buffer, sz);
-        assert_se(h);
-
-        log_info("message size = %lu, contents =\n%s", (unsigned long) sz, h);
-        free(h);
-
-#ifdef HAVE_GLIB
-        {
-                GDBusMessage *g;
-                char *p;
-
-#if !defined(GLIB_VERSION_2_36)
-                g_type_init();
-#endif
-
-                g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL);
-                p = g_dbus_message_print(g, 0);
-                log_info("%s", p);
-                g_free(p);
-                g_object_unref(g);
-        }
-#endif
-
-#ifdef HAVE_DBUS
-        {
-                DBusMessage *w;
-                DBusError error;
-
-                dbus_error_init(&error);
-
-                w = dbus_message_demarshal(buffer, sz, &error);
-                if (!w)
-                        log_error("%s", error.message);
-                else
-                        dbus_message_unref(w);
-        }
-#endif
-
-        m = sd_bus_message_unref(m);
-
-        r = bus_message_from_malloc(NULL, buffer, sz, NULL, 0, NULL, NULL, &m);
-        assert_se(r >= 0);
-
-        bus_message_dump(m, stdout, true);
-
-        fclose(ms);
-        ms = open_memstream(&second, &second_size);
-        bus_message_dump(m, ms, false);
-        fflush(ms);
-        assert_se(!ferror(ms));
-        assert_se(first_size == second_size);
-        assert_se(memcmp(first, second, first_size) == 0);
-
-        assert_se(sd_bus_message_rewind(m, true) >= 0);
-
-        r = sd_bus_message_read(m, "ssasg", &x, &x2, 2, &y, &z, &a_signature);
-        assert_se(r > 0);
-        assert_se(streq(x, "a string"));
-        assert_se(streq(x2, ""));
-        assert_se(streq(y, "string #1"));
-        assert_se(streq(z, "string #2"));
-        assert_se(streq(a_signature, "sba(tt)ss"));
-
-        r = sd_bus_message_read(m, "sass", &x, 5, &y, &z, &a, &b, &c, &d);
-        assert_se(r > 0);
-        assert_se(streq(x, "foobar"));
-        assert_se(streq(y, "foo"));
-        assert_se(streq(z, "bar"));
-        assert_se(streq(a, "waldo"));
-        assert_se(streq(b, "piep"));
-        assert_se(streq(c, "pap"));
-        assert_se(streq(d, "after"));
-
-        r = sd_bus_message_read(m, "a{yv}", 2, &u, "s", &x, &v, "s", &y);
-        assert_se(r > 0);
-        assert_se(u == 3);
-        assert_se(streq(x, "foo"));
-        assert_se(v == 5);
-        assert_se(streq(y, "waldo"));
-
-        r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
-        assert_se(r > 0);
-        assert_se(boolean);
-        assert_se(streq(x, "aaa"));
-        assert_se(streq(y, "1"));
-        assert_se(streq(a, "bbb"));
-        assert_se(streq(b, "2"));
-        assert_se(streq(c, "ccc"));
-        assert_se(streq(d, "3"));
-
-        assert_se(sd_bus_message_verify_type(m, 'a', "s") > 0);
-
-        r = sd_bus_message_read(m, "as", 2, &x, &y);
-        assert_se(r > 0);
-        assert_se(streq(x, "foobar"));
-        assert_se(streq(y, "waldo"));
-
-        r = sd_bus_message_read_basic(m, 's', &s);
-        assert_se(r > 0);
-        assert_se(streq(s, "hallo"));
-
-        r = sd_bus_message_read_array(m, 'i', (const void**) &return_array, &sz);
-        assert_se(r > 0);
-        assert_se(sz == sizeof(integer_array));
-        assert_se(memcmp(integer_array, return_array, sz) == 0);
-
-        r = sd_bus_message_read_array(m, 'u', (const void**) &return_array, &sz);
-        assert_se(r > 0);
-        assert_se(sz == 0);
-
-        r = sd_bus_message_peek_type(m, NULL, NULL);
-        assert_se(r == 0);
-
-        r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &copy);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_rewind(m, true);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_copy(copy, m, true);
-        assert_se(r >= 0);
-
-        r = bus_message_seal(copy, 4712, 0);
-        assert_se(r >= 0);
-
-        fclose(ms);
-        ms = open_memstream(&third, &third_size);
-        bus_message_dump(copy, ms, false);
-        fflush(ms);
-        assert_se(!ferror(ms));
-
-        printf("<%.*s>\n", (int) first_size, first);
-        printf("<%.*s>\n", (int) third_size, third);
-
-        assert_se(first_size == third_size);
-        assert_se(memcmp(first, third, third_size) == 0);
-
-        r = sd_bus_message_rewind(m, true);
-        assert_se(r >= 0);
-
-        assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
-
-        r = sd_bus_message_skip(m, "ssasg");
-        assert_se(r > 0);
-
-        assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
-
-        r = sd_bus_message_skip(m, "sass");
-        assert_se(r >= 0);
-
-        assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
-
-        r = sd_bus_message_skip(m, "a{yv}");
-        assert_se(r >= 0);
-
-        assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);
-
-        r = sd_bus_message_read(m, "b", &boolean);
-        assert_se(r > 0);
-        assert_se(boolean);
-
-        r = sd_bus_message_enter_container(m, 0, NULL);
-        assert_se(r > 0);
-
-        r = sd_bus_message_read(m, "(ss)", &x, &y);
-        assert_se(r > 0);
-
-        r = sd_bus_message_read(m, "(ss)", &a, &b);
-        assert_se(r > 0);
-
-        r = sd_bus_message_read(m, "(ss)", &c, &d);
-        assert_se(r > 0);
-
-        r = sd_bus_message_read(m, "(ss)", &x, &y);
-        assert_se(r == 0);
-
-        r = sd_bus_message_exit_container(m);
-        assert_se(r >= 0);
-
-        assert_se(streq(x, "aaa"));
-        assert_se(streq(y, "1"));
-        assert_se(streq(a, "bbb"));
-        assert_se(streq(b, "2"));
-        assert_se(streq(c, "ccc"));
-        assert_se(streq(d, "3"));
-
-        test_bus_label_escape();
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-match.c b/src/libsystemd/test-bus-match.c
deleted file mode 100644
index 7227e25..0000000
--- a/src/libsystemd/test-bus-match.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*-*- 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 <assert.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-
-#include "bus-match.h"
-#include "bus-message.h"
-#include "bus-util.h"
-
-static bool mask[32];
-
-static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        log_info("Ran %i", PTR_TO_INT(userdata));
-        mask[PTR_TO_INT(userdata)] = true;
-        return 0;
-}
-
-static bool mask_contains(unsigned a[], unsigned n) {
-        unsigned i, j;
-
-        for (i = 0; i < ELEMENTSOF(mask); i++) {
-                bool found = false;
-
-                for (j = 0; j < n; j++)
-                        if (a[j] == i) {
-                                found = true;
-                                break;
-                        }
-
-                if (found != mask[i])
-                        return false;
-        }
-
-        return true;
-}
-
-static int match_add(struct bus_match_node *root, const char *match, int value) {
-        struct bus_match_component *components = NULL;
-        unsigned n_components = 0;
-        int r;
-
-        r = bus_match_parse(match, &components, &n_components);
-        if (r < 0)
-                return r;
-
-        r = bus_match_add(root, components, n_components, filter, INT_TO_PTR(value), 0, NULL);
-        bus_match_parse_free(components, n_components);
-
-        return r;
-}
-
-static int match_remove(struct bus_match_node *root, const char *match, int value) {
-        struct bus_match_component *components = NULL;
-        unsigned n_components = 0;
-        int r;
-
-        r = bus_match_parse(match, &components, &n_components);
-        if (r < 0)
-                return r;
-
-        r = bus_match_remove(root, components, n_components, filter, INT_TO_PTR(value), 0);
-        bus_match_parse_free(components, n_components);
-
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        struct bus_match_node root;
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        enum bus_match_node_type i;
-
-        zero(root);
-        root.type = BUS_MATCH_ROOT;
-
-        assert_se(match_add(&root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
-        assert_se(match_add(&root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
-        assert_se(match_add(&root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
-        assert_se(match_add(&root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
-        assert_se(match_add(&root, "", 5) >= 0);
-        assert_se(match_add(&root, "interface='quux.x'", 6) >= 0);
-        assert_se(match_add(&root, "interface='bar.x'", 7) >= 0);
-        assert_se(match_add(&root, "member='waldo',path='/foo/bar'", 8) >= 0);
-        assert_se(match_add(&root, "path='/foo/bar'", 9) >= 0);
-        assert_se(match_add(&root, "path_namespace='/foo'", 10) >= 0);
-        assert_se(match_add(&root, "path_namespace='/foo/quux'", 11) >= 0);
-        assert_se(match_add(&root, "arg1='two'", 12) >= 0);
-        assert_se(match_add(&root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
-        assert_se(match_add(&root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
-
-        bus_match_dump(&root, 0);
-
-        assert_se(sd_bus_message_new_signal(NULL, "/foo/bar", "bar.x", "waldo", &m) >= 0);
-        assert_se(sd_bus_message_append(m, "ssss", "one", "two", "/prefix/three", "prefix.four") >= 0);
-        assert_se(bus_message_seal(m, 1, 0) >= 0);
-
-        zero(mask);
-        assert_se(bus_match_run(NULL, &root, m) == 0);
-        assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
-
-        assert_se(match_remove(&root, "member='waldo',path='/foo/bar'", 8) > 0);
-        assert_se(match_remove(&root, "arg2path='/prefix/',member='waldo'", 13) > 0);
-        assert_se(match_remove(&root, "interface='bar.xx'", 7) == 0);
-
-        bus_match_dump(&root, 0);
-
-        zero(mask);
-        assert_se(bus_match_run(NULL, &root, m) == 0);
-        assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7 }, 6));
-
-        for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
-                char buf[32];
-                const char *x;
-
-                assert_se(x = bus_match_node_type_to_string(i, buf, sizeof(buf)));
-
-                if (i >= BUS_MATCH_MESSAGE_TYPE)
-                        assert_se(bus_match_node_type_from_string(x, strlen(x)) == i);
-        }
-
-        bus_match_free(&root);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-memfd.c b/src/libsystemd/test-bus-memfd.c
deleted file mode 100644
index b9d6a25..0000000
--- a/src/libsystemd/test-bus-memfd.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*-*- 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 <sys/mman.h>
-#include <sys/uio.h>
-
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-
-#include "sd-memfd.h"
-
-int main(int argc, char *argv[]) {
-        sd_memfd *m;
-        char *s;
-        uint64_t sz;
-        int r, fd;
-        FILE *f;
-        char buf[3] = {};
-        struct iovec iov[3] = {};
-        char bufv[3][3] = {};
-
-        log_set_max_level(LOG_DEBUG);
-
-        r = sd_memfd_new(&m);
-        if (r == -ENOENT)
-                return EXIT_TEST_SKIP;
-
-        r = sd_memfd_map(m, 0, 12, (void**) &s);
-        assert_se(r >= 0);
-
-        strcpy(s, "----- world");
-
-        r = sd_memfd_set_sealed(m, 1);
-        assert_se(r == -ETXTBSY);
-
-        assert_se(write(sd_memfd_get_fd(m), "he", 2) == 2);
-        assert_se(write(sd_memfd_get_fd(m), "XXX", 3) == 3);
-        assert_se(streq(s, "heXXX world"));
-
-        /* fix "hello" */
-        assert_se(lseek(sd_memfd_get_fd(m), 2, SEEK_SET) == 2);
-        assert_se(write(sd_memfd_get_fd(m), "ll", 2) == 2);
-
-        assert_se(sd_memfd_get_file(m, &f) >= 0);
-        fputc('o', f);
-        fflush(f);
-
-        /* check content  */
-        assert_se(streq(s, "hello world"));
-
-        assert_se(munmap(s, 12) == 0);
-
-        r = sd_memfd_get_sealed(m);
-        assert_se(r == 0);
-
-        r = sd_memfd_get_size(m, &sz);
-        assert_se(r >= 0);
-        assert_se(sz = page_size());
-
-        /* truncate it */
-        r = sd_memfd_set_size(m, 6);
-        assert_se(r >= 0);
-
-        /* get back new value */
-        r = sd_memfd_get_size(m, &sz);
-        assert_se(r >= 0);
-        assert_se(sz == 6);
-
-        r = sd_memfd_set_sealed(m, 1);
-        assert_se(r >= 0);
-
-        r = sd_memfd_get_sealed(m);
-        assert_se(r == 1);
-
-        fd = sd_memfd_dup_fd(m);
-        assert_se(fd >= 0);
-
-        sd_memfd_free(m);
-
-        /* new sd_memfd, same underlying memfd */
-        r = sd_memfd_make(fd, &m);
-        assert_se(r >= 0);
-
-        /* we did truncate it to 6 */
-        r = sd_memfd_get_size(m, &sz);
-        assert_se(r >= 0 && sz == 6);
-
-        /* map it, check content */
-        r = sd_memfd_map(m, 0, 12, (void **)&s);
-        assert_se(r >= 0);
-
-        /* we only see the truncated size */
-        assert_se(streq(s, "hello "));
-
-        /* it was already sealed */
-        r = sd_memfd_set_sealed(m, 1);
-        assert_se(r == -EALREADY);
-
-        /* we cannot break the seal, it is mapped */
-        r = sd_memfd_set_sealed(m, 0);
-        assert_se(r == -ETXTBSY);
-
-        /* unmap it; become the single owner */
-        assert_se(munmap(s, 12) == 0);
-
-        /* now we can do flip the sealing */
-        r = sd_memfd_set_sealed(m, 0);
-        assert_se(r == 0);
-        r = sd_memfd_get_sealed(m);
-        assert_se(r == 0);
-
-        r = sd_memfd_set_sealed(m, 1);
-        assert_se(r == 0);
-        r = sd_memfd_get_sealed(m);
-        assert_se(r == 1);
-
-        r = sd_memfd_set_sealed(m, 0);
-        assert_se(r == 0);
-        r = sd_memfd_get_sealed(m);
-        assert_se(r == 0);
-
-        /* seek at 2, read() 2 bytes */
-        assert_se(lseek(fd, 2, SEEK_SET) == 2);
-        assert_se(read(fd, buf, 2) == 2);
-
-        /* check content */
-        assert_se(memcmp(buf, "ll", 2) == 0);
-
-        /* writev it out*/
-        iov[0].iov_base = (char *)"ABC";
-        iov[0].iov_len = 3;
-        iov[1].iov_base = (char *)"DEF";
-        iov[1].iov_len = 3;
-        iov[2].iov_base = (char *)"GHI";
-        iov[2].iov_len = 3;
-        assert_se(pwritev(fd, iov, 3, 0) == 9);
-
-        /* readv it back */
-        iov[0].iov_base = bufv[0];
-        iov[0].iov_len = 3;
-        iov[1].iov_base = bufv[1];
-        iov[1].iov_len = 3;
-        iov[2].iov_base = bufv[2];
-        iov[2].iov_len = 3;
-        assert_se(preadv(fd, iov, 3, 0) == 9);
-
-        /* check content */
-        assert_se(memcmp(bufv[0], "ABC", 3) == 0);
-        assert_se(memcmp(bufv[1], "DEF", 3) == 0);
-        assert_se(memcmp(bufv[2], "GHI", 3) == 0);
-
-        sd_memfd_free(m);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-objects.c b/src/libsystemd/test-bus-objects.c
deleted file mode 100644
index e2423c7..0000000
--- a/src/libsystemd/test-bus-objects.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*-*- 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 <assert.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-
-#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-
-struct context {
-        int fds[2];
-        bool quit;
-        char *something;
-        char *automatic_string_property;
-        uint32_t automatic_integer_property;
-};
-
-static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        struct context *c = userdata;
-        const char *s;
-        char *n = NULL;
-        int r;
-
-        r = sd_bus_message_read(m, "s", &s);
-        assert_se(r > 0);
-
-        n = strjoin("<<<", s, ">>>", NULL);
-        assert_se(n);
-
-        free(c->something);
-        c->something = n;
-
-        log_info("AlterSomething() called, got %s, returning %s", s, n);
-
-        /* This should fail, since the return type doesn't match */
-        assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
-
-        r = sd_bus_reply_method_return(m, "s", n);
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        struct context *c = userdata;
-        int r;
-
-        c->quit = true;
-
-        log_info("Exit called");
-
-        r = sd_bus_reply_method_return(m, "");
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
-        struct context *c = userdata;
-        int r;
-
-        log_info("property get for %s called, returning \"%s\".", property, c->something);
-
-        r = sd_bus_message_append(reply, "s", c->something);
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
-        struct context *c = userdata;
-        const char *s;
-        char *n;
-        int r;
-
-        log_info("property set for %s called", property);
-
-        r = sd_bus_message_read(value, "s", &s);
-        assert_se(r >= 0);
-
-        n = strdup(s);
-        assert_se(n);
-
-        free(c->something);
-        c->something = n;
-
-        return 1;
-}
-
-static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ char *s = NULL;
-        const char *x;
-        int r;
-
-        assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
-        r = sd_bus_message_append(reply, "s", s);
-        assert_se(r >= 0);
-
-        assert_se(x = startswith(path, "/value/"));
-
-        assert_se(PTR_TO_UINT(userdata) == 30);
-
-        return 1;
-}
-
-static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        int r;
-
-        assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
-
-        r = sd_bus_reply_method_return(m, NULL);
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        int r;
-
-        assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
-
-        r = sd_bus_reply_method_return(m, NULL);
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        int r;
-
-        assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
-
-        r = sd_bus_reply_method_return(m, NULL);
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        int r;
-
-        assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
-
-        r = sd_bus_reply_method_return(m, NULL);
-        assert_se(r >= 0);
-
-        return 1;
-}
-
-static const sd_bus_vtable vtable[] = {
-        SD_BUS_VTABLE_START(0),
-        SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
-        SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
-        SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
-        SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
-        SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
-        SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
-        SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
-        SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
-        SD_BUS_VTABLE_END
-};
-
-static const sd_bus_vtable vtable2[] = {
-        SD_BUS_VTABLE_START(0),
-        SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
-        SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
-        SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
-        SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
-        SD_BUS_VTABLE_END
-};
-
-static int enumerator_callback(sd_bus *b, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-
-        if (object_path_startswith("/value", path))
-                assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
-
-        return 1;
-}
-
-static void *server(void *p) {
-        struct context *c = p;
-        sd_bus *bus = NULL;
-        sd_id128_t id;
-        int r;
-
-        c->quit = false;
-
-        assert_se(sd_id128_randomize(&id) >= 0);
-
-        assert_se(sd_bus_new(&bus) >= 0);
-        assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
-        assert_se(sd_bus_set_server(bus, 1, id) >= 0);
-
-        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
-        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
-        assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
-        assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
-        assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
-
-        assert_se(sd_bus_start(bus) >= 0);
-
-        log_error("Entering event loop on server");
-
-        while (!c->quit) {
-                log_error("Loop!");
-
-                r = sd_bus_process(bus, NULL);
-                if (r < 0) {
-                        log_error("Failed to process requests: %s", strerror(-r));
-                        goto fail;
-                }
-
-                if (r == 0) {
-                        r = sd_bus_wait(bus, (uint64_t) -1);
-                        if (r < 0) {
-                                log_error("Failed to wait: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        continue;
-                }
-        }
-
-        r = 0;
-
-fail:
-        if (bus) {
-                sd_bus_flush(bus);
-                sd_bus_unref(bus);
-        }
-
-        return INT_TO_PTR(r);
-}
-
-static int client(struct context *c) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *s;
-        int r;
-
-        assert_se(sd_bus_new(&bus) >= 0);
-        assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
-        assert_se(sd_bus_start(bus) >= 0);
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
-        assert_se(r >= 0);
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        assert_se(streq(s, "<<<hallo>>>"));
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        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, 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, SD_BUS_ERROR_INVALID_ARGS));
-
-        sd_bus_error_free(&error);
-
-        r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        assert_se(streq(s, "<<<hallo>>>"));
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
-        assert_se(r >= 0);
-
-        r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        assert_se(streq(s, "test"));
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
-        assert_se(r >= 0);
-
-        assert_se(c->automatic_integer_property == 815);
-
-        r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
-        assert_se(r >= 0);
-
-        assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        fputs(s, stdout);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        log_info("read %s", s);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        fputs(s, stdout);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        fputs(s, stdout);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_read(reply, "s", &s);
-        assert_se(r >= 0);
-        fputs(s, stdout);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
-        assert_se(r >= 0);
-
-        bus_message_dump(reply, stdout, true);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        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, 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, 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, "");
-        assert_se(r >= 0);
-
-        bus_message_dump(reply, stdout, true);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_process(bus, &reply);
-        assert_se(r > 0);
-
-        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
-        bus_message_dump(reply, stdout, true);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_process(bus, &reply);
-        assert_se(r > 0);
-
-        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
-        bus_message_dump(reply, stdout, true);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_process(bus, &reply);
-        assert_se(r > 0);
-
-        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
-        bus_message_dump(reply, stdout, true);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
-        assert_se(r >= 0);
-
-        r = sd_bus_process(bus, &reply);
-        assert_se(r > 0);
-
-        assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
-        bus_message_dump(reply, stdout, true);
-
-        sd_bus_message_unref(reply);
-        reply = NULL;
-
-        r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
-        assert_se(r >= 0);
-
-        sd_bus_flush(bus);
-
-        return 0;
-}
-
-int main(int argc, char *argv[]) {
-        struct context c = {};
-        pthread_t s;
-        void *p;
-        int r, q;
-
-        zero(c);
-
-        c.automatic_integer_property = 4711;
-        assert_se(c.automatic_string_property = strdup("dudeldu"));
-
-        assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
-
-        r = pthread_create(&s, NULL, server, &c);
-        if (r != 0)
-                return -r;
-
-        r = client(&c);
-
-        q = pthread_join(s, &p);
-        if (q != 0)
-                return -q;
-
-        if (r < 0)
-                return r;
-
-        if (PTR_TO_INT(p) < 0)
-                return PTR_TO_INT(p);
-
-        free(c.something);
-        free(c.automatic_string_property);
-
-        return EXIT_SUCCESS;
-}
diff --git a/src/libsystemd/test-bus-server.c b/src/libsystemd/test-bus-server.c
deleted file mode 100644
index 0e65ee7..0000000
--- a/src/libsystemd/test-bus-server.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*-*- 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 <assert.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-
-#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.h"
-
-struct context {
-        int fds[2];
-
-        bool client_negotiate_unix_fds;
-        bool server_negotiate_unix_fds;
-
-        bool client_anonymous_auth;
-        bool server_anonymous_auth;
-};
-
-static void *server(void *p) {
-        struct context *c = p;
-        sd_bus *bus = NULL;
-        sd_id128_t id;
-        bool quit = false;
-        int r;
-
-        assert_se(sd_id128_randomize(&id) >= 0);
-
-        assert_se(sd_bus_new(&bus) >= 0);
-        assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
-        assert_se(sd_bus_set_server(bus, 1, id) >= 0);
-        assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0);
-        assert_se(sd_bus_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0);
-        assert_se(sd_bus_start(bus) >= 0);
-
-        while (!quit) {
-                _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
-
-                r = sd_bus_process(bus, &m);
-                if (r < 0) {
-                        log_error("Failed to process requests: %s", strerror(-r));
-                        goto fail;
-                }
-
-                if (r == 0) {
-                        r = sd_bus_wait(bus, (uint64_t) -1);
-                        if (r < 0) {
-                                log_error("Failed to wait: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        continue;
-                }
-
-                if (!m)
-                        continue;
-
-                log_info("Got message! member=%s", strna(sd_bus_message_get_member(m)));
-
-                if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) {
-
-                        assert_se((sd_bus_can_send(bus, 'h') >= 1) == (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds));
-
-                        r = sd_bus_message_new_method_return(m, &reply);
-                        if (r < 0) {
-                                log_error("Failed to allocate return: %s", strerror(-r));
-                                goto fail;
-                        }
-
-                        quit = true;
-
-                } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
-                        r = sd_bus_message_new_method_error(
-                                        m,
-                                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."),
-                                        &reply);
-                        if (r < 0) {
-                                log_error("Failed to allocate return: %s", strerror(-r));
-                                goto fail;
-                        }
-                }
-
-                if (reply) {
-                        r = sd_bus_send(bus, reply, NULL);
-                        if (r < 0) {
-                                log_error("Failed to send reply: %s", strerror(-r));
-                                goto fail;
-                        }
-                }
-        }
-
-        r = 0;
-
-fail:
-        if (bus) {
-                sd_bus_flush(bus);
-                sd_bus_unref(bus);
-        }
-
-        return INT_TO_PTR(r);
-}
-
-static int client(struct context *c) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
-        sd_bus_error error = SD_BUS_ERROR_NULL;
-        int r;
-
-        assert_se(sd_bus_new(&bus) >= 0);
-        assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
-        assert_se(sd_bus_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0);
-        assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0);
-        assert_se(sd_bus_start(bus) >= 0);
-
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        "org.freedesktop.systemd.test",
-                        "/",
-                        "org.freedesktop.systemd.test",
-                        "Exit",
-                        &m);
-        if (r < 0) {
-                log_error("Failed to allocate method call: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_bus_call(bus, m, 0, &error, &reply);
-        if (r < 0) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
-                return r;
-        }
-
-        return 0;
-}
-
-static int test_one(bool client_negotiate_unix_fds, bool server_negotiate_unix_fds,
-                    bool client_anonymous_auth, bool server_anonymous_auth) {
-
-        struct context c;
-        pthread_t s;
-        void *p;
-        int r, q;
-
-        zero(c);
-
-        assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
-
-        c.client_negotiate_unix_fds = client_negotiate_unix_fds;
-        c.server_negotiate_unix_fds = server_negotiate_unix_fds;
-        c.client_anonymous_auth = client_anonymous_auth;
-        c.server_anonymous_auth = server_anonymous_auth;
-
-        r = pthread_create(&s, NULL, server, &c);
-        if (r != 0)
-                return -r;
-
-        r = client(&c);
-
-        q = pthread_join(s, &p);
-        if (q != 0)
-                return -q;
-
-        if (r < 0)
-                return r;
-
-        if (PTR_TO_INT(p) < 0)
-                return PTR_TO_INT(p);
-
-        return 0;
-}
-
-int main(int argc, char *argv[]) {
-        int r;
-
-        r = test_one(true, true, false, false);
-        assert_se(r >= 0);
-
-        r = test_one(true, false, false, false);
-        assert_se(r >= 0);
-
-        r = test_one(false, true, false, false);
-        assert_se(r >= 0);
-
-        r = test_one(false, false, false, false);
-        assert_se(r >= 0);
-
-        r = test_one(true, true, true, true);
-        assert_se(r >= 0);
-
-        r = test_one(true, true, false, true);
-        assert_se(r >= 0);
-
-        r = test_one(true, true, true, false);
-        assert_se(r == -EPERM);
-
-        return EXIT_SUCCESS;
-}
diff --git a/src/libsystemd/test-bus-signature.c b/src/libsystemd/test-bus-signature.c
deleted file mode 100644
index 3fc565c..0000000
--- a/src/libsystemd/test-bus-signature.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*-*- 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 <assert.h>
-#include <stdlib.h>
-
-#include "log.h"
-#include "bus-signature.h"
-#include "bus-internal.h"
-
-int main(int argc, char *argv[]) {
-        char prefix[256];
-        int r;
-
-        assert_se(signature_is_single("y", false));
-        assert_se(signature_is_single("u", false));
-        assert_se(signature_is_single("v", false));
-        assert_se(signature_is_single("as", false));
-        assert_se(signature_is_single("(ss)", false));
-        assert_se(signature_is_single("()", false));
-        assert_se(signature_is_single("(()()()()())", false));
-        assert_se(signature_is_single("(((())))", false));
-        assert_se(signature_is_single("((((s))))", false));
-        assert_se(signature_is_single("{ss}", true));
-        assert_se(signature_is_single("a{ss}", false));
-        assert_se(!signature_is_single("uu", false));
-        assert_se(!signature_is_single("", false));
-        assert_se(!signature_is_single("(", false));
-        assert_se(!signature_is_single(")", false));
-        assert_se(!signature_is_single("())", false));
-        assert_se(!signature_is_single("((())", false));
-        assert_se(!signature_is_single("{)", false));
-        assert_se(!signature_is_single("{}", true));
-        assert_se(!signature_is_single("{sss}", true));
-        assert_se(!signature_is_single("{s}", true));
-        assert_se(!signature_is_single("{ss}", false));
-        assert_se(!signature_is_single("{ass}", true));
-        assert_se(!signature_is_single("a}", true));
-
-        assert_se(signature_is_pair("yy"));
-        assert_se(signature_is_pair("ss"));
-        assert_se(signature_is_pair("sas"));
-        assert_se(signature_is_pair("sv"));
-        assert_se(signature_is_pair("sa(vs)"));
-        assert_se(!signature_is_pair(""));
-        assert_se(!signature_is_pair("va"));
-        assert_se(!signature_is_pair("sss"));
-        assert_se(!signature_is_pair("{s}ss"));
-
-        assert_se(signature_is_valid("ssa{ss}sssub", true));
-        assert_se(signature_is_valid("ssa{ss}sssub", false));
-        assert_se(signature_is_valid("{ss}", true));
-        assert_se(!signature_is_valid("{ss}", false));
-        assert_se(signature_is_valid("", true));
-        assert_se(signature_is_valid("", false));
-
-        assert_se(signature_is_valid("sssusa(uuubbba(uu)uuuu)a{u(uuuvas)}", false));
-
-        assert_se(!signature_is_valid("a", false));
-        assert_se(signature_is_valid("as", false));
-        assert_se(signature_is_valid("aas", false));
-        assert_se(signature_is_valid("aaas", false));
-        assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad", false));
-        assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false));
-        assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false));
-
-        assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false));
-        assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
-
-        assert_se(namespace_complex_pattern("", ""));
-        assert_se(namespace_complex_pattern("foobar", "foobar"));
-        assert_se(namespace_complex_pattern("foobar.waldo", "foobar.waldo"));
-        assert_se(namespace_complex_pattern("foobar.", "foobar.waldo"));
-        assert_se(namespace_complex_pattern("foobar.waldo", "foobar."));
-        assert_se(!namespace_complex_pattern("foobar.waldo", "foobar"));
-        assert_se(!namespace_complex_pattern("foobar", "foobar.waldo"));
-        assert_se(!namespace_complex_pattern("", "foo"));
-        assert_se(!namespace_complex_pattern("foo", ""));
-        assert_se(!namespace_complex_pattern("foo.", ""));
-
-        assert_se(path_complex_pattern("", ""));
-        assert_se(path_complex_pattern("", "/"));
-        assert_se(path_complex_pattern("/", ""));
-        assert_se(path_complex_pattern("/", "/"));
-        assert_se(path_complex_pattern("/foobar/", "/"));
-        assert_se(path_complex_pattern("/foobar/", "/foobar"));
-        assert_se(path_complex_pattern("/foobar", "/foobar"));
-        assert_se(path_complex_pattern("/foobar", "/foobar/"));
-        assert_se(!path_complex_pattern("/foobar", "/foobar/waldo"));
-        assert_se(path_complex_pattern("/foobar/", "/foobar/waldo"));
-
-        assert_se(namespace_simple_pattern("", ""));
-        assert_se(namespace_simple_pattern("foobar", "foobar"));
-        assert_se(namespace_simple_pattern("foobar.waldo", "foobar.waldo"));
-        assert_se(namespace_simple_pattern("foobar", "foobar.waldo"));
-        assert_se(!namespace_simple_pattern("foobar.waldo", "foobar"));
-        assert_se(!namespace_simple_pattern("", "foo"));
-        assert_se(!namespace_simple_pattern("foo", ""));
-
-        assert_se(streq(object_path_startswith("/foo/bar", "/foo"), "bar"));
-        assert_se(streq(object_path_startswith("/foo", "/foo"), ""));
-        assert_se(streq(object_path_startswith("/foo", "/"), "foo"));
-        assert_se(streq(object_path_startswith("/", "/"), ""));
-        assert_se(!object_path_startswith("/foo", "/bar"));
-        assert_se(!object_path_startswith("/", "/bar"));
-        assert_se(!object_path_startswith("/foo", ""));
-
-        assert_se(object_path_is_valid("/foo/bar"));
-        assert_se(object_path_is_valid("/foo"));
-        assert_se(object_path_is_valid("/"));
-        assert_se(object_path_is_valid("/foo5"));
-        assert_se(object_path_is_valid("/foo_5"));
-        assert_se(!object_path_is_valid(""));
-        assert_se(!object_path_is_valid("/foo/"));
-        assert_se(!object_path_is_valid("//"));
-        assert_se(!object_path_is_valid("//foo"));
-        assert_se(!object_path_is_valid("/foo//bar"));
-        assert_se(!object_path_is_valid("/foo/aaaäöä"));
-
-        OBJECT_PATH_FOREACH_PREFIX(prefix, "/") {
-                log_info("<%s>", prefix);
-                assert_not_reached("???");
-        }
-
-        r = 0;
-        OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx") {
-                log_info("<%s>", prefix);
-                assert_se(streq(prefix, "/"));
-                assert_se(r == 0);
-                r++;
-        }
-        assert_se(r == 1);
-
-        r = 0;
-        OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx/yyy/zzz") {
-                log_info("<%s>", prefix);
-                assert_se(r != 0 || streq(prefix, "/xxx/yyy"));
-                assert_se(r != 1 || streq(prefix, "/xxx"));
-                assert_se(r != 2 || streq(prefix, "/"));
-                r++;
-        }
-        assert_se(r == 3);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-bus-zero-copy.c b/src/libsystemd/test-bus-zero-copy.c
deleted file mode 100644
index 5ad8ed5..0000000
--- a/src/libsystemd/test-bus-zero-copy.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*-*- 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 <fcntl.h>
-#include <sys/mman.h>
-
-#include "util.h"
-#include "log.h"
-
-#include "sd-bus.h"
-#include "sd-memfd.h"
-#include "bus-message.h"
-#include "bus-error.h"
-#include "bus-kernel.h"
-#include "bus-dump.h"
-
-#define FIRST_ARRAY 17
-#define SECOND_ARRAY 33
-
-#define STRING_SIZE 123
-
-int main(int argc, char *argv[]) {
-        _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
-        uint8_t *p;
-        sd_bus *a, *b;
-        int r, bus_ref;
-        sd_bus_message *m;
-        sd_memfd *f;
-        uint64_t sz;
-        uint32_t u32;
-        size_t i, l;
-        char *s;
-
-        log_set_max_level(LOG_DEBUG);
-
-        assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
-
-        bus_ref = bus_kernel_create_bus(name, false, &bus_name);
-        if (bus_ref == -ENOENT)
-                return EXIT_TEST_SKIP;
-
-        assert_se(bus_ref >= 0);
-
-        address = strappend("kernel:path=", bus_name);
-        assert_se(address);
-
-        r = sd_bus_new(&a);
-        assert_se(r >= 0);
-
-        r = sd_bus_new(&b);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(a, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_set_address(b, address);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(a);
-        assert_se(r >= 0);
-
-        r = sd_bus_start(b);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_new_method_call(b, ":1.1", "/a/path", "an.inter.face", "AMethod", &m);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_open_container(m, 'r', "aysay");
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append_array_space(m, 'y', FIRST_ARRAY, (void**) &p);
-        assert_se(r >= 0);
-
-        p[0] = '<';
-        memset(p+1, 'L', FIRST_ARRAY-2);
-        p[FIRST_ARRAY-1] = '>';
-
-        r = sd_memfd_new_and_map(&f, STRING_SIZE, (void**) &s);
-        assert_se(r >= 0);
-
-        s[0] = '<';
-        for (i = 1; i < STRING_SIZE-2; i++)
-                s[i] = '0' + (i % 10);
-        s[STRING_SIZE-2] = '>';
-        s[STRING_SIZE-1] = 0;
-        munmap(s, STRING_SIZE);
-
-        r = sd_memfd_get_size(f, &sz);
-        assert_se(r >= 0);
-        assert_se(sz == STRING_SIZE);
-
-        r = sd_bus_message_append_string_memfd(m, f);
-        assert_se(r >= 0);
-
-        sd_memfd_free(f);
-
-        r = sd_memfd_new_and_map(&f, SECOND_ARRAY, (void**) &p);
-        assert_se(r >= 0);
-
-        p[0] = '<';
-        memset(p+1, 'P', SECOND_ARRAY-2);
-        p[SECOND_ARRAY-1] = '>';
-        munmap(p, SECOND_ARRAY);
-
-        r = sd_memfd_get_size(f, &sz);
-        assert_se(r >= 0);
-        assert_se(sz == SECOND_ARRAY);
-
-        r = sd_bus_message_append_array_memfd(m, 'y', f);
-        assert_se(r >= 0);
-
-        sd_memfd_free(f);
-
-        r = sd_bus_message_close_container(m);
-        assert_se(r >= 0);
-
-        r = sd_bus_message_append(m, "u", 4711);
-        assert_se(r >= 0);
-
-        r = bus_message_seal(m, 55, 99*USEC_PER_SEC);
-        assert_se(r >= 0);
-
-        bus_message_dump(m, stdout, true);
-
-        r = sd_bus_send(b, m, NULL);
-        assert_se(r >= 0);
-
-        sd_bus_message_unref(m);
-
-        r = sd_bus_process(a, &m);
-        assert_se(r > 0);
-
-        bus_message_dump(m, stdout, true);
-        sd_bus_message_rewind(m, true);
-
-        r = sd_bus_message_enter_container(m, 'r', "aysay");
-        assert_se(r > 0);
-
-        r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l);
-        assert_se(r > 0);
-        assert_se(l == FIRST_ARRAY);
-
-        assert_se(p[0] == '<');
-        for (i = 1; i < l-1; i++)
-                assert_se(p[i] == 'L');
-        assert_se(p[l-1] == '>');
-
-        r = sd_bus_message_read(m, "s", &s);
-        assert_se(r > 0);
-
-        assert_se(s[0] == '<');
-        for (i = 1; i < STRING_SIZE-2; i++)
-                assert_se(s[i] == (char) ('0' + (i % 10)));
-        assert_se(s[STRING_SIZE-2] == '>');
-        assert_se(s[STRING_SIZE-1] == 0);
-
-        r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l);
-        assert_se(r > 0);
-        assert_se(l == SECOND_ARRAY);
-
-        assert_se(p[0] == '<');
-        for (i = 1; i < l-1; i++)
-                assert_se(p[i] == 'P');
-        assert_se(p[l-1] == '>');
-
-        r = sd_bus_message_exit_container(m);
-        assert_se(r > 0);
-
-        r = sd_bus_message_read(m, "u", &u32);
-        assert_se(r > 0);
-        assert_se(u32 == 4711);
-
-        sd_bus_message_unref(m);
-
-        sd_bus_unref(a);
-        sd_bus_unref(b);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-event.c b/src/libsystemd/test-event.c
deleted file mode 100644
index 28ef6a3..0000000
--- a/src/libsystemd/test-event.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*-*- 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 "log.h"
-#include "util.h"
-
-static int prepare_handler(sd_event_source *s, void *userdata) {
-        log_info("preparing %c", PTR_TO_INT(userdata));
-        return 1;
-}
-
-static bool got_a, got_b, got_c, got_unref;
-static unsigned got_d;
-
-static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_event_source_unref(s);
-        got_unref = true;
-        return 0;
-}
-
-static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-
-        log_info("got IO on %c", PTR_TO_INT(userdata));
-
-        if (userdata == INT_TO_PTR('a')) {
-                assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
-                assert_se(!got_a);
-                got_a = true;
-        } else if (userdata == INT_TO_PTR('b')) {
-                assert_se(!got_b);
-                got_b = true;
-        } else if (userdata == INT_TO_PTR('d')) {
-                got_d++;
-                if (got_d < 2)
-                        assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
-                else
-                        assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
-        } else
-                assert_not_reached("Yuck!");
-
-        return 1;
-}
-
-static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
-
-        assert(s);
-        assert(si);
-
-        log_info("got child on %c", PTR_TO_INT(userdata));
-
-        assert(userdata == INT_TO_PTR('f'));
-
-        assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
-        sd_event_source_unref(s);
-
-        return 1;
-}
-
-static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        sd_event_source *p;
-        sigset_t ss;
-        pid_t pid;
-
-        assert(s);
-        assert(si);
-
-        log_info("got signal on %c", PTR_TO_INT(userdata));
-
-        assert(userdata == INT_TO_PTR('e'));
-
-        assert_se(sigemptyset(&ss) >= 0);
-        assert_se(sigaddset(&ss, SIGCHLD) >= 0);
-        assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
-
-        pid = fork();
-        assert_se(pid >= 0);
-
-        if (pid == 0)
-                _exit(0);
-
-        assert_se(sd_event_add_child(sd_event_source_get_event(s), pid, WEXITED, child_handler, INT_TO_PTR('f'), &p) >= 0);
-        assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
-
-        sd_event_source_unref(s);
-
-        return 1;
-}
-
-static int defer_handler(sd_event_source *s, void *userdata) {
-        sd_event_source *p;
-        sigset_t ss;
-
-        assert(s);
-
-        log_info("got defer on %c", PTR_TO_INT(userdata));
-
-        assert(userdata == INT_TO_PTR('d'));
-
-        assert_se(sigemptyset(&ss) >= 0);
-        assert_se(sigaddset(&ss, SIGUSR1) >= 0);
-        assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
-        assert_se(sd_event_add_signal(sd_event_source_get_event(s), SIGUSR1, signal_handler, INT_TO_PTR('e'), &p) >= 0);
-        assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
-        raise(SIGUSR1);
-
-        sd_event_source_unref(s);
-
-        return 1;
-}
-
-static bool do_quit = false;
-
-static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
-        log_info("got timer on %c", PTR_TO_INT(userdata));
-
-        if (userdata == INT_TO_PTR('c')) {
-
-                if (do_quit) {
-                        sd_event_source *p;
-
-                        assert_se(sd_event_add_defer(sd_event_source_get_event(s), defer_handler, INT_TO_PTR('d'), &p) >= 0);
-                        assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
-                } else {
-                        assert(!got_c);
-                        got_c = true;
-                }
-        } else
-                assert_not_reached("Huh?");
-
-        return 2;
-}
-
-static bool got_exit = false;
-
-static int exit_handler(sd_event_source *s, void *userdata) {
-        log_info("got quit handler on %c", PTR_TO_INT(userdata));
-
-        got_exit = true;
-
-        return 3;
-}
-
-int main(int argc, char *argv[]) {
-        sd_event *e = NULL;
-        sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
-        static const char ch = 'x';
-        int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
-
-        assert_se(pipe(a) >= 0);
-        assert_se(pipe(b) >= 0);
-        assert_se(pipe(d) >= 0);
-        assert_se(pipe(k) >= 0);
-
-        assert_se(sd_event_default(&e) >= 0);
-
-        assert_se(sd_event_set_watchdog(e, true) >= 0);
-
-        /* Test whether we cleanly can destroy an io event source from its own handler */
-        got_unref = false;
-        assert_se(sd_event_add_io(e, k[0], EPOLLIN, unref_handler, NULL, &t) >= 0);
-        assert_se(write(k[1], &ch, 1) == 1);
-        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-        assert_se(got_unref);
-
-        got_a = false, got_b = false, got_c = false, got_d = 0;
-
-        /* Add a oneshot handler, trigger it, re-enable it, and trigger
-         * it again. */
-        assert_se(sd_event_add_io(e, d[0], EPOLLIN, io_handler, INT_TO_PTR('d'), &w) >= 0);
-        assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
-        assert_se(write(d[1], &ch, 1) >= 0);
-        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-        assert_se(got_d == 1);
-        assert_se(write(d[1], &ch, 1) >= 0);
-        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-        assert_se(got_d == 2);
-
-        assert_se(sd_event_add_io(e, a[0], EPOLLIN, io_handler, INT_TO_PTR('a'), &x) >= 0);
-        assert_se(sd_event_add_io(e, b[0], EPOLLIN, io_handler, INT_TO_PTR('b'), &y) >= 0);
-        assert_se(sd_event_add_monotonic(e, 0, 0, time_handler, INT_TO_PTR('c'), &z) >= 0);
-        assert_se(sd_event_add_exit(e, exit_handler, INT_TO_PTR('g'), &q) >= 0);
-
-        assert_se(sd_event_source_set_priority(x, 99) >= 0);
-        assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
-        assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
-        assert_se(sd_event_source_set_priority(z, 50) >= 0);
-        assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
-        assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
-
-        assert_se(write(a[1], &ch, 1) >= 0);
-        assert_se(write(b[1], &ch, 1) >= 0);
-
-        assert_se(!got_a && !got_b && !got_c);
-
-        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-
-        assert_se(!got_a && got_b && !got_c);
-
-        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-
-        assert_se(!got_a && got_b && got_c);
-
-        assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-
-        assert_se(got_a && got_b && got_c);
-
-        sd_event_source_unref(x);
-        sd_event_source_unref(y);
-
-        do_quit = true;
-        assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
-        assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
-
-        assert_se(sd_event_loop(e) >= 0);
-
-        sd_event_source_unref(z);
-        sd_event_source_unref(q);
-
-        sd_event_source_unref(w);
-
-        sd_event_unref(e);
-
-        close_pipe(a);
-        close_pipe(b);
-        close_pipe(d);
-        close_pipe(k);
-
-        return 0;
-}
diff --git a/src/libsystemd/test-resolve.c b/src/libsystemd/test-resolve.c
deleted file mode 100644
index 3903e64..0000000
--- a/src/libsystemd/test-resolve.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2005-2008 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 <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#include <assert.h>
-#include <signal.h>
-#include <errno.h>
-
-#include "sd-resolve.h"
-#include "resolve-util.h"
-#include "macro.h"
-
-int main(int argc, char *argv[]) {
-        int r = 1, ret;
-        _cleanup_resolve_free_ sd_resolve *resolve = NULL;
-        _cleanup_resolve_addrinfo_free_ struct addrinfo *ai = NULL;
-        _cleanup_free_ unsigned char *srv = NULL;
-        sd_resolve_query *q1, *q2, *q3;
-        struct addrinfo hints = {};
-        struct sockaddr_in sa = {};
-        char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
-
-        signal(SIGCHLD, SIG_IGN);
-
-        resolve = sd_resolve_new(2);
-        if (!resolve)
-                log_oom();
-
-        /* Make a name -> address query */
-        hints.ai_family = PF_UNSPEC;
-        hints.ai_socktype = SOCK_STREAM;
-
-        q1 = sd_resolve_getaddrinfo(resolve, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints);
-        if (!q1)
-                fprintf(stderr, "sd_resolve_getaddrinfo(): %s\n", strerror(errno));
-
-        /* Make an address -> name query */
-        sa.sin_family = AF_INET;
-        sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
-        sa.sin_port = htons(80);
-
-        q2 = sd_resolve_getnameinfo(resolve, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1);
-        if (!q2)
-                fprintf(stderr, "sd_resolve_getnameinfo(): %s\n", strerror(errno));
-
-        /* Make a res_query() call */
-        q3 = sd_resolve_res_query(resolve, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV);
-        if (!q3)
-                fprintf(stderr, "sd_resolve_res_query(): %s\n", strerror(errno));
-
-        /* Wait until the three queries are completed */
-        while (!sd_resolve_isdone(resolve, q1) ||
-               !sd_resolve_isdone(resolve, q2) ||
-               !sd_resolve_isdone(resolve, q3)) {
-                if (sd_resolve_wait(resolve, 1) < 0)
-                        fprintf(stderr, "sd_resolve_wait(): %s\n", strerror(errno));
-        }
-
-        /* Interpret the result of the name -> addr query */
-        ret = sd_resolve_getaddrinfo_done(resolve, q1, &ai);
-        if (ret)
-                fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
-        else {
-                struct addrinfo *i;
-
-                for (i = ai; i; i = i->ai_next) {
-                        char t[256];
-                        const char *p = NULL;
-
-                        if (i->ai_family == PF_INET)
-                                p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
-                        else if (i->ai_family == PF_INET6)
-                                p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));
-
-                        printf("%s\n", p);
-                }
-        }
-
-        /* Interpret the result of the addr -> name query */
-        ret = sd_resolve_getnameinfo_done(resolve, q2, host, sizeof(host), serv, sizeof(serv));
-        if (ret)
-                fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
-        else
-                printf("%s -- %s\n", host, serv);
-
-        /* Interpret the result of the SRV lookup */
-        ret = sd_resolve_res_done(resolve, q3, &srv);
-        if (ret < 0) {
-                fprintf(stderr, "error: %s %i\n", strerror(errno), ret);
-        } else if (ret == 0) {
-                fprintf(stderr, "No reply for SRV lookup\n");
-        } else {
-                int qdcount;
-                int ancount;
-                int len;
-                const unsigned char *pos = srv + sizeof(HEADER);
-                unsigned char *end = srv + ret;
-                HEADER *head = (HEADER *)srv;
-                char name[256];
-
-                qdcount = ntohs(head->qdcount);
-                ancount = ntohs(head->ancount);
-
-                printf("%d answers for srv lookup:\n", ancount);
-
-                /* Ignore the questions */
-                while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
-                        assert(len >= 0);
-                        pos += len + QFIXEDSZ;
-                }
-
-                /* Parse the answers */
-                while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
-                        /* Ignore the initial string */
-                        uint16_t pref, weight, port;
-                        assert(len >= 0);
-                        pos += len;
-                        /* Ignore type, ttl, class and dlen */
-                        pos += 10;
-
-                        GETSHORT(pref, pos);
-                        GETSHORT(weight, pos);
-                        GETSHORT(port, pos);
-                        len = dn_expand(srv, end, pos, name, 255);
-                        printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
-                                        pref, weight, port, name);
-
-                        pos += len;
-                }
-        }
-
-        r = 0;
-
-        return r;
-}
diff --git a/src/libsystemd/test-rtnl.c b/src/libsystemd/test-rtnl.c
deleted file mode 100644
index 58654e9..0000000
--- a/src/libsystemd/test-rtnl.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg at jklm.no>
-
-  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 <linux/rtnetlink.h>
-#include <netinet/ether.h>
-
-#include "util.h"
-#include "macro.h"
-#include "sd-rtnl.h"
-#include "socket-util.h"
-#include "rtnl-util.h"
-#include "event-util.h"
-
-static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
-        uint16_t type;
-        const char *mac = "98:fe:94:3f:c6:18", *name = "test";
-        unsigned int mtu = 1450;
-        void *data;
-
-        /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &message) >= 0);
-        assert(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
-        assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
-        assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
-
-        assert(sd_rtnl_message_read(message, &type, &data) > 0);
-        assert(type == IFLA_IFNAME);
-        assert(streq(name, (char *) data));
-
-        assert(sd_rtnl_message_read(message, &type, &data) > 0);
-        assert(type == IFLA_ADDRESS);
-        assert(streq(mac, ether_ntoa(data)));
-
-        assert(sd_rtnl_message_read(message, &type, &data) > 0);
-        assert(type == IFLA_MTU);
-        assert(mtu == *(unsigned int *) data);
-
-        assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
-}
-
-static void test_route(void) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
-        struct in_addr addr;
-        uint32_t index = 2;
-        uint16_t type;
-        void *data;
-        int r;
-
-        r = sd_rtnl_message_route_new(RTM_NEWROUTE, AF_INET, &req);
-        if (r < 0) {
-                log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
-                return;
-        }
-
-        addr.s_addr = htonl(INADDR_LOOPBACK);
-
-        r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
-        if (r < 0) {
-                log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
-                return;
-        }
-
-        r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
-        if (r < 0) {
-                log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
-                return;
-        }
-
-        assert(sd_rtnl_message_read(req, &type, &data) > 0);
-        assert(type == RTA_GATEWAY);
-        assert(((struct in_addr *)data)->s_addr == addr.s_addr);
-
-        assert(sd_rtnl_message_read(req, &type, &data) > 0);
-        assert(type == RTA_OIF);
-        assert(*(uint32_t *) data == index);
-}
-
-static void test_multiple(void) {
-        sd_rtnl *rtnl1, *rtnl2;
-
-        assert(sd_rtnl_open(0, &rtnl1) >= 0);
-        assert(sd_rtnl_open(0, &rtnl2) >= 0);
-
-        rtnl1 = sd_rtnl_unref(rtnl1);
-        rtnl2 = sd_rtnl_unref(rtnl2);
-}
-
-static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
-        void *data;
-        uint16_t type;
-        char *ifname = userdata;
-
-        assert(rtnl);
-        assert(m);
-
-        log_info("got link info about %s", ifname);
-        free(ifname);
-
-        while (sd_rtnl_message_read(m, &type, &data) > 0) {
-                switch (type) {
-//                        case IFLA_MTU:
-//                                assert(*(unsigned int *) data == 65536);
-//                                break;
-//                        case IFLA_QDISC:
-//                                assert(streq((char *) data, "noqueue"));
-//                                break;
-                        case IFLA_IFNAME:
-                                assert(streq((char *) data, "lo"));
-                                break;
-                }
-        }
-
-        return 1;
-}
-
-static void test_event_loop(int ifindex) {
-        _cleanup_event_unref_ sd_event *event = NULL;
-        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        char *ifname;
-
-        ifname = strdup("lo2");
-        assert(ifname);
-
-        assert(sd_rtnl_open(0, &rtnl) >= 0);
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
-
-        assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
-
-        assert(sd_event_default(&event) >= 0);
-
-        assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
-
-        assert(sd_event_run(event, 0) >= 0);
-
-        assert(sd_rtnl_detach_event(rtnl) >= 0);
-}
-
-static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
-        int *counter = userdata;
-
-        (*counter) --;
-
-        log_info("got reply, %d left in pipe", *counter);
-
-        return sd_rtnl_message_get_errno(m);
-}
-
-static void test_async(int ifindex) {
-        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
-        uint32_t serial;
-        char *ifname;
-
-        ifname = strdup("lo");
-        assert(ifname);
-
-        assert(sd_rtnl_open(0, &rtnl) >= 0);
-
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
-
-        assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
-
-        assert(sd_rtnl_wait(rtnl, 0) >= 0);
-        assert(sd_rtnl_process(rtnl, &r) >= 0);
-}
-
-static void test_pipe(int ifindex) {
-        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
-        int counter = 0;
-
-        assert(sd_rtnl_open(0, &rtnl) >= 0);
-
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m1) >= 0);
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m2) >= 0);
-
-        counter ++;
-        assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
-
-        counter ++;
-        assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
-
-        while (counter > 0) {
-                assert(sd_rtnl_wait(rtnl, 0) >= 0);
-                assert(sd_rtnl_process(rtnl, NULL) >= 0);
-        }
-}
-
-static void test_container(void) {
-        _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-        uint16_t type;
-        void *data;
-
-        assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, &m) >= 0);
-
-        assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
-        assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -EINVAL);
-        assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
-        assert(sd_rtnl_message_close_container(m) >= 0);
-        assert(sd_rtnl_message_close_container(m) == -EINVAL);
-
-        assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
-
-/* TODO: add support for entering containers
-        assert(sd_rtnl_message_read(m, &type, &data) > 0);
-        assert(type == IFLA_INFO_KIND);
-        assert(streq("kind", (char *) data));
-
-        assert(sd_rtnl_message_read(m, &type, &data) == 0);
-*/
-}
-
-static void test_match(void) {
-        _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
-
-        assert(sd_rtnl_open(0, &rtnl) >= 0);
-
-        assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
-        assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
-
-        assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
-        assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
-        assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
-}
-
-int main(void) {
-        sd_rtnl *rtnl;
-        sd_rtnl_message *m;
-        sd_rtnl_message *r;
-        void *data;
-        int if_loopback;
-        uint16_t type;
-        unsigned int mtu = 0;
-        unsigned int *mtu_reply;
-
-        test_match();
-
-        test_multiple();
-
-        test_route();
-
-        test_container();
-
-        assert(sd_rtnl_open(0, &rtnl) >= 0);
-        assert(rtnl);
-
-        if_loopback = (int) if_nametoindex("lo");
-        assert(if_loopback > 0);
-
-        test_async(if_loopback);
-
-        test_pipe(if_loopback);
-
-        test_event_loop(if_loopback);
-
-        test_link_configure(rtnl, if_loopback);
-
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
-        assert(m);
-
-        assert(sd_rtnl_message_get_type(m, &type) >= 0);
-        assert(type == RTM_GETLINK);
-
-        assert(sd_rtnl_message_read(m, &type, &data) == 0);
-
-        assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
-        assert(sd_rtnl_message_get_type(r, &type) >= 0);
-        assert(type == RTM_NEWLINK);
-
-        assert(sd_rtnl_message_read(m, &type, &data) == 0);
-        assert((r = sd_rtnl_message_unref(r)) == NULL);
-
-        assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
-        assert((m = sd_rtnl_message_unref(m)) == NULL);
-        assert((r = sd_rtnl_message_unref(r)) == NULL);
-
-        assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
-        assert(m);
-
-        assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
-        assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
-
-        assert(type == IFLA_MTU);
-        assert(*mtu_reply == 0);
-
-        assert(sd_rtnl_message_read(m, &type, &data) == 0);
-
-        assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
-        while (sd_rtnl_message_read(r, &type, &data) > 0) {
-                switch (type) {
-//                        case IFLA_MTU:
-//                                assert(*(unsigned int *) data == 65536);
-//                                break;
-//                        case IFLA_QDISC:
-//                                assert(streq((char *) data, "noqueue"));
-//                                break;
-                        case IFLA_IFNAME:
-                                assert(streq((char *) data, "lo"));
-                                break;
-                }
-        }
-
-        assert(sd_rtnl_flush(rtnl) >= 0);
-
-        assert((m = sd_rtnl_message_unref(m)) == NULL);
-        assert((r = sd_rtnl_message_unref(r)) == NULL);
-        assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-
-        return EXIT_SUCCESS;
-}



More information about the systemd-commits mailing list