[systemd-commits] 2 commits - automount.c automount.h cgroup.c cgroup.h cgroups-agent.c configure.ac conf-parser.c conf-parser.h dbus-automount.c dbus-automount.h dbus.c dbus-device.c dbus-device.h dbus-execute.c dbus-execute.h dbus.h dbus-job.c dbus-job.h dbus-manager.c dbus-manager.h dbus-mount.c dbus-mount.h dbus-service.c dbus-service.h dbus-snapshot.c dbus-snapshot.h dbus-socket.c dbus-socket.h dbus-swap.c dbus-swap.h dbus-target.c dbus-target.h dbus-unit.c dbus-unit.h device.c device.h execute.c execute.h fdset.c fdset.h hashmap.c hashmap.h hostname-setup.c hostname-setup.h initctl.c initreq.h ioprio.h job.c job.h linux/auto_dev-ioctl.h list.h load-dropin.c load-dropin.h load-fragment.c load-fragment.h log.c logger.c log.h loopback-setup.c loopback-setup.h macro.h main.c Makefile.am manager.c manager.h missing.h mount.c mount.h mount-setup.c mount-setup.h namespace.c namespace.h ratelimit.c ratelimit.h sd-daemon.c sd-daemon.h securebits.h service.c service.h set.c set.h snapshot .c snapshot.h socket.c socket.h socket-util.c socket-util.h specifier.c specifier.h src/automount.c src/automount.h src/cgroup.c src/cgroup.h src/cgroups-agent.c src/conf-parser.c src/conf-parser.h src/dbus-automount.c src/dbus-automount.h src/dbus.c src/dbus-device.c src/dbus-device.h src/dbus-execute.c src/dbus-execute.h src/dbus.h src/dbus-job.c src/dbus-job.h src/dbus-manager.c src/dbus-manager.h src/dbus-mount.c src/dbus-mount.h src/dbus-service.c src/dbus-service.h src/dbus-snapshot.c src/dbus-snapshot.h src/dbus-socket.c src/dbus-socket.h src/dbus-swap.c src/dbus-swap.h src/dbus-target.c src/dbus-target.h src/dbus-unit.c src/dbus-unit.h src/device.c src/device.h src/execute.c src/execute.h src/fdset.c src/fdset.h src/hashmap.c src/hashmap.h src/hostname-setup.c src/hostname-setup.h src/initctl.c src/initreq.h src/ioprio.h src/job.c src/job.h src/linux src/list.h src/load-dropin.c src/load-dropin.h src/load-fragment.c src/load-fragment.h src/log.c src/logger.c src/log. h src/loopback-setup.c src/loopback-setup.h src/macro.h src/main.c src/manager.c src/manager.h src/missing.h src/mount.c src/mount.h src/mount-setup.c src/mount-setup.h src/namespace.c src/namespace.h src/ratelimit.c src/ratelimit.h src/sd-daemon.c src/sd-daemon.h src/securebits.h src/service.c src/service.h src/set.c src/set.h src/snapshot.c src/snapshot.h src/socket.c src/socket.h src/socket-util.c src/socket-util.h src/specifier.c src/specifier.h src/strv.c src/strv.h src/swap.c src/swap.h src/systemadm.vala src/systemctl.vala src/systemd-interfaces.vala src/target.c src/target.h src/test-engine.c src/test-job-type.c src/test-loopback.c src/test-ns.c src/timer.c src/timer.h src/unit.c src/unit.h src/unit-name.c src/unit-name.h src/util.c src/util.h src/utmp-wtmp.c src/utmp-wtmp.h strv.c strv.h swap.c swap.h systemadm.vala systemctl.vala systemd-interfaces.vala target.c target.h test-engine.c test-job-type.c test-loopback.c test-ns.c timer.c timer.h unit.c unit.h unit-name .c unit-name.h util.c util.h utmp-wtmp.c utmp-wtmp.h

Lennart Poettering lennart at kemper.freedesktop.org
Sun May 16 09:45:33 PDT 2010


 Makefile.am                 |  175 +--
 automount.c                 |  784 --------------
 automount.h                 |   65 -
 cgroup.c                    |  561 ----------
 cgroup.h                    |   82 -
 cgroups-agent.c             |   72 -
 conf-parser.c               |  460 --------
 conf-parser.h               |   55 
 configure.ac                |    8 
 dbus-automount.c            |   44 
 dbus-automount.h            |   31 
 dbus-device.c               |   44 
 dbus-device.h               |   31 
 dbus-execute.c              |   28 
 dbus-execute.h              |   79 -
 dbus-job.c                  |  236 ----
 dbus-job.h                  |   32 
 dbus-manager.c              |  657 -----------
 dbus-manager.h              |   29 
 dbus-mount.c                |  134 --
 dbus-mount.h                |   31 
 dbus-service.c              |   78 -
 dbus-service.h              |   31 
 dbus-snapshot.c             |   75 -
 dbus-snapshot.h             |   31 
 dbus-socket.c               |   64 -
 dbus-socket.h               |   31 
 dbus-swap.c                 |   73 -
 dbus-swap.h                 |   32 
 dbus-target.c               |   42 
 dbus-target.h               |   31 
 dbus-unit.c                 |  451 --------
 dbus-unit.h                 |  128 --
 dbus.c                      | 1136 --------------------
 dbus.h                      |  107 -
 device.c                    |  471 --------
 device.h                    |   53 
 execute.c                   | 1619 ----------------------------
 execute.h                   |  221 ---
 fdset.c                     |  162 --
 fdset.h                     |   40 
 hashmap.c                   |  543 ---------
 hashmap.h                   |   85 -
 hostname-setup.c            |  168 ---
 hostname-setup.h            |   27 
 initctl.c                   |  397 -------
 initreq.h                   |   77 -
 ioprio.h                    |   57 -
 job.c                       |  589 ----------
 job.h                       |  150 --
 linux/auto_dev-ioctl.h      |  229 ----
 list.h                      |  119 --
 load-dropin.c               |  117 --
 load-dropin.h               |   31 
 load-fragment.c             | 1483 --------------------------
 load-fragment.h             |   33 
 log.c                       |  439 -------
 log.h                       |   79 -
 logger.c                    |  565 ----------
 loopback-setup.c            |  276 ----
 loopback-setup.h            |   27 
 macro.h                     |  130 --
 main.c                      |  787 --------------
 manager.c                   | 2291 ----------------------------------------
 manager.h                   |  284 -----
 missing.h                   |   38 
 mount-setup.c               |  168 ---
 mount-setup.h               |   31 
 mount.c                     | 1539 ---------------------------
 mount.h                     |  110 -
 namespace.c                 |  331 -----
 namespace.h                 |   34 
 ratelimit.c                 |   62 -
 ratelimit.h                 |   55 
 sd-daemon.c                 |   96 -
 sd-daemon.h                 |   61 -
 securebits.h                |   45 
 service.c                   | 2463 --------------------------------------------
 service.h                   |  147 --
 set.c                       |  114 --
 set.h                       |   68 -
 snapshot.c                  |  276 ----
 snapshot.h                  |   52 
 socket-util.c               |  468 --------
 socket-util.h               |   79 -
 socket.c                    | 1411 -------------------------
 socket.h                    |  132 --
 specifier.c                 |  110 -
 specifier.h                 |   37 
 src/automount.c             |  784 ++++++++++++++
 src/automount.h             |   65 +
 src/cgroup.c                |  561 ++++++++++
 src/cgroup.h                |   82 +
 src/cgroups-agent.c         |   72 +
 src/conf-parser.c           |  460 ++++++++
 src/conf-parser.h           |   55 
 src/dbus-automount.c        |   44 
 src/dbus-automount.h        |   31 
 src/dbus-device.c           |   44 
 src/dbus-device.h           |   31 
 src/dbus-execute.c          |   28 
 src/dbus-execute.h          |   79 +
 src/dbus-job.c              |  236 ++++
 src/dbus-job.h              |   32 
 src/dbus-manager.c          |  657 +++++++++++
 src/dbus-manager.h          |   29 
 src/dbus-mount.c            |  134 ++
 src/dbus-mount.h            |   31 
 src/dbus-service.c          |   78 +
 src/dbus-service.h          |   31 
 src/dbus-snapshot.c         |   75 +
 src/dbus-snapshot.h         |   31 
 src/dbus-socket.c           |   64 +
 src/dbus-socket.h           |   31 
 src/dbus-swap.c             |   73 +
 src/dbus-swap.h             |   32 
 src/dbus-target.c           |   42 
 src/dbus-target.h           |   31 
 src/dbus-unit.c             |  451 ++++++++
 src/dbus-unit.h             |  128 ++
 src/dbus.c                  | 1136 ++++++++++++++++++++
 src/dbus.h                  |  107 +
 src/device.c                |  471 ++++++++
 src/device.h                |   53 
 src/execute.c               | 1619 ++++++++++++++++++++++++++++
 src/execute.h               |  221 +++
 src/fdset.c                 |  162 ++
 src/fdset.h                 |   40 
 src/hashmap.c               |  543 +++++++++
 src/hashmap.h               |   85 +
 src/hostname-setup.c        |  168 +++
 src/hostname-setup.h        |   27 
 src/initctl.c               |  397 +++++++
 src/initreq.h               |   77 +
 src/ioprio.h                |   57 +
 src/job.c                   |  589 ++++++++++
 src/job.h                   |  150 ++
 src/linux/auto_dev-ioctl.h  |  229 ++++
 src/list.h                  |  119 ++
 src/load-dropin.c           |  117 ++
 src/load-dropin.h           |   31 
 src/load-fragment.c         | 1483 ++++++++++++++++++++++++++
 src/load-fragment.h         |   33 
 src/log.c                   |  439 +++++++
 src/log.h                   |   79 +
 src/logger.c                |  565 ++++++++++
 src/loopback-setup.c        |  276 ++++
 src/loopback-setup.h        |   27 
 src/macro.h                 |  130 ++
 src/main.c                  |  787 ++++++++++++++
 src/manager.c               | 2291 ++++++++++++++++++++++++++++++++++++++++
 src/manager.h               |  284 +++++
 src/missing.h               |   38 
 src/mount-setup.c           |  168 +++
 src/mount-setup.h           |   31 
 src/mount.c                 | 1539 +++++++++++++++++++++++++++
 src/mount.h                 |  110 +
 src/namespace.c             |  331 +++++
 src/namespace.h             |   34 
 src/ratelimit.c             |   62 +
 src/ratelimit.h             |   55 
 src/sd-daemon.c             |   96 +
 src/sd-daemon.h             |   61 +
 src/securebits.h            |   45 
 src/service.c               | 2463 ++++++++++++++++++++++++++++++++++++++++++++
 src/service.h               |  147 ++
 src/set.c                   |  114 ++
 src/set.h                   |   68 +
 src/snapshot.c              |  276 ++++
 src/snapshot.h              |   52 
 src/socket-util.c           |  468 ++++++++
 src/socket-util.h           |   79 +
 src/socket.c                | 1411 +++++++++++++++++++++++++
 src/socket.h                |  132 ++
 src/specifier.c             |  110 +
 src/specifier.h             |   37 
 src/strv.c                  |  503 ++++++++
 src/strv.h                  |   65 +
 src/swap.c                  |  578 ++++++++++
 src/swap.h                  |   71 +
 src/systemadm.vala          |  956 +++++++++++++++++
 src/systemctl.vala          |  321 +++++
 src/systemd-interfaces.vala |  137 ++
 src/target.c                |  194 +++
 src/target.h                |   49 
 src/test-engine.c           |   99 +
 src/test-job-type.c         |   84 +
 src/test-loopback.c         |   35 
 src/test-ns.c               |   60 +
 src/timer.c                 |   51 
 src/timer.h                 |   49 
 src/unit-name.c             |  424 +++++++
 src/unit-name.h             |   54 
 src/unit.c                  | 1949 ++++++++++++++++++++++++++++++++++
 src/unit.h                  |  448 ++++++++
 src/util.c                  | 2027 ++++++++++++++++++++++++++++++++++++
 src/util.h                  |  256 ++++
 src/utmp-wtmp.c             |  214 +++
 src/utmp-wtmp.h             |   33 
 strv.c                      |  503 --------
 strv.h                      |   65 -
 swap.c                      |  578 ----------
 swap.h                      |   71 -
 systemadm.vala              |  956 -----------------
 systemctl.vala              |  321 -----
 systemd-interfaces.vala     |  137 --
 target.c                    |  194 ---
 target.h                    |   49 
 test-engine.c               |   99 -
 test-job-type.c             |   84 -
 test-loopback.c             |   35 
 test-ns.c                   |   60 -
 timer.c                     |   51 
 timer.h                     |   49 
 unit-name.c                 |  424 -------
 unit-name.h                 |   54 
 unit.c                      | 1949 ----------------------------------
 unit.h                      |  448 --------
 util.c                      | 2027 ------------------------------------
 util.h                      |  256 ----
 utmp-wtmp.c                 |  214 ---
 utmp-wtmp.h                 |   33 
 222 files changed, 33997 insertions(+), 33982 deletions(-)

New commits:
commit e99e38bbdcca3fe5956823bdb3d38544ccf93221
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun May 16 18:45:24 2010 +0200

    build-sys: move source files to subdirectory

diff --git a/Makefile.am b/Makefile.am
index c676712..0da02af 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,11 +33,8 @@ AM_CPPFLAGS = \
 	-DSESSION_CONFIG_UNIT_PATH=\"$(pkgsysconfdir)/session\" \
 	-DSESSION_DATA_UNIT_PATH=\"$(sessionunitdir)\" \
 	-DCGROUP_AGENT_PATH=\"$(pkglibexecdir)/systemd-cgroups-agent\" \
-	-DSYSTEMD_BINARY_PATH=\"$(sbindir)/systemd\"
-
-VALA_CFLAGS = \
-	-Wno-unused-variable \
-	-Wno-unused-function
+	-DSYSTEMD_BINARY_PATH=\"$(sbindir)/systemd\" \
+	-I $(top_srcdir)/src
 
 sbin_PROGRAMS = \
 	systemd
@@ -86,65 +83,65 @@ EXTRA_DIST = \
 # rules for C programs, but not Vala programs.  We therefore can't
 # list the .h files as dependencies if we want make dist to work.
 BASIC_SOURCES = \
-        util.c \
-        hashmap.c \
-        set.c \
-        strv.c \
-        conf-parser.c \
-        socket-util.c \
-        log.c \
-        ratelimit.c
+        src/util.c \
+        src/hashmap.c \
+        src/set.c \
+        src/strv.c \
+        src/conf-parser.c \
+        src/socket-util.c \
+        src/log.c \
+        src/ratelimit.c
 
 COMMON_SOURCES = \
 	$(BASIC_SOURCES) \
-	unit.c \
-        job.c \
-        manager.c \
-        load-fragment.c \
-        service.c \
-        automount.c \
-        mount.c \
-        swap.c \
-        device.c \
-        target.c \
-        snapshot.c \
-        socket.c \
-        timer.c \
-        load-dropin.c \
-        execute.c \
-        dbus.c \
-        dbus-manager.c \
-        dbus-unit.c \
-        dbus-job.c \
-	dbus-service.c \
-	dbus-socket.c \
-	dbus-target.c \
-	dbus-mount.c \
-	dbus-automount.c \
-	dbus-swap.c \
-	dbus-snapshot.c \
-	dbus-device.c \
-	dbus-execute.c \
-	cgroup.c \
-	mount-setup.c \
-	hostname-setup.c \
-	loopback-setup.c \
-	utmp-wtmp.c \
-	specifier.c \
-	unit-name.c \
-	fdset.c \
-	namespace.c
+	src/unit.c \
+        src/job.c \
+        src/manager.c \
+        src/load-fragment.c \
+        src/service.c \
+        src/automount.c \
+        src/mount.c \
+        src/swap.c \
+        src/device.c \
+        src/target.c \
+        src/snapshot.c \
+        src/socket.c \
+        src/timer.c \
+        src/load-dropin.c \
+        src/execute.c \
+        src/dbus.c \
+        src/dbus-manager.c \
+        src/dbus-unit.c \
+        src/dbus-job.c \
+	src/dbus-service.c \
+	src/dbus-socket.c \
+	src/dbus-target.c \
+	src/dbus-mount.c \
+	src/dbus-automount.c \
+	src/dbus-swap.c \
+	src/dbus-snapshot.c \
+	src/dbus-device.c \
+	src/dbus-execute.c \
+	src/cgroup.c \
+	src/mount-setup.c \
+	src/hostname-setup.c \
+	src/loopback-setup.c \
+	src/utmp-wtmp.c \
+	src/specifier.c \
+	src/unit-name.c \
+	src/fdset.c \
+	src/namespace.c
 
 EXTRA_DIST += \
 	${COMMON_SOURCES:.c=.h} \
-	macro.h \
-	ioprio.h \
-	missing.h \
-	list.h \
-	securebits.h \
-	linux/auto_dev-ioctl.h \
-	initreq.h \
-	sd-daemon.h
+	src/macro.h \
+	src/ioprio.h \
+	src/missing.h \
+	src/list.h \
+	src/securebits.h \
+	src/linux/auto_dev-ioctl.h \
+	src/initreq.h \
+	src/sd-daemon.h
 
 dist_man_MANS = \
 	systemd.unit.5 \
@@ -163,7 +160,7 @@ EXTRA_DIST += \
 
 systemd_SOURCES = \
 	$(COMMON_SOURCES) \
-	main.c
+	src/main.c
 
 systemd_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
@@ -178,43 +175,43 @@ systemd_LDADD = \
 
 test_engine_SOURCES = \
 	$(COMMON_SOURCES) \
-	test-engine.c
+	src/test-engine.c
 
 test_engine_CPPFLAGS = $(systemd_CPPFLAGS)
 test_engine_LDADD = $(systemd_LDADD)
 
 test_job_type_SOURCES = \
 	$(COMMON_SOURCES) \
-	test-engine.c
+	src/test-engine.c
 
 test_job_type_CPPFLAGS = $(systemd_CPPFLAGS)
 test_job_type_LDADD = $(systemd_LDADD)
 
 test_ns_SOURCES = \
 	$(BASIC_SOURCES) \
-	test-ns.c \
-	namespace.c
+	src/test-ns.c \
+	src/namespace.c
 
 test_ns_CPPFLAGS = $(systemd_CPPFLAGS)
 test_ns_LDADD = $(systemd_LDADD)
 
 test_loopback_SOURCES = \
 	$(BASIC_SOURCES) \
-	test-loopback.c \
-	loopback-setup.c
+	src/test-loopback.c \
+	src/loopback-setup.c
 
 test_loopback_CPPFLAGS = $(systemd_CPPFLAGS)
 test_loopback_LDADD = $(systemd_LDADD)
 
 systemd_logger_SOURCES = \
 	$(BASIC_SOURCES) \
-	logger.c \
-	sd-daemon.c
+	src/logger.c \
+	src/sd-daemon.c
 
 systemd_initctl_SOURCES = \
 	$(BASIC_SOURCES) \
-	initctl.c \
-	sd-daemon.c
+	src/initctl.c \
+	src/sd-daemon.c
 
 systemd_initctl_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
@@ -225,7 +222,7 @@ systemd_initctl_LDADD = \
 
 systemd_cgroups_agent_SOURCES = \
 	$(BASIC_SOURCES) \
-	cgroups-agent.c
+	src/cgroups-agent.c
 
 systemd_cgroups_agent_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
@@ -234,18 +231,31 @@ systemd_cgroups_agent_CPPFLAGS = \
 systemd_cgroups_agent_LDADD = \
 	$(DBUS_LIBS)
 
-VALAFLAGS = -g --save-temps --pkg=dbus-glib-1 --pkg=posix --pkg gtk+-2.0
+VALAFLAGS = \
+	-g \
+	--save-temps \
+	--pkg=dbus-glib-1 \
+	--pkg=posix
+
+if HAVE_GTK
+VALAFLAGS += \
+	--pkg=gtk+-2.0
+endif
+
+VALA_CFLAGS = \
+	-Wno-unused-variable \
+	-Wno-unused-function
 
 systemctl_SOURCES = \
-	systemctl.vala \
-	systemd-interfaces.vala
+	src/systemctl.vala \
+	src/systemd-interfaces.vala
 
 systemctl_CPPFLAGS = $(AM_CPPFLAGS) $(DBUSGLIB_CFLAGS) $(VALA_CFLAGS)
 systemctl_LDADD = $(DBUSGLIB_LIBS)
 
 systemadm_SOURCES = \
-	systemadm.vala \
-	systemd-interfaces.vala
+	src/systemadm.vala \
+	src/systemd-interfaces.vala
 
 systemadm_CPPFLAGS = $(AM_CPPFLAGS) $(DBUSGLIB_CFLAGS) $(GTK_CFLAGS) $(VALA_CFLAGS)
 systemadm_LDADD = $(DBUSGLIB_LIBS) $(GTK_LIBS)
@@ -261,9 +271,9 @@ systemd-logger.service: units/systemd-logger.service.in Makefile
 		< $< > $@
 
 CLEANFILES = \
-	systemd-interfaces.c \
-	systemctl.c \
-	systemadm.c \
+	src/systemd-interfaces.c \
+	src/systemctl.c \
+	src/systemadm.c \
 	systemd-initctl.service \
 	systemd-logger.service
 
diff --git a/automount.c b/automount.c
deleted file mode 100644
index 465354f..0000000
--- a/automount.c
+++ /dev/null
@@ -1,784 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <limits.h>
-#include <sys/mount.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <linux/auto_fs4.h>
-#include <linux/auto_dev-ioctl.h>
-
-#include "unit.h"
-#include "automount.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "unit-name.h"
-#include "dbus-automount.h"
-
-static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
-        [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
-        [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
-        [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
-        [AUTOMOUNT_MAINTAINANCE] = UNIT_INACTIVE,
-};
-
-static int open_dev_autofs(Manager *m);
-
-static void automount_init(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        a->pipe_watch.fd = a->pipe_fd = -1;
-        a->pipe_watch.type = WATCH_INVALID;
-}
-
-static void repeat_unmout(const char *path) {
-        assert(path);
-
-        for (;;) {
-
-                if (umount2(path, MNT_DETACH) >= 0)
-                        continue;
-
-                if (errno != EINVAL)
-                        log_error("Failed to unmount: %m");
-
-                break;
-        }
-}
-
-static void unmount_autofs(Automount *a) {
-        assert(a);
-
-        if (a->pipe_fd < 0)
-                return;
-
-        automount_send_ready(a, -EHOSTDOWN);
-
-        unit_unwatch_fd(UNIT(a), &a->pipe_watch);
-        close_nointr_nofail(a->pipe_fd);
-        a->pipe_fd = -1;
-
-        /* If we reload/reexecute things we keep the mount point
-         * around */
-        if (a->where &&
-            (UNIT(a)->meta.manager->exit_code != MANAGER_RELOAD &&
-             UNIT(a)->meta.manager->exit_code != MANAGER_REEXECUTE))
-                repeat_unmout(a->where);
-}
-
-static void automount_done(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        unmount_autofs(a);
-        a->mount = NULL;
-
-        free(a->where);
-        a->where = NULL;
-
-        set_free(a->tokens);
-        a->tokens = NULL;
-}
-
-int automount_add_one_mount_link(Automount *a, Mount *m) {
-        int r;
-
-        assert(a);
-        assert(m);
-
-        if (a->meta.load_state != UNIT_LOADED ||
-            m->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (!path_startswith(a->where, m->where))
-                return 0;
-
-        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(a), true)) < 0)
-                return r;
-
-        if ((r = unit_add_dependency(UNIT(a), UNIT_REQUIRES, UNIT(m), true)) < 0)
-                return r;
-
-        return 0;
-}
-
-static int automount_add_mount_links(Automount *a) {
-        Meta *other;
-        int r;
-
-        assert(a);
-
-        LIST_FOREACH(units_per_type, other, a->meta.manager->units_per_type[UNIT_MOUNT])
-                if ((r = automount_add_one_mount_link(a, (Mount*) other)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int automount_verify(Automount *a) {
-        bool b;
-        char *e;
-        assert(a);
-
-        if (UNIT(a)->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (!(e = unit_name_from_path(a->where, ".automount")))
-                return -ENOMEM;
-
-        b = unit_has_name(UNIT(a), e);
-        free(e);
-
-        if (!b) {
-                log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->meta.id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int automount_load(Unit *u) {
-        int r;
-        Automount *a = AUTOMOUNT(u);
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        /* Load a .automount file */
-        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
-                return r;
-
-        if (u->meta.load_state == UNIT_LOADED) {
-
-                if (!a->where)
-                        if (!(a->where = unit_name_to_path(u->meta.id)))
-                                return -ENOMEM;
-
-                path_kill_slashes(a->where);
-
-                if ((r = automount_add_mount_links(a)) < 0)
-                        return r;
-
-                if ((r = unit_load_related_unit(u, ".mount", (Unit**) &a->mount)) < 0)
-                        return r;
-
-                if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(a->mount), true)) < 0)
-                        return r;
-        }
-
-        return automount_verify(a);
-}
-
-static void automount_set_state(Automount *a, AutomountState state) {
-        AutomountState old_state;
-        assert(a);
-
-        old_state = a->state;
-        a->state = state;
-
-        if (state != AUTOMOUNT_WAITING &&
-            state != AUTOMOUNT_RUNNING)
-                unmount_autofs(a);
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(a)->meta.id,
-                          automount_state_to_string(old_state),
-                          automount_state_to_string(state));
-
-        unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int automount_coldplug(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-        int r;
-
-        assert(a);
-        assert(a->state == AUTOMOUNT_DEAD);
-
-        if (a->deserialized_state != a->state) {
-
-                if ((r = open_dev_autofs(u->meta.manager)) < 0)
-                        return r;
-
-                if (a->deserialized_state == AUTOMOUNT_WAITING ||
-                    a->deserialized_state == AUTOMOUNT_RUNNING) {
-
-                        assert(a->pipe_fd >= 0);
-
-                        if ((r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch)) < 0)
-                                return r;
-                }
-
-                automount_set_state(a, a->deserialized_state);
-        }
-
-        return 0;
-}
-
-static void automount_dump(Unit *u, FILE *f, const char *prefix) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        fprintf(f,
-                "%sAutomount State: %s\n"
-                "%sWhere: %s\n",
-                prefix, automount_state_to_string(a->state),
-                prefix, a->where);
-}
-
-static void automount_enter_dead(Automount *a, bool success) {
-        assert(a);
-
-        if (!success)
-                a->failure = true;
-
-        automount_set_state(a, a->failure ? AUTOMOUNT_MAINTAINANCE : AUTOMOUNT_DEAD);
-}
-
-static int open_dev_autofs(Manager *m) {
-        struct autofs_dev_ioctl param;
-
-        assert(m);
-
-        if (m->dev_autofs_fd >= 0)
-                return m->dev_autofs_fd;
-
-        if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) {
-                log_error("Failed to open /dev/autofs: %s", strerror(errno));
-                return -errno;
-        }
-
-        init_autofs_dev_ioctl(&param);
-        if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
-                close_nointr_nofail(m->dev_autofs_fd);
-                m->dev_autofs_fd = -1;
-                return -errno;
-        }
-
-        log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
-
-        return m->dev_autofs_fd;
-}
-
-static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
-        struct autofs_dev_ioctl *param;
-        size_t l;
-        int r;
-
-        assert(dev_autofs_fd >= 0);
-        assert(where);
-
-        l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
-
-        if (!(param = malloc(l)))
-                return -ENOMEM;
-
-        init_autofs_dev_ioctl(param);
-        param->size = l;
-        param->ioctlfd = -1;
-        param->openmount.devid = devid;
-        strcpy(param->path, where);
-
-        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (param->ioctlfd < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        fd_cloexec(param->ioctlfd, true);
-        r = param->ioctlfd;
-
-finish:
-        free(param);
-        return r;
-}
-
-static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
-        uint32_t major, minor;
-        struct autofs_dev_ioctl param;
-
-        assert(dev_autofs_fd >= 0);
-        assert(ioctl_fd >= 0);
-
-        init_autofs_dev_ioctl(&param);
-        param.ioctlfd = ioctl_fd;
-
-        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
-                return -errno;
-
-        major = param.protover.version;
-
-        init_autofs_dev_ioctl(&param);
-        param.ioctlfd = ioctl_fd;
-
-        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
-                return -errno;
-
-        minor = param.protosubver.sub_version;
-
-        log_debug("Autofs protocol version %i.%i", major, minor);
-        return 0;
-}
-
-static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
-        struct autofs_dev_ioctl param;
-
-        assert(dev_autofs_fd >= 0);
-        assert(ioctl_fd >= 0);
-
-        init_autofs_dev_ioctl(&param);
-        param.ioctlfd = ioctl_fd;
-        param.timeout.timeout = sec;
-
-        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
-        struct autofs_dev_ioctl param;
-
-        assert(dev_autofs_fd >= 0);
-        assert(ioctl_fd >= 0);
-
-        init_autofs_dev_ioctl(&param);
-        param.ioctlfd = ioctl_fd;
-
-        if (status) {
-                param.fail.token = token;
-                param.fail.status = status;
-        } else
-                param.ready.token = token;
-
-        if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int automount_send_ready(Automount *a, int status) {
-        int ioctl_fd, r;
-        unsigned token;
-
-        assert(a);
-        assert(status <= 0);
-
-        if (set_isempty(a->tokens))
-                return 0;
-
-        if ((ioctl_fd = open_ioctl_fd(UNIT(a)->meta.manager->dev_autofs_fd, a->where, a->dev_id)) < 0) {
-                r = ioctl_fd;
-                goto fail;
-        }
-
-        if (status)
-                log_debug("Sending failure: %s", strerror(-status));
-        else
-                log_debug("Sending success.");
-
-        /* Autofs thankfully does not hand out 0 as a token */
-        while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
-                int k;
-
-                /* Autofs fun fact II:
-                 *
-                 * if you pass a positive status code here, the kernel will
-                 * freeze! Yay! */
-
-                if ((k = autofs_send_ready(UNIT(a)->meta.manager->dev_autofs_fd,
-                                           ioctl_fd,
-                                           token,
-                                           status)) < 0)
-                        r = k;
-        }
-
-        r = 0;
-
-fail:
-        if (ioctl_fd >= 0)
-                close_nointr_nofail(ioctl_fd);
-
-        return r;
-}
-
-static void automount_enter_waiting(Automount *a) {
-        int p[2] = { -1, -1 };
-        char name[32], options[128];
-        bool mounted = false;
-        int r, ioctl_fd = -1, dev_autofs_fd;
-        struct stat st;
-
-        assert(a);
-        assert(a->pipe_fd < 0);
-        assert(a->where);
-
-        if (a->tokens)
-                set_clear(a->tokens);
-
-        if ((dev_autofs_fd = open_dev_autofs(UNIT(a)->meta.manager)) < 0) {
-                r = dev_autofs_fd;
-                goto fail;
-        }
-
-        /* We knowingly ignore the results of this call */
-        mkdir_p(a->where, 0555);
-
-        if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp());
-        char_array_0(options);
-
-        snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid());
-        char_array_0(name);
-
-        if (mount(name, a->where, "autofs", 0, options) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        mounted = true;
-
-        close_nointr_nofail(p[1]);
-        p[1] = -1;
-
-        if (stat(a->where, &st) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if ((ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev)) < 0) {
-                r = ioctl_fd;
-                goto fail;
-        }
-
-        if ((r = autofs_protocol(dev_autofs_fd, ioctl_fd)) < 0)
-                goto fail;
-
-        if ((r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300)) < 0)
-                goto fail;
-
-        /* Autofs fun fact:
-         *
-         * Unless we close the ioctl fd here, for some weird reason
-         * the direct mount will not receive events from the
-         * kernel. */
-
-        close_nointr_nofail(ioctl_fd);
-        ioctl_fd = -1;
-
-        if ((r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch)) < 0)
-                goto fail;
-
-        a->pipe_fd = p[0];
-        a->dev_id = st.st_dev;
-
-        automount_set_state(a, AUTOMOUNT_WAITING);
-
-        return;
-
-fail:
-        assert_se(close_pipe(p) == 0);
-
-        if (ioctl_fd >= 0)
-                close_nointr_nofail(ioctl_fd);
-
-        if (mounted)
-                repeat_unmout(a->where);
-
-        log_error("Failed to initialize automounter: %s", strerror(-r));
-        automount_enter_dead(a, false);
-}
-
-static void automount_enter_runnning(Automount *a) {
-        int r;
-        struct stat st;
-
-        assert(a);
-        assert(a->mount);
-
-        /* Before we do anything, let's see if somebody is playing games with us? */
-
-        if (stat(a->where, &st) < 0) {
-                log_warning("%s failed stat automount point: %m", a->meta.id);
-                goto fail;
-        }
-
-        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
-                log_info("%s's automount point already active?", a->meta.id);
-        else if ((r = manager_add_job(UNIT(a)->meta.manager, JOB_START, UNIT(a->mount), JOB_REPLACE, true, NULL)) < 0) {
-                log_warning("%s failed to queue mount startup job: %s", a->meta.id, strerror(-r));
-                goto fail;
-        }
-
-        automount_set_state(a, AUTOMOUNT_RUNNING);
-        return;
-
-fail:
-        automount_enter_dead(a, false);
-}
-
-static int automount_start(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        if (path_is_mount_point(a->where)) {
-                log_error("Path %s is already a mount point, refusing start for %s", a->where, u->meta.id);
-                return -EEXIST;
-        }
-
-        assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_MAINTAINANCE);
-
-        a->failure = false;
-        automount_enter_waiting(a);
-        return 0;
-}
-
-static int automount_stop(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
-
-        automount_enter_dead(a, true);
-        return 0;
-}
-
-static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Automount *a = AUTOMOUNT(u);
-        void *p;
-        Iterator i;
-
-        assert(a);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
-        unit_serialize_item(u, f, "failure", yes_no(a->failure));
-        unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
-
-        SET_FOREACH(p, a->tokens, i)
-                unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
-
-        if (a->pipe_fd >= 0) {
-                int copy;
-
-                if ((copy = fdset_put_dup(fds, a->pipe_fd)) < 0)
-                        return copy;
-
-                unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
-        }
-
-        return 0;
-}
-
-static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Automount *a = AUTOMOUNT(u);
-        int r;
-
-        assert(a);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                AutomountState state;
-
-                if ((state = automount_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        a->deserialized_state = state;
-        } else if (streq(key, "failure")) {
-                int b;
-
-                if ((b = parse_boolean(value)) < 0)
-                        log_debug("Failed to parse failure value %s", value);
-                else
-                        a->failure = b || a->failure;
-        } else if (streq(key, "dev-id")) {
-                unsigned d;
-
-                if (safe_atou(value, &d) < 0)
-                        log_debug("Failed to parse dev-id value %s", value);
-                else
-                        a->dev_id = (unsigned) d;
-        } else if (streq(key, "token")) {
-                unsigned token;
-
-                if (safe_atou(value, &token) < 0)
-                        log_debug("Failed to parse token value %s", value);
-                else {
-                        if (!a->tokens)
-                                if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func)))
-                                        return -ENOMEM;
-
-                        if ((r = set_put(a->tokens, UINT_TO_PTR(token))) < 0)
-                                return r;
-                }
-        } else if (streq(key, "pipe-fd")) {
-                int fd;
-
-                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
-                        log_debug("Failed to parse pipe-fd value %s", value);
-                else {
-                        if (a->pipe_fd >= 0)
-                                close_nointr_nofail(a->pipe_fd);
-
-                        a->pipe_fd = fdset_remove(fds, fd);
-                }
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState automount_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[AUTOMOUNT(u)->state];
-}
-
-static const char *automount_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return automount_state_to_string(AUTOMOUNT(u)->state);
-}
-
-static bool automount_check_gc(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        return UNIT_VTABLE(UNIT(a->mount))->check_gc(UNIT(a->mount));
-}
-
-static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
-        Automount *a = AUTOMOUNT(u);
-        union autofs_v5_packet_union packet;
-        ssize_t l;
-        int r;
-
-        assert(a);
-        assert(fd == a->pipe_fd);
-
-        if (events != EPOLLIN) {
-                log_error("Got invalid poll event on pipe.");
-                goto fail;
-        }
-
-        if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet))) != sizeof(packet)) {
-                log_error("Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
-                goto fail;
-        }
-
-        switch (packet.hdr.type) {
-
-        case autofs_ptype_missing_direct:
-                log_debug("Got direct mount request for %s", packet.v5_packet.name);
-
-                if (!a->tokens)
-                        if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) {
-                                log_error("Failed to allocate token set.");
-                                goto fail;
-                        }
-
-                if ((r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token))) < 0) {
-                        log_error("Failed to remember token: %s", strerror(-r));
-                        goto fail;
-                }
-
-                automount_enter_runnning(a);
-                break;
-
-        default:
-                log_error("Received unknown automount request %i", packet.hdr.type);
-                break;
-        }
-
-        return;
-
-fail:
-        automount_enter_dead(a, false);
-}
-
-static void automount_shutdown(Manager *m) {
-        assert(m);
-
-        if (m->dev_autofs_fd >= 0)
-                close_nointr_nofail(m->dev_autofs_fd);
-}
-
-static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
-        [AUTOMOUNT_DEAD] = "dead",
-        [AUTOMOUNT_WAITING] = "waiting",
-        [AUTOMOUNT_RUNNING] = "running",
-        [AUTOMOUNT_MAINTAINANCE] = "maintainance"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-
-const UnitVTable automount_vtable = {
-        .suffix = ".automount",
-
-        .no_alias = true,
-        .no_instances = true,
-
-        .init = automount_init,
-        .load = automount_load,
-        .done = automount_done,
-
-        .coldplug = automount_coldplug,
-
-        .dump = automount_dump,
-
-        .start = automount_start,
-        .stop = automount_stop,
-
-        .serialize = automount_serialize,
-        .deserialize_item = automount_deserialize_item,
-
-        .active_state = automount_active_state,
-        .sub_state_to_string = automount_sub_state_to_string,
-
-        .check_gc = automount_check_gc,
-
-        .fd_event = automount_fd_event,
-
-        .bus_message_handler = bus_automount_message_handler,
-
-        .shutdown = automount_shutdown
-};
diff --git a/automount.h b/automount.h
deleted file mode 100644
index 014482c..0000000
--- a/automount.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooautomounthfoo
-#define fooautomounthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Automount Automount;
-
-#include "unit.h"
-
-typedef enum AutomountState {
-        AUTOMOUNT_DEAD,
-        AUTOMOUNT_WAITING,
-        AUTOMOUNT_RUNNING,
-        AUTOMOUNT_MAINTAINANCE,
-        _AUTOMOUNT_STATE_MAX,
-        _AUTOMOUNT_STATE_INVALID = -1
-} AutomountState;
-
-struct Automount {
-        Meta meta;
-
-        AutomountState state, deserialized_state;
-
-        char *where;
-
-        Mount *mount;
-
-        int pipe_fd;
-        Watch pipe_watch;
-        dev_t dev_id;
-
-        Set *tokens;
-
-        bool failure:1;
-};
-
-extern const UnitVTable automount_vtable;
-
-int automount_send_ready(Automount *a, int status);
-
-int automount_add_one_mount_link(Automount *a, Mount *m);
-
-const char* automount_state_to_string(AutomountState i);
-AutomountState automount_state_from_string(const char *s);
-
-#endif
diff --git a/cgroup.c b/cgroup.c
deleted file mode 100644
index 301fc94..0000000
--- a/cgroup.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <sys/mount.h>
-
-#include "cgroup.h"
-#include "log.h"
-
-static int translate_error(int error, int _errno) {
-
-        switch (error) {
-
-        case ECGROUPNOTCOMPILED:
-        case ECGROUPNOTMOUNTED:
-        case ECGROUPNOTEXIST:
-        case ECGROUPNOTCREATED:
-                return -ENOENT;
-
-        case ECGINVAL:
-                return -EINVAL;
-
-        case ECGROUPNOTALLOWED:
-                return -EPERM;
-
-        case ECGOTHER:
-                return -_errno;
-        }
-
-        return -EIO;
-}
-
-int cgroup_bonding_realize(CGroupBonding *b) {
-        int r;
-
-        assert(b);
-        assert(b->path);
-        assert(b->controller);
-
-        if (b->cgroup)
-                return 0;
-
-        if (!(b->cgroup = cgroup_new_cgroup(b->path)))
-                return -ENOMEM;
-
-        if (!cgroup_add_controller(b->cgroup, b->controller)) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (b->inherit)
-                r = cgroup_create_cgroup_from_parent(b->cgroup, true);
-        else
-                r = cgroup_create_cgroup(b->cgroup, true);
-
-        if (r != 0) {
-                r = translate_error(r, errno);
-                goto fail;
-        }
-
-        return 0;
-
-fail:
-        cgroup_free(&b->cgroup);
-        b->cgroup = NULL;
-        return r;
-}
-
-int cgroup_bonding_realize_list(CGroupBonding *first) {
-        CGroupBonding *b;
-
-        LIST_FOREACH(by_unit, b, first) {
-                int r;
-
-                if ((r = cgroup_bonding_realize(b)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-void cgroup_bonding_free(CGroupBonding *b) {
-        assert(b);
-
-        if (b->unit) {
-                CGroupBonding *f;
-
-                LIST_REMOVE(CGroupBonding, by_unit, b->unit->meta.cgroup_bondings, b);
-
-                assert_se(f = hashmap_get(b->unit->meta.manager->cgroup_bondings, b->path));
-                LIST_REMOVE(CGroupBonding, by_path, f, b);
-
-                if (f)
-                        hashmap_replace(b->unit->meta.manager->cgroup_bondings, b->path, f);
-                else
-                        hashmap_remove(b->unit->meta.manager->cgroup_bondings, b->path);
-        }
-
-        if (b->cgroup) {
-                if (b->only_us && b->clean_up && cgroup_bonding_is_empty(b) > 0)
-                        cgroup_delete_cgroup_ext(b->cgroup, true);
-
-                cgroup_free(&b->cgroup);
-        }
-
-        free(b->controller);
-        free(b->path);
-        free(b);
-}
-
-void cgroup_bonding_free_list(CGroupBonding *first) {
-        CGroupBonding *b, *n;
-
-        LIST_FOREACH_SAFE(by_unit, b, n, first)
-                cgroup_bonding_free(b);
-}
-
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
-        int r;
-
-        assert(b);
-        assert(pid >= 0);
-
-        if (pid == 0)
-                pid = getpid();
-
-        if (!b->cgroup)
-                return -ENOENT;
-
-        if ((r = cgroup_attach_task_pid(b->cgroup, pid)))
-                return translate_error(r, errno);
-
-        return 0;
-}
-
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
-        CGroupBonding *b;
-
-        LIST_FOREACH(by_unit, b, first) {
-                int r;
-
-                if ((r = cgroup_bonding_install(b, pid)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int cgroup_bonding_kill(CGroupBonding *b, int sig) {
-        int r;
-        Set *s;
-        bool done;
-        bool killed = false;
-
-        assert(b);
-        assert(sig > 0);
-
-        if (!b->only_us)
-                return -EAGAIN;
-
-        if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
-                return -ENOMEM;
-
-        do {
-                void *iterator;
-                pid_t pid;
-
-                done = true;
-
-                if ((r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid)) != 0) {
-                        if (r == ECGEOF) {
-                                r = 0;
-                                goto kill_done;
-                        } else {
-                                r = translate_error(r, errno);
-                                break;
-                        }
-                }
-
-                for (;;) {
-                        if (set_get(s, INT_TO_PTR(pid)) != INT_TO_PTR(pid)) {
-
-                                /* If we haven't killed this process
-                                 * yet, kill it */
-
-                                if (kill(pid, sig) < 0 && errno != ESRCH) {
-                                        r = -errno;
-                                        break;
-                                }
-
-                                killed = true;
-                                done = false;
-
-                                if ((r = set_put(s, INT_TO_PTR(pid))) < 0)
-                                    break;
-                        }
-
-                        if ((r = cgroup_get_task_next(&iterator, &pid)) != 0) {
-
-                                if (r == ECGEOF)
-                                        r = 0;
-                                else
-                                        r = translate_error(r, errno);
-
-                                break;
-                        }
-                }
-
-        kill_done:
-                assert_se(cgroup_get_task_end(&iterator) == 0);
-
-                /* To avoid racing against processes which fork
-                 * quicker than we can kill them we repeat this until
-                 * no new pids need to be killed. */
-
-        } while (!done && r >= 0);
-
-        set_free(s);
-
-        if (r < 0)
-                return r;
-
-        return killed ? 0 : -ESRCH;
-}
-
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig) {
-        CGroupBonding *b;
-        int r = -EAGAIN;
-
-        LIST_FOREACH(by_unit, b, first) {
-                if ((r = cgroup_bonding_kill(b, sig)) < 0) {
-                        if (r == -EAGAIN || -ESRCH)
-                                continue;
-
-                        return r;
-                }
-
-                return 0;
-        }
-
-        return r;
-}
-
-/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
- * cannot know */
-int cgroup_bonding_is_empty(CGroupBonding *b) {
-        void *iterator;
-        pid_t pid;
-        int r;
-
-        assert(b);
-
-        r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid);
-
-        if (r == 0 || r == ECGEOF)
-                cgroup_get_task_end(&iterator);
-
-        /* Hmm, no PID in this group? Then it is definitely empty */
-        if (r == ECGEOF)
-                return 1;
-
-        /* Some error? Let's return it */
-        if (r != 0)
-                return translate_error(r, errno);
-
-        /* It's not empty, and we are the only user, then it is
-         * definitely not empty */
-        if (b->only_us)
-                return 0;
-
-        /* There are PIDs in the group but we aren't the only users,
-         * hence we cannot say */
-        return -EAGAIN;
-}
-
-int cgroup_bonding_is_empty_list(CGroupBonding *first) {
-        CGroupBonding *b;
-
-        LIST_FOREACH(by_unit, b, first) {
-                int r;
-
-                if ((r = cgroup_bonding_is_empty(b)) < 0) {
-                        /* If this returned -EAGAIN, then we don't know if the
-                         * group is empty, so let's see if another group can
-                         * tell us */
-
-                        if (r != -EAGAIN)
-                                return r;
-                } else
-                        return r;
-        }
-
-        return -EAGAIN;
-}
-
-static int install_release_agent(Manager *m, const char *mount_point) {
-        char *p, *c, *sc;
-        int r;
-
-        assert(m);
-        assert(mount_point);
-
-        if (asprintf(&p, "%s/release_agent", mount_point) < 0)
-                return -ENOMEM;
-
-        if ((r = read_one_line_file(p, &c)) < 0) {
-                free(p);
-                return r;
-        }
-
-        sc = strstrip(c);
-
-        if (sc[0] == 0) {
-                if ((r = write_one_line_file(p, CGROUP_AGENT_PATH "\n" )) < 0) {
-                        free(p);
-                        free(c);
-                        return r;
-                }
-        } else if (!streq(sc, CGROUP_AGENT_PATH)) {
-                free(p);
-                free(c);
-                return -EEXIST;
-        }
-
-        free(c);
-        free(p);
-
-        if (asprintf(&p, "%s/notify_on_release", mount_point) < 0)
-                return -ENOMEM;
-
-        if ((r = read_one_line_file(p, &c)) < 0) {
-                free(p);
-                return r;
-        }
-
-        sc = strstrip(c);
-
-        if (streq(sc, "0")) {
-                if ((r = write_one_line_file(p, "1\n")) < 0) {
-                        free(p);
-                        free(c);
-                        return r;
-                }
-        } else if (!streq(sc, "1")) {
-                free(p);
-                free(c);
-                return -EIO;
-        }
-
-        free(p);
-        free(c);
-
-        return 0;
-}
-
-static int create_hierarchy_cgroup(Manager *m) {
-        struct cgroup *cg;
-        int r;
-
-        assert(m);
-
-        if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy)))
-                return -ENOMEM;
-
-        if (!(cgroup_add_controller(cg, m->cgroup_controller))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if ((r = cgroup_create_cgroup(cg, true)) != 0) {
-                log_error("Failed to create cgroup hierarchy group: %s", cgroup_strerror(r));
-                r = translate_error(r, errno);
-                goto finish;
-        }
-
-        if ((r = cgroup_attach_task(cg)) != 0) {
-                log_error("Failed to add ourselves to hierarchy group: %s", cgroup_strerror(r));
-                r = translate_error(r, errno);
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        cgroup_free(&cg);
-        return r;
-}
-
-int manager_setup_cgroup(Manager *m) {
-        char *mp, *cp;
-        int r;
-        pid_t pid;
-        char suffix[32];
-
-        assert(m);
-
-        if ((r = cgroup_init()) != 0) {
-                log_error("Failed to initialize libcg: %s", cgroup_strerror(r));
-                return translate_error(r, errno);
-        }
-
-        free(m->cgroup_controller);
-        if (!(m->cgroup_controller = strdup("debug")))
-                return -ENOMEM;
-
-        if ((r = cgroup_get_subsys_mount_point(m->cgroup_controller, &mp)))
-                return translate_error(r, errno);
-
-        pid = getpid();
-
-        if ((r = cgroup_get_current_controller_path(pid, m->cgroup_controller, &cp))) {
-                free(mp);
-                return translate_error(r, errno);
-        }
-
-        snprintf(suffix, sizeof(suffix), "/systemd-%u", (unsigned) pid);
-        char_array_0(suffix);
-
-        free(m->cgroup_hierarchy);
-
-        if (endswith(cp, suffix))
-                /* We probably got reexecuted and can continue to use our root cgroup */
-                m->cgroup_hierarchy = cp;
-        else {
-                /* We need a new root cgroup */
-
-                m->cgroup_hierarchy = NULL;
-                r = asprintf(&m->cgroup_hierarchy, "%s%s", streq(cp, "/") ? "" : cp, suffix);
-                free(cp);
-
-                if (r < 0) {
-                        free(mp);
-                        return -ENOMEM;
-                }
-        }
-
-        log_debug("Using cgroup controller <%s>, hierarchy mounted at <%s>, using root group <%s>.",
-                  m->cgroup_controller,
-                  mp,
-                  m->cgroup_hierarchy);
-
-        if ((r = install_release_agent(m, mp)) < 0)
-                log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
-        else
-                log_debug("Installed release agent, or already installed.");
-
-        free(mp);
-
-        if ((r = create_hierarchy_cgroup(m)) < 0)
-                log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
-        else
-                log_debug("Created root group.");
-
-        return r;
-}
-
-int manager_shutdown_cgroup(Manager *m, bool delete) {
-        struct cgroup *cg;
-        int r;
-
-        assert(m);
-
-        if (!m->cgroup_hierarchy)
-                return 0;
-
-        if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy)))
-                return -ENOMEM;
-
-        if (!(cgroup_add_controller(cg, m->cgroup_controller))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        /* Often enough we won't be able to delete the cgroup we
-         * ourselves are in, hence ignore all errors here */
-        if (delete)
-                cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_IGNORE_MIGRATION|CGFLAG_DELETE_RECURSIVE);
-        r = 0;
-
-finish:
-        cgroup_free(&cg);
-        return r;
-
-}
-
-int cgroup_notify_empty(Manager *m, const char *group) {
-        CGroupBonding *l, *b;
-
-        assert(m);
-        assert(group);
-
-        if (!(l = hashmap_get(m->cgroup_bondings, group)))
-                return 0;
-
-        LIST_FOREACH(by_path, b, l) {
-                int t;
-
-                if (!b->unit)
-                        continue;
-
-                if ((t = cgroup_bonding_is_empty_list(b)) < 0) {
-
-                        /* If we don't know, we don't know */
-                        if (t != -EAGAIN)
-                                log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
-
-                        continue;
-                }
-
-                if (t > 0)
-                        if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
-                                UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
-        }
-
-        return 0;
-}
-
-CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
-        CGroupBonding *b;
-
-        assert(controller);
-
-        LIST_FOREACH(by_unit, b, first)
-                if (streq(b->controller, controller))
-                        return b;
-
-        return NULL;
-}
-
-char *cgroup_bonding_to_string(CGroupBonding *b) {
-        char *r;
-
-        assert(b);
-
-        if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
-                return NULL;
-
-        return r;
-}
diff --git a/cgroup.h b/cgroup.h
deleted file mode 100644
index d27c063..0000000
--- a/cgroup.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foocgrouphfoo
-#define foocgrouphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <libcgroup.h>
-
-typedef struct CGroupBonding CGroupBonding;
-
-#include "unit.h"
-
-/* Binds a cgroup to a name */
-struct CGroupBonding {
-        char *controller;
-        char *path;
-
-        Unit *unit;
-
-        struct cgroup *cgroup;
-
-        /* For the Unit::cgroup_bondings list */
-        LIST_FIELDS(CGroupBonding, by_unit);
-
-        /* For the Manager::cgroup_bondings hashmap */
-        LIST_FIELDS(CGroupBonding, by_path);
-
-        /* When shutting down, remove cgroup? */
-        bool clean_up:1;
-
-        /* When our tasks are the only ones in this group */
-        bool only_us:1;
-
-        /* Inherit parameters from parent group */
-        bool inherit:1;
-};
-
-int cgroup_bonding_realize(CGroupBonding *b);
-int cgroup_bonding_realize_list(CGroupBonding *first);
-
-void cgroup_bonding_free(CGroupBonding *b);
-void cgroup_bonding_free_list(CGroupBonding *first);
-
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid);
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid);
-
-int cgroup_bonding_kill(CGroupBonding *b, int sig);
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig);
-
-int cgroup_bonding_is_empty(CGroupBonding *b);
-int cgroup_bonding_is_empty_list(CGroupBonding *first);
-
-CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller);
-
-char *cgroup_bonding_to_string(CGroupBonding *b);
-
-#include "manager.h"
-
-int manager_setup_cgroup(Manager *m);
-int manager_shutdown_cgroup(Manager *m, bool delete);
-
-int cgroup_notify_empty(Manager *m, const char *group);
-
-#endif
diff --git a/cgroups-agent.c b/cgroups-agent.c
deleted file mode 100644
index 232b63e..0000000
--- a/cgroups-agent.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "log.h"
-
-int main(int argc, char *argv[]) {
-        DBusError error;
-        DBusConnection *bus = NULL;
-        DBusMessage *m = NULL;
-        int r = 1;
-
-        dbus_error_init(&error);
-
-        if (argc != 2) {
-                log_error("Incorrect number of arguments.");
-                goto finish;
-        }
-
-        if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
-                log_error("Failed to get D-Bus connection: %s", error.message);
-                goto finish;
-        }
-
-        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1/agent", "org.freedesktop.systemd1.Agent", "Released"))) {
-                log_error("Could not allocate signal message.");
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &argv[1],
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not attach group information to signal message.");
-                goto finish;
-        }
-
-        if (!dbus_connection_send(bus, m, NULL)) {
-                log_error("Failed to send signal message.");
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        if (bus)
-                dbus_connection_unref(bus);
-
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-        return r;
-}
diff --git a/conf-parser.c b/conf-parser.c
deleted file mode 100644
index 6994211..0000000
--- a/conf-parser.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <assert.h>
-#include <stdlib.h>
-
-#include "conf-parser.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-
-#define COMMENTS "#;\n"
-#define LINE_MAX 4096
-
-/* Run the user supplied parser for an assignment */
-static int next_assignment(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const ConfigItem *t,
-                const char *lvalue,
-                const char *rvalue,
-                void *userdata) {
-
-        assert(filename);
-        assert(t);
-        assert(lvalue);
-        assert(rvalue);
-
-        for (; t->parse; t++) {
-
-                if (t->lvalue && !streq(lvalue, t->lvalue))
-                        continue;
-
-                if (t->section && !section)
-                        continue;
-
-                if (t->section && !streq(section, t->section))
-                        continue;
-
-                return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
-        }
-
-        /* Warn about unknown non-extension fields. */
-        if (!startswith(lvalue, "X-"))
-                log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
-
-        return 0;
-}
-
-/* Parse a variable assignment line */
-static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
-        char *e;
-
-        l = strstrip(l);
-
-        if (!*l)
-                return 0;
-
-        if (strchr(COMMENTS, *l))
-                return 0;
-
-        if (startswith(l, ".include ")) {
-                char *fn;
-                int r;
-
-                if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
-                        return -ENOMEM;
-
-                r = config_parse(fn, NULL, sections, t, userdata);
-                free(fn);
-
-                return r;
-        }
-
-        if (*l == '[') {
-                size_t k;
-                char *n;
-
-                k = strlen(l);
-                assert(k > 0);
-
-                if (l[k-1] != ']') {
-                        log_error("[%s:%u] Invalid section header.", filename, line);
-                        return -EBADMSG;
-                }
-
-                if (!(n = strndup(l+1, k-2)))
-                        return -ENOMEM;
-
-                if (sections && !strv_contains((char**) sections, n)) {
-                        log_error("[%s:%u] Unknown section '%s'.", filename, line, n);
-                        free(n);
-                        return -EBADMSG;
-                }
-
-                free(*section);
-                *section = n;
-
-                return 0;
-        }
-
-        if (!(e = strchr(l, '='))) {
-                log_error("[%s:%u] Missing '='.", filename, line);
-                return -EBADMSG;
-        }
-
-        *e = 0;
-        e++;
-
-        return next_assignment(filename, line, *section, t, strstrip(l), strstrip(e), userdata);
-}
-
-/* Go through the file and parse each line */
-int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
-        unsigned line = 0;
-        char *section = NULL;
-        int r;
-        bool ours = false;
-
-        assert(filename);
-        assert(t);
-
-        if (!f) {
-                if (!(f = fopen(filename, "re"))) {
-                        r = -errno;
-                        log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
-                        goto finish;
-                }
-
-                ours = true;
-        }
-
-        while (!feof(f)) {
-                char l[LINE_MAX];
-
-                if (!fgets(l, sizeof(l), f)) {
-                        if (feof(f))
-                                break;
-
-                        r = -errno;
-                        log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
-                        goto finish;
-                }
-
-                if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        free(section);
-
-        if (f && ours)
-                fclose(f);
-
-        return r;
-}
-
-int config_parse_int(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *i = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atoi(rvalue, i)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        return 0;
-}
-
-int config_parse_unsigned(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        unsigned *u = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atou(rvalue, u)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        return 0;
-}
-
-int config_parse_size(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        size_t *sz = data;
-        unsigned u;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atou(rvalue, &u)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        *sz = (size_t) u;
-        return 0;
-}
-
-int config_parse_bool(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int k;
-        bool *b = data;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((k = parse_boolean(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
-                return k;
-        }
-
-        *b = !!k;
-        return 0;
-}
-
-int config_parse_string(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char **s = data;
-        char *n;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (*rvalue) {
-                if (!(n = strdup(rvalue)))
-                        return -ENOMEM;
-        } else
-                n = NULL;
-
-        free(*s);
-        *s = n;
-
-        return 0;
-}
-
-int config_parse_path(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char **s = data;
-        char *n;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (!path_is_absolute(rvalue)) {
-                log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
-                return -EINVAL;
-        }
-
-        if (!(n = strdup(rvalue)))
-                return -ENOMEM;
-
-        free(*s);
-        *s = n;
-
-        return 0;
-}
-
-int config_parse_strv(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char*** sv = data;
-        char **n;
-        char *w;
-        unsigned k;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        k = strv_length(*sv);
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
-
-        if (!(n = new(char*, k+1)))
-                return -ENOMEM;
-
-        if (*sv)
-                for (k = 0; (*sv)[k]; k++)
-                        n[k] = (*sv)[k];
-        else
-                k = 0;
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                if (!(n[k++] = strndup(w, l)))
-                        goto fail;
-
-        n[k] = NULL;
-        free(*sv);
-        *sv = n;
-
-        return 0;
-
-fail:
-        for (; k > 0; k--)
-                free(n[k-1]);
-        free(n);
-
-        return -ENOMEM;
-}
-
-int config_parse_path_strv(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char*** sv = data;
-        char **n;
-        char *w;
-        unsigned k;
-        size_t l;
-        char *state;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        k = strv_length(*sv);
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
-
-        if (!(n = new(char*, k+1)))
-                return -ENOMEM;
-
-        k = 0;
-        if (*sv)
-                for (; (*sv)[k]; k++)
-                        n[k] = (*sv)[k];
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                if (!(n[k] = strndup(w, l))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                if (!path_is_absolute(n[k])) {
-                        log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
-                        r = -EINVAL;
-                        goto fail;
-                }
-
-                k++;
-        }
-
-        n[k] = NULL;
-        free(*sv);
-        *sv = n;
-
-        return 0;
-
-fail:
-        free(n[k]);
-        for (; k > 0; k--)
-                free(n[k-1]);
-        free(n);
-
-        return r;
-}
diff --git a/conf-parser.h b/conf-parser.h
deleted file mode 100644
index bea2a8e..0000000
--- a/conf-parser.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooconfparserhfoo
-#define fooconfparserhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-
-/* An abstract parser for simple, line based, shallow configuration
- * files consisting of variable assignments only. */
-
-typedef int (*ConfigParserCallback)(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-
-/* Wraps info for parsing a specific configuration variable */
-typedef struct ConfigItem {
-        const char *lvalue; /* name of the variable */
-        ConfigParserCallback parse; /* Function that is called to parse the variable's value */
-        void *data; /* Where to store the variable's data */
-        const char *section;
-} ConfigItem;
-
-/* The configuration file parsing routine. Expects a table of
- * config_items in *t that is terminated by an item where lvalue is
- * NULL */
-int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata);
-
-/* Generic parsers */
-int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-
-#endif
diff --git a/configure.ac b/configure.ac
index 1d2efc3..691d970 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,11 +18,11 @@
 AC_PREREQ(2.63)
 
 AC_INIT([systemd],[0],[systemd-devel at lists.freedesktop.org])
-AC_CONFIG_SRCDIR([main.c])
+AC_CONFIG_SRCDIR([src/main.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS([config.h])
 
-AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax])
+AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax subdir-objects])
 
 AC_SUBST(PACKAGE_URL, [http://www.freedesktop.org/wiki/Software/systemd])
 
diff --git a/dbus-automount.c b/dbus-automount.c
deleted file mode 100644
index 9003b74..0000000
--- a/dbus-automount.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-automount.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Automount\">"
-        "  <property name=\"Where\" type=\"s\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Automount", "Where", bus_property_append_string, "s", u->automount.where },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-automount.h b/dbus-automount.h
deleted file mode 100644
index 947bf0f..0000000
--- a/dbus-automount.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusautomounthfoo
-#define foodbusautomounthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-device.c b/dbus-device.c
deleted file mode 100644
index 8376478..0000000
--- a/dbus-device.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-device.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Device\">"
-        "  <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Device", "SysFSPath", bus_property_append_string, "s", u->device.sysfs },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-device.h b/dbus-device.h
deleted file mode 100644
index f2850a6..0000000
--- a/dbus-device.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusdevicehfoo
-#define foodbusdevicehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-execute.c b/dbus-execute.c
deleted file mode 100644
index 8840396..0000000
--- a/dbus-execute.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <dbus/dbus.h>
-
-#include "dbus-execute.h"
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
diff --git a/dbus-execute.h b/dbus-execute.h
deleted file mode 100644
index 25ecd98..0000000
--- a/dbus-execute.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusexecutehfoo
-#define foodbusexecutehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "manager.h"
-
-#define BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>" \
-        "  <property name=\"UMask\" type=\"u\" access=\"read\"/>"       \
-        "  <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>" \
-        "  <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>" \
-        "  <property name=\"StandardInput\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"StandardError\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>"     \
-        "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>" \
-        "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>"  \
-        "  <property name=\"CapabilityBoundingSetDrop\" type=\"t\" access=\"read\"/>" \
-        "  <property name=\"User\" type=\"s\" access=\"read\"/>"        \
-        "  <property name=\"Group\" type=\"s\" access=\"read\"/>"       \
-        "  <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>"
-
-#define BUS_EXEC_CONTEXT_PROPERTIES(interface, context)                 \
-        { interface, "Environment",                   bus_property_append_strv,   "as",    (context).environment                   }, \
-        { interface, "UMask",                         bus_property_append_mode,   "u",     &(context).umask                        }, \
-            /* RLimits */                                               \
-        { interface, "WorkingDirectory",              bus_property_append_string, "s",     (context).working_directory             }, \
-        { interface, "RootDirectory",                 bus_property_append_string, "s",     (context).root_directory                }, \
-            /* OOM Adjust */                                            \
-            /* Nice */                                                  \
-            /* IOPrio */                                                \
-            /* CPUSchedPolicy */                                        \
-            /* CPUSchedPriority */                                      \
-            /* CPUAffinity */                                           \
-            /* TimerSlackNS */                                          \
-        { interface, "CPUSchedulingResetOnFork",      bus_property_append_bool,   "b",     &(context).cpu_sched_reset_on_fork      }, \
-        { interface, "NonBlocking",                   bus_property_append_bool,   "b",     &(context).non_blocking                 }, \
-        { interface, "StandardInput",                 bus_execute_append_input,   "s",     &(context).std_input                    }, \
-        { interface, "StandardOutput",                bus_execute_append_output,  "s",     &(context).std_output                   }, \
-        { interface, "StandardError",                 bus_execute_append_output,  "s",     &(context).std_error                    }, \
-        { interface, "TTYPath",                       bus_property_append_string, "s",     (context).tty_path                      }, \
-        { interface, "SyslogPriority",                bus_property_append_int,    "i",     &(context).syslog_priority              }, \
-        { interface, "SyslogIdentifier",              bus_property_append_string, "s",     (context).syslog_identifier             }, \
-            /* CAPABILITIES */                                          \
-        { interface, "SecureBits",                    bus_property_append_int,    "i",     &(context).secure_bits                  }, \
-        { interface, "CapabilityBoundingSetDrop",     bus_property_append_uint64, "t",     &(context).capability_bounding_set_drop }, \
-        { interface, "User",                          bus_property_append_string, "s",     (context).user                          }, \
-        { interface, "Group",                         bus_property_append_string, "s",     (context).group                         }, \
-        { interface, "SupplementaryGroups",           bus_property_append_strv,   "as",    (context).supplementary_groups          }
-
-int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data);
-
-#endif
diff --git a/dbus-job.c b/dbus-job.c
deleted file mode 100644
index 3a6e715..0000000
--- a/dbus-job.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-job.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        " <interface name=\"org.freedesktop.systemd1.Job\">"
-        "  <method name=\"Cancel\"/>"
-        "  <signal name=\"Changed\"/>"
-        "  <property name=\"Id\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>"
-        "  <property name=\"JobType\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"State\" type=\"s\" access=\"read\"/>"
-        " </interface>"
-        BUS_PROPERTIES_INTERFACE
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType);
-
-static int bus_job_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Job *j = data;
-        DBusMessageIter sub;
-        char *p;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(j);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
-                return -ENOMEM;
-
-        if (!(p = unit_dbus_path(j->unit)))
-                return -ENOMEM;
-
-        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->meta.id) ||
-            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
-                free(p);
-                return -ENOMEM;
-        }
-
-        free(p);
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusMessage *message) {
-        const BusProperty properties[] = {
-                { "org.freedesktop.systemd1.Job", "Id",      bus_property_append_uint32, "u",    &j->id    },
-                { "org.freedesktop.systemd1.Job", "State",   bus_job_append_state,       "s",    &j->state },
-                { "org.freedesktop.systemd1.Job", "JobType", bus_job_append_type,        "s",    &j->type  },
-                { "org.freedesktop.systemd1.Job", "Unit",    bus_job_append_unit,        "(so)", j         },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        DBusMessage *reply = NULL;
-        Manager *m = j->manager;
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                job_free(j);
-
-        } else
-                return bus_default_message_handler(j->manager, message, introspection, properties);
-
-        if (reply) {
-                if (!dbus_connection_send(m->api_bus, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-static DBusHandlerResult bus_job_message_handler(DBusConnection  *connection, DBusMessage  *message, void *data) {
-        Manager *m = data;
-        Job *j;
-        int r;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        log_debug("Got D-Bus request: %s.%s() on %s",
-                  dbus_message_get_interface(message),
-                  dbus_message_get_member(message),
-                  dbus_message_get_path(message));
-
-        if ((r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j)) < 0) {
-
-                if (r == -ENOMEM)
-                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
-                if (r == -ENOENT)
-                        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-                return bus_send_error_reply(m, message, NULL, r);
-        }
-
-        return bus_job_message_dispatch(j, message);
-}
-
-const DBusObjectPathVTable bus_job_vtable = {
-        .message_function = bus_job_message_handler
-};
-
-void bus_job_send_change_signal(Job *j) {
-        char *p = NULL;
-        DBusMessage *m = NULL;
-
-        assert(j);
-        assert(j->in_dbus_queue);
-
-        LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
-        j->in_dbus_queue = false;
-
-        if (set_isempty(j->manager->subscribed)) {
-                j->sent_dbus_new_signal = true;
-                return;
-        }
-
-        if (!(p = job_dbus_path(j)))
-                goto oom;
-
-        if (j->sent_dbus_new_signal) {
-                /* Send a change signal */
-
-                if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Job", "Changed")))
-                        goto oom;
-        } else {
-                /* Send a new signal */
-
-                if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew")))
-                        goto oom;
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_UINT32, &j->id,
-                                              DBUS_TYPE_OBJECT_PATH, &p,
-                                              DBUS_TYPE_INVALID))
-                        goto oom;
-        }
-
-        if (!dbus_connection_send(j->manager->api_bus, m, NULL))
-                goto oom;
-
-        free(p);
-        dbus_message_unref(m);
-
-        j->sent_dbus_new_signal = true;
-
-        return;
-
-oom:
-        free(p);
-
-        if (m)
-                dbus_message_unref(m);
-
-        log_error("Failed to allocate job change signal.");
-}
-
-void bus_job_send_removed_signal(Job *j) {
-        char *p = NULL;
-        DBusMessage *m = NULL;
-
-        assert(j);
-
-        if (set_isempty(j->manager->subscribed) || !j->sent_dbus_new_signal)
-                return;
-
-        if (!(p = job_dbus_path(j)))
-                goto oom;
-
-        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved")))
-                goto oom;
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_UINT32, &j->id,
-                                      DBUS_TYPE_OBJECT_PATH, &p,
-                                      DBUS_TYPE_INVALID))
-                goto oom;
-
-        if (!dbus_connection_send(j->manager->api_bus, m, NULL))
-                goto oom;
-
-        free(p);
-        dbus_message_unref(m);
-
-        return;
-
-oom:
-        free(p);
-
-        if (m)
-                dbus_message_unref(m);
-
-        log_error("Failed to allocate job remove signal.");
-}
diff --git a/dbus-job.h b/dbus-job.h
deleted file mode 100644
index cf91760..0000000
--- a/dbus-job.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusjobhfoo
-#define foodbusjobhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-void bus_job_send_change_signal(Job *j);
-void bus_job_send_removed_signal(Job *j);
-
-extern const DBusObjectPathVTable bus_job_vtable;
-
-#endif
diff --git a/dbus-manager.c b/dbus-manager.c
deleted file mode 100644
index 90ab8d1..0000000
--- a/dbus-manager.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-manager.h"
-#include "strv.h"
-
-#define INTROSPECTION_BEGIN                                             \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>"                                                        \
-        " <interface name=\"org.freedesktop.systemd1.Manager\">"        \
-        "  <method name=\"GetUnit\">"                                   \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>"          \
-        "  </method>"                                                   \
-        "  <method name=\"LoadUnit\">"                                  \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>"          \
-        "  </method>"                                                   \
-        "  <method name=\"GetJob\">"                                    \
-        "   <arg name=\"id\" type=\"u\" direction=\"in\"/>"             \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
-        "  </method>"                                                   \
-        "  <method name=\"ClearJobs\"/>"                                \
-        "  <method name=\"ListUnits\">"                                 \
-        "   <arg name=\"units\" type=\"a(sssssouso)\" direction=\"out\"/>" \
-        "  </method>"                                                   \
-        "  <method name=\"ListJobs\">"                                  \
-        "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>"  \
-        "  </method>"                                                   \
-        "  <method name=\"Subscribe\"/>"                                \
-        "  <method name=\"Unsubscribe\"/>"                              \
-        "  <method name=\"Dump\"/>"                                     \
-        "  <method name=\"CreateSnapshot\">"                            \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg nane=\"cleanup\" type=\"b\" direction=\"in\"/>"        \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>"          \
-        "  </method>"                                                   \
-        "  <method name=\"Reload\"/>"                                   \
-        "  <method name=\"Reexecute\"/>"                                \
-        "  <method name=\"Exit\"/>"                                     \
-        "  <method name=\"SetEnvironment\">"                            \
-        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>"         \
-        "  </method>"                                                   \
-        "  <method name=\"UnsetEnvironment\">"                          \
-        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>"         \
-        "  </method>"                                                   \
-        "  <signal name=\"UnitNew\">"                                   \
-        "   <arg name=\"id\" type=\"s\"/>"                              \
-        "   <arg name=\"unit\" type=\"o\"/>"                            \
-        "  </signal>"                                                   \
-        "  <signal name=\"UnitRemoved\">"                               \
-        "   <arg name=\"id\" type=\"s\"/>"                              \
-        "   <arg name=\"unit\" type=\"o\"/>"                            \
-        "  </signal>"                                                   \
-        "  <signal name=\"JobNew\">"                                    \
-        "   <arg name=\"id\" type=\"u\"/>"                              \
-        "   <arg name=\"job\" type=\"o\"/>"                             \
-        "  </signal>"                                                   \
-        "  <signal name=\"JobRemoved\">"                                \
-        "   <arg name=\"id\" type=\"u\"/>"                              \
-        "   <arg name=\"job\" type=\"o\"/>"                             \
-        "  </signal>"                                                   \
-        "  <property name=\"Version\" type=\"s\" access=\"read\"/>"     \
-        "  <property name=\"RunningAs\" type=\"s\" access=\"read\"/>"   \
-        "  <property name=\"BootTimestamp\" type=\"t\" access=\"read\"/>" \
-        "  <property name=\"LogLevel\" type=\"s\" access=\"read\"/>"    \
-        "  <property name=\"LogTarget\" type=\"s\" access=\"read\"/>"   \
-        "  <property name=\"NNames\" type=\"u\" access=\"read\"/>"      \
-        "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>"       \
-        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>" \
-        " </interface>"                                                 \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_INTROSPECTABLE_INTERFACE
-
-#define INTROSPECTION_END                                               \
-        "</node>"
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
-
-static int bus_manager_append_log_target(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        t = log_target_to_string(log_get_target());
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_append_log_level(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        t = log_level_to_string(log_get_max_level());
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_append_n_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        uint32_t u;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        u = hashmap_size(m->units);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_append_n_jobs(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        uint32_t u;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        u = hashmap_size(m->jobs);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection, DBusMessage *message, void *data) {
-        Manager *m = data;
-
-        const BusProperty properties[] = {
-                { "org.freedesktop.systemd1.Manager", "Version",       bus_property_append_string,    "s", PACKAGE_STRING     },
-                { "org.freedesktop.systemd1.Manager", "RunningAs",     bus_manager_append_running_as, "s", &m->running_as     },
-                { "org.freedesktop.systemd1.Manager", "BootTimestamp", bus_property_append_uint64,    "t", &m->boot_timestamp },
-                { "org.freedesktop.systemd1.Manager", "LogLevel",      bus_manager_append_log_level,  "s", NULL               },
-                { "org.freedesktop.systemd1.Manager", "LogTarget",     bus_manager_append_log_target, "s", NULL               },
-                { "org.freedesktop.systemd1.Manager", "NNames",        bus_manager_append_n_names,    "u", NULL               },
-                { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u", NULL               },
-                { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment   },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        int r;
-        DBusError error;
-        DBusMessage *reply = NULL;
-        char * path = NULL;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        log_debug("Got D-Bus request: %s.%s() on %s",
-                  dbus_message_get_interface(message),
-                  dbus_message_get_member(message),
-                  dbus_message_get_path(message));
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
-                const char *name;
-                Unit *u;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                if (!(u = manager_get_unit(m, name)))
-                        return bus_send_error_reply(m, message, NULL, -ENOENT);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!(path = unit_dbus_path(u)))
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
-                const char *name;
-                Unit *u;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                if ((r = manager_load_unit(m, name, NULL, &u)) < 0)
-                        return bus_send_error_reply(m, message, NULL, r);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!(path = unit_dbus_path(u)))
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
-                uint32_t id;
-                Job *j;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &id,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                if (!(j = manager_get_job(m, id)))
-                        return bus_send_error_reply(m, message, NULL, -ENOENT);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!(path = job_dbus_path(j)))
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
-
-                manager_clear_jobs(m);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
-                DBusMessageIter iter, sub;
-                Iterator i;
-                Unit *u;
-                const char *k;
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssssouso)", &sub))
-                        goto oom;
-
-                HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-                        char *u_path, *j_path;
-                        const char *description, *load_state, *active_state, *sub_state, *job_type;
-                        DBusMessageIter sub2;
-                        uint32_t job_id;
-
-                        if (k != u->meta.id)
-                                continue;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
-
-                        description = unit_description(u);
-                        load_state = unit_load_state_to_string(u->meta.load_state);
-                        active_state = unit_active_state_to_string(unit_active_state(u));
-                        sub_state = unit_sub_state_to_string(u);
-
-                        if (!(u_path = unit_dbus_path(u)))
-                                goto oom;
-
-                        if (u->meta.job) {
-                                job_id = (uint32_t) u->meta.job->id;
-
-                                if (!(j_path = job_dbus_path(u->meta.job))) {
-                                        free(u_path);
-                                        goto oom;
-                                }
-
-                                job_type = job_type_to_string(u->meta.job->type);
-                        } else {
-                                job_id = 0;
-                                j_path = u_path;
-                                job_type = "";
-                        }
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &job_type) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
-                                free(u_path);
-                                if (u->meta.job)
-                                        free(j_path);
-                                goto oom;
-                        }
-
-                        free(u_path);
-                        if (u->meta.job)
-                                free(j_path);
-
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
-                DBusMessageIter iter, sub;
-                Iterator i;
-                Job *j;
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
-                        goto oom;
-
-                HASHMAP_FOREACH(j, m->jobs, i) {
-                        char *u_path, *j_path;
-                        const char *state, *type;
-                        uint32_t id;
-                        DBusMessageIter sub2;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
-
-                        id = (uint32_t) j->id;
-                        state = job_state_to_string(j->state);
-                        type = job_type_to_string(j->type);
-
-                        if (!(j_path = job_dbus_path(j)))
-                                goto oom;
-
-                        if (!(u_path = unit_dbus_path(j->unit))) {
-                                free(j_path);
-                                goto oom;
-                        }
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->meta.id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
-                                free(j_path);
-                                free(u_path);
-                                goto oom;
-                        }
-
-                        free(j_path);
-                        free(u_path);
-
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
-                char *client;
-
-                if (!(client = strdup(dbus_message_get_sender(message))))
-                        goto oom;
-
-                r = set_put(m->subscribed, client);
-
-                if (r < 0)
-                        return bus_send_error_reply(m, message, NULL, r);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
-                char *client;
-
-                if (!(client = set_remove(m->subscribed, (char*) dbus_message_get_sender(message))))
-                        return bus_send_error_reply(m, message, NULL, -ENOENT);
-
-                free(client);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
-                FILE *f;
-                char *dump = NULL;
-                size_t size;
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!(f = open_memstream(&dump, &size)))
-                        goto oom;
-
-                manager_dump_units(m, f, NULL);
-                manager_dump_jobs(m, f, NULL);
-
-                if (ferror(f)) {
-                        fclose(f);
-                        free(dump);
-                        goto oom;
-                }
-
-                fclose(f);
-
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
-                        free(dump);
-                        goto oom;
-                }
-
-                free(dump);
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
-                const char *name;
-                dbus_bool_t cleanup;
-                Snapshot *s;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_BOOLEAN, &cleanup,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                if (name && name[0] == 0)
-                        name = NULL;
-
-                if ((r = snapshot_create(m, name, cleanup, &s)) < 0)
-                        return bus_send_error_reply(m, message, NULL, r);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!(path = unit_dbus_path(UNIT(s))))
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-                char *introspection = NULL;
-                FILE *f;
-                Iterator i;
-                Unit *u;
-                Job *j;
-                const char *k;
-                size_t size;
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                /* We roll our own introspection code here, instead of
-                 * relying on bus_default_message_handler() because we
-                 * need to generate our introspection string
-                 * dynamically. */
-
-                if (!(f = open_memstream(&introspection, &size)))
-                        goto oom;
-
-                fputs(INTROSPECTION_BEGIN, f);
-
-                HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-                        char *p;
-
-                        if (k != u->meta.id)
-                                continue;
-
-                        if (!(p = bus_path_escape(k))) {
-                                fclose(f);
-                                free(introspection);
-                                goto oom;
-                        }
-
-                        fprintf(f, "<node name=\"unit/%s\"/>", p);
-                        free(p);
-                }
-
-                HASHMAP_FOREACH(j, m->jobs, i)
-                        fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
-
-                fputs(INTROSPECTION_END, f);
-
-                if (ferror(f)) {
-                        fclose(f);
-                        free(introspection);
-                        goto oom;
-                }
-
-                fclose(f);
-
-                if (!introspection)
-                        goto oom;
-
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
-                        free(introspection);
-                        goto oom;
-                }
-
-                free(introspection);
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
-
-                assert(!m->queued_message);
-
-                /* Instead of sending the reply back right away, we
-                 * just remember that we need to and then send it
-                 * after the reload is finished. That way the caller
-                 * knows when the reload finished. */
-
-                if (!(m->queued_message = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_RELOAD;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_REEXECUTE;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
-
-                if (m->running_as == MANAGER_INIT)
-                        return bus_send_error_reply(m, message, NULL, -ENOTSUP);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_EXIT;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
-                char **l = NULL, **e = NULL;
-
-                if ((r = bus_parse_strv(message, &l)) < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        return bus_send_error_reply(m, message, NULL, r);
-                }
-
-                e = strv_env_merge(m->environment, l, NULL);
-                strv_free(l);
-
-                if (!e)
-                        goto oom;
-
-                if (!(reply = dbus_message_new_method_return(message))) {
-                        strv_free(e);
-                        goto oom;
-                }
-
-                strv_free(m->environment);
-                m->environment = e;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
-                char **l = NULL, **e = NULL;
-
-                if ((r = bus_parse_strv(message, &l)) < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        return bus_send_error_reply(m, message, NULL, r);
-                }
-
-                e = strv_env_delete(m->environment, l, NULL);
-                strv_free(l);
-
-                if (!e)
-                        goto oom;
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                strv_free(m->environment);
-                m->environment = e;
-
-        } else
-                return bus_default_message_handler(m, message, NULL, properties);
-
-        free(path);
-
-        if (reply) {
-                if (!dbus_connection_send(connection, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        free(path);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-const DBusObjectPathVTable bus_manager_vtable = {
-        .message_function = bus_manager_message_handler
-};
diff --git a/dbus-manager.h b/dbus-manager.h
deleted file mode 100644
index 0acd2d0..0000000
--- a/dbus-manager.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusmanagerhfoo
-#define foodbusmanagerhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-extern const DBusObjectPathVTable bus_manager_vtable;
-
-#endif
diff --git a/dbus-mount.c b/dbus-mount.c
deleted file mode 100644
index 500b773..0000000
--- a/dbus-mount.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-mount.h"
-#include "dbus-execute.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Mount\">"
-        "  <property name=\"Where\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"What\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"Options\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"Type\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>"
-        BUS_EXEC_CONTEXT_INTERFACE
-        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-static int bus_mount_append_what(Manager *n, DBusMessageIter *i, const char *property, void *data) {
-        Mount *m = data;
-        const char *d;
-
-        assert(n);
-        assert(i);
-        assert(property);
-        assert(m);
-
-        if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what)
-                d = m->parameters_proc_self_mountinfo.what;
-        else if (m->from_fragment && m->parameters_fragment.what)
-                d = m->parameters_fragment.what;
-        else if (m->from_etc_fstab && m->parameters_etc_fstab.what)
-                d = m->parameters_etc_fstab.what;
-        else
-                d = "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_mount_append_options(Manager *n, DBusMessageIter *i, const char *property, void *data) {
-        Mount *m = data;
-        const char *d;
-
-        assert(n);
-        assert(i);
-        assert(property);
-        assert(m);
-
-        if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options)
-                d = m->parameters_proc_self_mountinfo.options;
-        else if (m->from_fragment && m->parameters_fragment.options)
-                d = m->parameters_fragment.options;
-        else if (m->from_etc_fstab && m->parameters_etc_fstab.options)
-                d = m->parameters_etc_fstab.options;
-        else
-                d = "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_mount_append_type(Manager *n, DBusMessageIter *i, const char *property, void *data) {
-        Mount *m = data;
-        const char *d;
-
-        assert(n);
-        assert(i);
-        assert(property);
-        assert(m);
-
-        if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype)
-                d = m->parameters_proc_self_mountinfo.fstype;
-        else if (m->from_fragment && m->parameters_fragment.fstype)
-                d = m->parameters_fragment.fstype;
-        else if (m->from_etc_fstab && m->parameters_etc_fstab.fstype)
-                d = m->parameters_etc_fstab.fstype;
-        else
-                d = "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
-                return -ENOMEM;
-
-        return 0;
-}
-
-DBusHandlerResult bus_mount_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Mount", "Where",       bus_property_append_string, "s", u->mount.where         },
-                { "org.freedesktop.systemd1.Mount", "What",        bus_mount_append_what,      "s", u                      },
-                { "org.freedesktop.systemd1.Mount", "Options",     bus_mount_append_options,   "s", u                      },
-                { "org.freedesktop.systemd1.Mount", "Type",        bus_mount_append_type,      "s", u                      },
-                { "org.freedesktop.systemd1.Mount", "TimeoutUSec", bus_property_append_usec,   "t", &u->mount.timeout_usec },
-                /* ExecCommand */
-                BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Mount", u->mount.exec_context),
-                { "org.freedesktop.systemd1.Mount", "KillMode",    bus_unit_append_kill_mode,  "s", &u->mount.kill_mode    },
-                { "org.freedesktop.systemd1.Mount", "ControlPID",  bus_property_append_pid,    "u", &u->mount.control_pid  },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-mount.h b/dbus-mount.h
deleted file mode 100644
index b92867d..0000000
--- a/dbus-mount.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusmounthfoo
-#define foodbusmounthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_mount_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-service.c b/dbus-service.c
deleted file mode 100644
index 24dd6c1..0000000
--- a/dbus-service.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-execute.h"
-#include "dbus-service.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Service\">"
-        "  <property name=\"Type\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"Restart\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"PIDFile\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>"
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>"
-        BUS_EXEC_CONTEXT_INTERFACE
-        "  <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>"
-        "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>"
-        "  <property name=\"ValidNoProcess\" type=\"b\" access=\"read\"/>"
-        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"MainPID\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"SysVPath\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"BusName\" type=\"s\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
-
-DBusHandlerResult bus_service_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Service", "Type",                   bus_service_append_type,    "s", &u->service.type },
-                { "org.freedesktop.systemd1.Service", "Restart",                bus_service_append_restart, "s", &u->service.restart },
-                { "org.freedesktop.systemd1.Service", "PIDFile",                bus_property_append_string, "s", u->service.pid_file },
-                { "org.freedesktop.systemd1.Service", "RestartUSec",            bus_property_append_usec,   "t", &u->service.restart_usec },
-                { "org.freedesktop.systemd1.Service", "TimeoutUSec",            bus_property_append_usec,   "t", &u->service.timeout_usec },
-                /* ExecCommand */
-                BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Service", u->service.exec_context),
-                { "org.freedesktop.systemd1.Service", "PermissionsStartOnly",   bus_property_append_bool,   "b", &u->service.permissions_start_only },
-                { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool,   "b", &u->service.root_directory_start_only },
-                { "org.freedesktop.systemd1.Service", "ValidNoProcess",         bus_property_append_bool,   "b", &u->service.valid_no_process },
-                { "org.freedesktop.systemd1.Service", "KillMode",               bus_unit_append_kill_mode,  "s", &u->service.kill_mode },
-                /* MainExecStatus */
-                { "org.freedesktop.systemd1.Service", "MainPID",                bus_property_append_pid,    "u", &u->service.main_pid },
-                { "org.freedesktop.systemd1.Service", "ControlPID",             bus_property_append_pid,    "u", &u->service.control_pid },
-                { "org.freedesktop.systemd1.Service", "SysVPath",               bus_property_append_string, "s", u->service.sysv_path },
-                { "org.freedesktop.systemd1.Service", "BusName",                bus_property_append_string, "s", u->service.bus_name },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-service.h b/dbus-service.h
deleted file mode 100644
index f0a468e..0000000
--- a/dbus-service.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusservicehfoo
-#define foodbusservicehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_service_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-snapshot.c b/dbus-snapshot.c
deleted file mode 100644
index 8aeca15..0000000
--- a/dbus-snapshot.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-snapshot.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Snapshot\">"
-        "  <method name=\"Remove\"/>"
-        "  <property name=\"Cleanup\" type=\"b\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Snapshot", "Cleanup", bus_property_append_bool, "b", &u->snapshot.cleanup },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        DBusMessage *reply = NULL;
-        DBusError error;
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Snapshot", "Remove")) {
-
-                snapshot_remove(SNAPSHOT(u));
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else
-                return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-
-        if (reply) {
-                if (!dbus_connection_send(u->meta.manager->api_bus, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
diff --git a/dbus-snapshot.h b/dbus-snapshot.h
deleted file mode 100644
index 5f28550..0000000
--- a/dbus-snapshot.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbussnapshothfoo
-#define foodbussnapshothfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-socket.c b/dbus-socket.c
deleted file mode 100644
index 2a2349c..0000000
--- a/dbus-socket.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-socket.h"
-#include "dbus-execute.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Socket\">"
-        "  <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>"
-        "  <property name=\"Backlog\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>"
-        BUS_EXEC_CONTEXT_INTERFACE
-        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"SocketMode\" type=\"u\" access=\"read\"/>"
-        "  <property name=\"Accept\" type=\"b\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-DBusHandlerResult bus_socket_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Socket", "BindIPv6Only",  bus_property_append_bool,     "b", &u->socket.bind_ipv6_only },
-                { "org.freedesktop.systemd1.Socket", "Backlog",       bus_property_append_unsigned, "u", &u->socket.backlog },
-                { "org.freedesktop.systemd1.Socket", "TimeoutUSec",   bus_property_append_usec,     "t", &u->socket.timeout_usec },
-                /* ExecCommand */
-                BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Socket", u->socket.exec_context),
-                { "org.freedesktop.systemd1.Socket", "KillMode",      bus_unit_append_kill_mode,    "s", &u->socket.kill_mode },
-                { "org.freedesktop.systemd1.Socket", "ControlPID",    bus_property_append_pid,      "u", &u->socket.control_pid },
-                { "org.freedesktop.systemd1.Socket", "BindToDevice",  bus_property_append_string,   "s", u->socket.bind_to_device },
-                { "org.freedesktop.systemd1.Socket", "DirectoryMode", bus_property_append_mode,     "u", &u->socket.directory_mode },
-                { "org.freedesktop.systemd1.Socket", "SocketMode",    bus_property_append_mode,     "u", &u->socket.socket_mode },
-                { "org.freedesktop.systemd1.Socket", "Accept",        bus_property_append_bool,     "b", &u->socket.accept },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-socket.h b/dbus-socket.h
deleted file mode 100644
index 6a8f534..0000000
--- a/dbus-socket.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbussockethfoo
-#define foodbussockethfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_socket_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-swap.c b/dbus-swap.c
deleted file mode 100644
index e935e09..0000000
--- a/dbus-swap.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-  Copyright 2010 Maarten Lankhorst
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-swap.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Swap\">"
-        "  <property name=\"What\" type=\"s\" access=\"read\"/>"
-        "  <property name=\"Priority\" type=\"i\" access=\"read\"/>"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-static int bus_swap_append_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Swap *s = data;
-        dbus_int32_t j;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(s);
-
-        if (s->from_proc_swaps)
-                j = s->parameters_proc_swaps.priority;
-        else if (s->from_fragment)
-                j = s->parameters_fragment.priority;
-        else if (s->from_etc_fstab)
-                j = s->parameters_etc_fstab.priority;
-        else
-                j = -1;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &j))
-                return -ENOMEM;
-
-        return 0;
-}
-
-DBusHandlerResult bus_swap_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Swap", "What",     bus_property_append_string, "s", u->swap.what },
-                { "org.freedesktop.systemd1.Swap", "Priority", bus_swap_append_priority,   "i", u            },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-swap.h b/dbus-swap.h
deleted file mode 100644
index 3bef6ad..0000000
--- a/dbus-swap.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusswaphfoo
-#define foodbusswaphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-  Copyright 2010 Maarten Lankhorst
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_swap_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-target.c b/dbus-target.c
deleted file mode 100644
index be984b9..0000000
--- a/dbus-target.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-target.h"
-
-static const char introspection[] =
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-        "<node>"
-        BUS_UNIT_INTERFACE
-        BUS_PROPERTIES_INTERFACE
-        " <interface name=\"org.freedesktop.systemd1.Target\">"
-        " </interface>"
-        BUS_INTROSPECTABLE_INTERFACE
-        "</node>";
-
-DBusHandlerResult bus_target_message_handler(Unit *u, DBusMessage *message) {
-        const BusProperty properties[] = {
-                BUS_UNIT_PROPERTIES,
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
-}
diff --git a/dbus-target.h b/dbus-target.h
deleted file mode 100644
index f6a1ac5..0000000
--- a/dbus-target.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbustargethfoo
-#define foodbustargethfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_target_message_handler(Unit *u, DBusMessage *message);
-
-#endif
diff --git a/dbus-unit.c b/dbus-unit.c
deleted file mode 100644
index e3e1be1..0000000
--- a/dbus-unit.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-unit.h"
-
-int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        char *t;
-        Iterator j;
-        DBusMessageIter sub;
-        Unit *u = data;
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
-
-        SET_FOREACH(t, u->meta.names, j)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t))
-                        return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u;
-        Iterator j;
-        DBusMessageIter sub;
-        Set *s = data;
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
-
-        SET_FOREACH(u, s, j)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->meta.id))
-                        return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *d;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        d = unit_description(u);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
-                return -ENOMEM;
-
-        return 0;
-}
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState);
-
-int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *state;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        state = unit_active_state_to_string(unit_active_state(u));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *state;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        state = unit_sub_state_to_string(u);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        b = unit_can_start(u);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        b = unit_can_reload(u);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        DBusMessageIter sub;
-        char *p;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
-                return -ENOMEM;
-
-        if (u->meta.job) {
-
-                if (!(p = job_dbus_path(u->meta.job)))
-                        return -ENOMEM;
-
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->meta.job->id) ||
-                    !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
-                        free(p);
-                        return -ENOMEM;
-                }
-        } else {
-                uint32_t id = 0;
-
-                /* No job, so let's fill in some placeholder
-                 * data. Since we need to fill in a valid path we
-                 * simple point to ourselves. */
-
-                if (!(p = unit_dbus_path(u)))
-                        return -ENOMEM;
-
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
-                    !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
-                        free(p);
-                        return -ENOMEM;
-                }
-        }
-
-        free(p);
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        char *t;
-        CGroupBonding *cgb;
-        bool success;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        if ((cgb = unit_get_default_cgroup(u))) {
-                if (!(t = cgroup_bonding_to_string(cgb)))
-                        return -ENOMEM;
-        } else
-                t = (char*) "";
-
-        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
-
-        if (cgb)
-                free(t);
-
-        return success ? 0 : -ENOMEM;
-}
-
-int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        CGroupBonding *cgb;
-        DBusMessageIter sub;
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
-
-        LIST_FOREACH(by_unit, cgb, u->meta.cgroup_bondings) {
-                char *t;
-                bool success;
-
-                if (!(t = cgroup_bonding_to_string(cgb)))
-                        return -ENOMEM;
-
-                success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t);
-                free(t);
-
-                if (!success)
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_kill_mode, kill_mode, KillMode);
-
-static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message) {
-        DBusMessage *reply = NULL;
-        Manager *m = u->meta.manager;
-        DBusError error;
-        JobType job_type = _JOB_TYPE_INVALID;
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start"))
-                job_type = JOB_START;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop"))
-                job_type = JOB_STOP;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload"))
-                job_type = JOB_RELOAD;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart"))
-                job_type = JOB_RESTART;
-        else if (UNIT_VTABLE(u)->bus_message_handler)
-                return UNIT_VTABLE(u)->bus_message_handler(u, message);
-        else
-                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-        if (job_type != _JOB_TYPE_INVALID) {
-                const char *smode;
-                JobMode mode;
-                Job *j;
-                int r;
-                char *path;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &smode,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID)
-                        return bus_send_error_reply(m, message, NULL, -EINVAL);
-
-                if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0)
-                        return bus_send_error_reply(m, message, NULL, r);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!(path = job_dbus_path(j)))
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_OBJECT_PATH, &path,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-        }
-
-        if (reply) {
-                if (!dbus_connection_send(m->api_bus, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-static DBusHandlerResult bus_unit_message_handler(DBusConnection  *connection, DBusMessage  *message, void *data) {
-        Manager *m = data;
-        Unit *u;
-        int r;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        log_debug("Got D-Bus request: %s.%s() on %s",
-                  dbus_message_get_interface(message),
-                  dbus_message_get_member(message),
-                  dbus_message_get_path(message));
-
-        if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) {
-
-                if (r == -ENOMEM)
-                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
-                if (r == -ENOENT)
-                        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-                return bus_send_error_reply(m, message, NULL, r);
-        }
-
-        return bus_unit_message_dispatch(u, message);
-}
-
-const DBusObjectPathVTable bus_unit_vtable = {
-        .message_function = bus_unit_message_handler
-};
-
-void bus_unit_send_change_signal(Unit *u) {
-        char *p = NULL;
-        DBusMessage *m = NULL;
-
-        assert(u);
-        assert(u->meta.in_dbus_queue);
-
-        LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
-        u->meta.in_dbus_queue = false;
-
-        if (set_isempty(u->meta.manager->subscribed)) {
-                u->meta.sent_dbus_new_signal = true;
-                return;
-        }
-
-        if (!(p = unit_dbus_path(u)))
-                goto oom;
-
-        if (u->meta.sent_dbus_new_signal) {
-                /* Send a change signal */
-
-                if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Unit", "Changed")))
-                        goto oom;
-        } else {
-                /* Send a new signal */
-
-                if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew")))
-                        goto oom;
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &u->meta.id,
-                                              DBUS_TYPE_OBJECT_PATH, &p,
-                                              DBUS_TYPE_INVALID))
-                        goto oom;
-        }
-
-        if (!dbus_connection_send(u->meta.manager->api_bus, m, NULL))
-                goto oom;
-
-        free(p);
-        dbus_message_unref(m);
-
-        u->meta.sent_dbus_new_signal = true;
-
-        return;
-
-oom:
-        free(p);
-
-        if (m)
-                dbus_message_unref(m);
-
-        log_error("Failed to allocate unit change/new signal.");
-}
-
-void bus_unit_send_removed_signal(Unit *u) {
-        char *p = NULL;
-        DBusMessage *m = NULL;
-
-        assert(u);
-
-        if (set_isempty(u->meta.manager->subscribed) || !u->meta.sent_dbus_new_signal)
-                return;
-
-        if (!(p = unit_dbus_path(u)))
-                goto oom;
-
-        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved")))
-                goto oom;
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &u->meta.id,
-                                      DBUS_TYPE_OBJECT_PATH, &p,
-                                      DBUS_TYPE_INVALID))
-                goto oom;
-
-        if (!dbus_connection_send(u->meta.manager->api_bus, m, NULL))
-                goto oom;
-
-        free(p);
-        dbus_message_unref(m);
-
-        return;
-
-oom:
-        free(p);
-
-        if (m)
-                dbus_message_unref(m);
-
-        log_error("Failed to allocate unit remove signal.");
-}
diff --git a/dbus-unit.h b/dbus-unit.h
deleted file mode 100644
index c5840d5..0000000
--- a/dbus-unit.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbusunithfoo
-#define foodbusunithfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "manager.h"
-
-#define BUS_UNIT_INTERFACE \
-        " <interface name=\"org.freedesktop.systemd1.Unit\">"           \
-        "  <method name=\"Start\">"                                     \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
-        "  </method>"                                                   \
-        "  <method name=\"Stop\">"                                      \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
-        "  </method>"                                                   \
-        "  <method name=\"Restart\">"                                   \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
-        "  </method>"                                                   \
-        "  <method name=\"Reload\">"                                    \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
-        "  </method>"                                                   \
-        "  <signal name=\"Changed\"/>"                                  \
-        "  <property name=\"Id\" type=\"s\" access=\"read\"/>"          \
-        "  <property name=\"Names\" type=\"as\" access=\"read\"/>"      \
-        "  <property name=\"Requires\" type=\"as\" access=\"read\"/>"   \
-        "  <property name=\"RequiresOverridable\" type=\"as\" access=\"read\"/>" \
-        "  <property name=\"Requisite\" type=\"as\" access=\"read\"/>"  \
-        "  <property name=\"RequisiteOverridable\" type=\"as\" access=\"read\"/>" \
-        "  <property name=\"Wants\" type=\"as\" access=\"read\"/>"      \
-        "  <property name=\"RequiredBy\" type=\"as\" access=\"read\"/>" \
-        "  <property name=\"RequiredByOverridable\" type=\"as\" access=\"read\"/>" \
-        "  <property name=\"WantedBy\" type=\"as\" access=\"read\"/>"   \
-        "  <property name=\"Conflicts\" type=\"as\" access=\"read\"/>"  \
-        "  <property name=\"Before\" type=\"as\" access=\"read\"/>"     \
-        "  <property name=\"After\" type=\"as\" access=\"read\"/>"      \
-        "  <property name=\"Description\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"LoadState\" type=\"s\" access=\"read\"/>"   \
-        "  <property name=\"ActiveState\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"SubState\" type=\"s\" access=\"read\"/>"    \
-        "  <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>" \
-        "  <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>" \
-        "  <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>" \
-        "  <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>" \
-        "  <property name=\"CanReload\" type=\"b\" access=\"read\"/>"   \
-        "  <property name=\"CanStart\" type=\"b\" access=\"read\"/>"    \
-        "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>"      \
-        "  <property name=\"RecursiveStop\" type=\"b\" access=\"read\"/>" \
-        "  <property name=\"StopWhenUneeded\" type=\"b\" access=\"read\"/>" \
-        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>" \
-        "  <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>" \
-        " </interface>"
-
-#define BUS_UNIT_PROPERTIES \
-        { "org.freedesktop.systemd1.Unit", "Id",                   bus_property_append_string,     "s",    u->meta.id                        }, \
-        { "org.freedesktop.systemd1.Unit", "Names",                bus_unit_append_names,          "as",   u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "Requires",             bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRES] }, \
-        { "org.freedesktop.systemd1.Unit", "RequiresOverridable",  bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE] }, \
-        { "org.freedesktop.systemd1.Unit", "Requisite",            bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUISITE] }, \
-        { "org.freedesktop.systemd1.Unit", "RequisiteOverridable", bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE] }, \
-        { "org.freedesktop.systemd1.Unit", "Wants",                bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_WANTS]  }, \
-        { "org.freedesktop.systemd1.Unit", "RequiredBy",           bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRED_BY] }, \
-        { "org.freedesktop.systemd1.Unit", "RequiredByOverridable",bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE] }, \
-        { "org.freedesktop.systemd1.Unit", "WantedBy",             bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_WANTED_BY] }, \
-        { "org.freedesktop.systemd1.Unit", "Conflicts",            bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_CONFLICTS] }, \
-        { "org.freedesktop.systemd1.Unit", "Before",               bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_BEFORE] }, \
-        { "org.freedesktop.systemd1.Unit", "After",                bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_AFTER]  }, \
-        { "org.freedesktop.systemd1.Unit", "Description",          bus_unit_append_description,    "s",    u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "LoadState",            bus_unit_append_load_state,     "s",    &u->meta.load_state               }, \
-        { "org.freedesktop.systemd1.Unit", "ActiveState",          bus_unit_append_active_state,   "s",    u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "SubState",             bus_unit_append_sub_state,      "s",    u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "FragmentPath",         bus_property_append_string,     "s",    u->meta.fragment_path             }, \
-        { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_uint64,     "t",    &u->meta.inactive_exit_timestamp  }, \
-        { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_uint64,     "t",    &u->meta.active_enter_timestamp   }, \
-        { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp",  bus_property_append_uint64,     "t",    &u->meta.active_exit_timestamp    }, \
-        { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_uint64,    "t",    &u->meta.inactive_enter_timestamp }, \
-        { "org.freedesktop.systemd1.Unit", "CanStart",             bus_unit_append_can_start,      "b",    u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "CanReload",            bus_unit_append_can_reload,     "b",    u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "Job",                  bus_unit_append_job,            "(uo)", u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "RecursiveStop",        bus_property_append_bool,       "b",    &u->meta.recursive_stop           }, \
-        { "org.freedesktop.systemd1.Unit", "StopWhenUneeded",      bus_property_append_bool,       "b",    &u->meta.stop_when_unneeded       }, \
-        { "org.freedesktop.systemd1.Unit", "DefaultControlGroup",  bus_unit_append_default_cgroup, "s",    u                                 }, \
-        { "org.freedesktop.systemd1.Unit", "ControlGroups",        bus_unit_append_cgroups,        "as",   u                                 }
-
-int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_unit_append_kill_mode(Manager *m, DBusMessageIter *i, const char *property, void *data);
-
-void bus_unit_send_change_signal(Unit *u);
-void bus_unit_send_removed_signal(Unit *u);
-
-extern const DBusObjectPathVTable bus_unit_vtable;
-
-#endif
diff --git a/dbus.c b/dbus.c
deleted file mode 100644
index 6ed659a..0000000
--- a/dbus.c
+++ /dev/null
@@ -1,1136 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dbus/dbus.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "strv.h"
-#include "cgroup.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-
-static void api_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
-        Manager *m = data;
-
-        assert(bus);
-        assert(m);
-
-        if (!m->api_bus)
-                return;
-
-        assert(m->api_bus == bus);
-
-        m->request_api_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
-}
-
-static void system_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
-        Manager *m = data;
-
-        assert(bus);
-        assert(m);
-
-        if (!m->system_bus)
-                return;
-
-        assert(m->system_bus == bus);
-
-        m->request_system_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
-}
-
-static uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
-        unsigned flags;
-        uint32_t events = 0;
-
-        assert(bus_watch);
-
-        /* no watch flags for disabled watches */
-        if (!dbus_watch_get_enabled(bus_watch))
-                return 0;
-
-        flags = dbus_watch_get_flags(bus_watch);
-
-        if (flags & DBUS_WATCH_READABLE)
-                events |= EPOLLIN;
-        if (flags & DBUS_WATCH_WRITABLE)
-                events |= EPOLLOUT;
-
-        return events | EPOLLHUP | EPOLLERR;
-}
-
-static unsigned events_to_bus_flags(uint32_t events) {
-        unsigned flags = 0;
-
-        if (events & EPOLLIN)
-                flags |= DBUS_WATCH_READABLE;
-        if (events & EPOLLOUT)
-                flags |= DBUS_WATCH_WRITABLE;
-        if (events & EPOLLHUP)
-                flags |= DBUS_WATCH_HANGUP;
-        if (events & EPOLLERR)
-                flags |= DBUS_WATCH_ERROR;
-
-        return flags;
-}
-
-void bus_watch_event(Manager *m, Watch *w, int events) {
-        assert(m);
-        assert(w);
-
-        /* This is called by the event loop whenever there is
-         * something happening on D-Bus' file handles. */
-
-        if (!dbus_watch_get_enabled(w->data.bus_watch))
-                return;
-
-        dbus_watch_handle(w->data.bus_watch, events_to_bus_flags(events));
-}
-
-static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
-        Manager *m = data;
-        Watch *w;
-        struct epoll_event ev;
-
-        assert(bus_watch);
-        assert(m);
-
-        if (!(w = new0(Watch, 1)))
-                return FALSE;
-
-        w->fd = dbus_watch_get_unix_fd(bus_watch);
-        w->type = WATCH_DBUS_WATCH;
-        w->data.bus_watch = bus_watch;
-
-        zero(ev);
-        ev.events = bus_flags_to_events(bus_watch);
-        ev.data.ptr = w;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
-
-                if (errno != EEXIST) {
-                        free(w);
-                        return FALSE;
-                }
-
-                /* Hmm, bloody D-Bus creates multiple watches on the
-                 * same fd. epoll() does not like that. As a dirty
-                 * hack we simply dup() the fd and hence get a second
-                 * one we can safely add to the epoll(). */
-
-                if ((w->fd = dup(w->fd)) < 0) {
-                        free(w);
-                        return FALSE;
-                }
-
-                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
-                        free(w);
-                        close_nointr_nofail(w->fd);
-                        return FALSE;
-                }
-
-                w->fd_is_dupped = true;
-        }
-
-        dbus_watch_set_data(bus_watch, w, NULL);
-
-        return TRUE;
-}
-
-static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
-        Manager *m = data;
-        Watch *w;
-
-        assert(bus_watch);
-        assert(m);
-
-        if (!(w = dbus_watch_get_data(bus_watch)))
-                return;
-
-        assert(w->type == WATCH_DBUS_WATCH);
-        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-
-        if (w->fd_is_dupped)
-                close_nointr_nofail(w->fd);
-
-        free(w);
-}
-
-static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
-        Manager *m = data;
-        Watch *w;
-        struct epoll_event ev;
-
-        assert(bus_watch);
-        assert(m);
-
-        assert_se(w = dbus_watch_get_data(bus_watch));
-        assert(w->type == WATCH_DBUS_WATCH);
-
-        zero(ev);
-        ev.events = bus_flags_to_events(bus_watch);
-        ev.data.ptr = w;
-
-        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
-}
-
-static int bus_timeout_arm(Manager *m, Watch *w) {
-        struct itimerspec its;
-
-        assert(m);
-        assert(w);
-
-        zero(its);
-
-        if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
-                timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
-                its.it_interval = its.it_interval;
-        }
-
-        if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
-                return -errno;
-
-        return 0;
-}
-
-void bus_timeout_event(Manager *m, Watch *w, int events) {
-        assert(m);
-        assert(w);
-
-        /* This is called by the event loop whenever there is
-         * something happening on D-Bus' file handles. */
-
-        if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
-                return;
-
-        dbus_timeout_handle(w->data.bus_timeout);
-}
-
-static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
-        Manager *m = data;
-        Watch *w;
-        struct epoll_event ev;
-
-        assert(timeout);
-        assert(m);
-
-        if (!(w = new0(Watch, 1)))
-                return FALSE;
-
-        if (!(w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
-                goto fail;
-
-        w->type = WATCH_DBUS_TIMEOUT;
-        w->data.bus_timeout = timeout;
-
-        if (bus_timeout_arm(m, w) < 0)
-                goto fail;
-
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.ptr = w;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
-                goto fail;
-
-        dbus_timeout_set_data(timeout, w, NULL);
-
-        return TRUE;
-
-fail:
-        if (w->fd >= 0)
-                close_nointr_nofail(w->fd);
-
-        free(w);
-        return FALSE;
-}
-
-static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
-        Manager *m = data;
-        Watch *w;
-
-        assert(timeout);
-        assert(m);
-
-        if (!(w = dbus_timeout_get_data(timeout)))
-                return;
-
-        assert(w->type == WATCH_DBUS_TIMEOUT);
-        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-        close_nointr_nofail(w->fd);
-        free(w);
-}
-
-static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
-        Manager *m = data;
-        Watch *w;
-        int r;
-
-        assert(timeout);
-        assert(m);
-
-        assert_se(w = dbus_timeout_get_data(timeout));
-        assert(w->type == WATCH_DBUS_TIMEOUT);
-
-        if ((r = bus_timeout_arm(m, w)) < 0)
-                log_error("Failed to rearm timer: %s", strerror(-r));
-}
-
-static DBusHandlerResult api_bus_message_filter(DBusConnection  *connection, DBusMessage  *message, void *data) {
-        Manager *m = data;
-        DBusError error;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        /* log_debug("Got D-Bus request: %s.%s() on %s", */
-        /*           dbus_message_get_interface(message), */
-        /*           dbus_message_get_member(message), */
-        /*           dbus_message_get_path(message)); */
-
-        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
-                log_error("Warning! API D-Bus connection terminated.");
-                bus_done_api(m);
-
-        } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
-                const char *name, *old_owner, *new_owner;
-
-                if (!dbus_message_get_args(message, &error,
-                                           DBUS_TYPE_STRING, &name,
-                                           DBUS_TYPE_STRING, &old_owner,
-                                           DBUS_TYPE_STRING, &new_owner,
-                                           DBUS_TYPE_INVALID))
-                        log_error("Failed to parse NameOwnerChanged message: %s", error.message);
-                else  {
-                        if (set_remove(m->subscribed, (char*) name))
-                                log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
-
-                        if (old_owner[0] == 0)
-                                old_owner = NULL;
-
-                        if (new_owner[0] == 0)
-                                new_owner = NULL;
-
-                        manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
-                }
-        }
-
-        dbus_error_free(&error);
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static DBusHandlerResult system_bus_message_filter(DBusConnection  *connection, DBusMessage  *message, void *data) {
-        Manager *m = data;
-        DBusError error;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        /* log_debug("Got D-Bus request: %s.%s() on %s", */
-        /*           dbus_message_get_interface(message), */
-        /*           dbus_message_get_member(message), */
-        /*           dbus_message_get_path(message)); */
-
-        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
-                log_error("Warning! System D-Bus connection terminated.");
-                bus_done_system(m);
-
-        } if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
-                const char *cgroup;
-
-                if (!dbus_message_get_args(message, &error,
-                                           DBUS_TYPE_STRING, &cgroup,
-                                           DBUS_TYPE_INVALID))
-                        log_error("Failed to parse Released message: %s", error.message);
-                else
-                        cgroup_notify_empty(m, cgroup);
-        }
-
-        dbus_error_free(&error);
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-unsigned bus_dispatch(Manager *m) {
-        assert(m);
-
-        if (m->queued_message) {
-                /* If we cannot get rid of this message we won't
-                 * dispatch any D-Bus messages, so that we won't end
-                 * up wanting to queue another message. */
-
-                if (!dbus_connection_send(m->api_bus, m->queued_message, NULL))
-                        return 0;
-
-                dbus_message_unref(m->queued_message);
-                m->queued_message = NULL;
-        }
-
-        if (m->request_api_bus_dispatch) {
-                if (dbus_connection_dispatch(m->api_bus) == DBUS_DISPATCH_COMPLETE)
-                        m->request_api_bus_dispatch = false;
-
-                return 1;
-        }
-
-        if (m->request_system_bus_dispatch) {
-                if (dbus_connection_dispatch(m->system_bus) == DBUS_DISPATCH_COMPLETE)
-                        m->request_system_bus_dispatch = false;
-
-                return 1;
-        }
-
-        return 0;
-}
-
-static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
-        DBusMessage *reply;
-        DBusError error;
-
-        dbus_error_init(&error);
-
-        assert_se(reply = dbus_pending_call_steal_reply(pending));
-
-        switch (dbus_message_get_type(reply)) {
-
-        case DBUS_MESSAGE_TYPE_ERROR:
-
-                assert_se(dbus_set_error_from_message(&error, reply));
-                log_warning("RequestName() failed: %s", error.message);
-                break;
-
-        case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
-                uint32_t r;
-
-                if (!dbus_message_get_args(reply,
-                                           &error,
-                                           DBUS_TYPE_UINT32, &r,
-                                           DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse RequestName() reply: %s", error.message);
-                        break;
-                }
-
-                if (r == 1)
-                        log_debug("Successfully acquired name.");
-                else
-                        log_error("Name already owned.");
-
-                break;
-        }
-
-        default:
-                assert_not_reached("Invalid reply message");
-        }
-
-        dbus_message_unref(reply);
-        dbus_error_free(&error);
-}
-
-static int request_name(Manager *m) {
-        const char *name = "org.freedesktop.systemd1";
-        uint32_t flags = 0;
-        DBusMessage *message = NULL;
-        DBusPendingCall *pending = NULL;
-
-        if (!(message = dbus_message_new_method_call(
-                              DBUS_SERVICE_DBUS,
-                              DBUS_PATH_DBUS,
-                              DBUS_INTERFACE_DBUS,
-                              "RequestName")))
-                goto oom;
-
-        if (!dbus_message_append_args(
-                            message,
-                            DBUS_TYPE_STRING, &name,
-                            DBUS_TYPE_UINT32, &flags,
-                            DBUS_TYPE_INVALID))
-                goto oom;
-
-        if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
-                goto oom;
-
-        if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
-                goto oom;
-
-        dbus_message_unref(message);
-        dbus_pending_call_unref(pending);
-
-        /* We simple ask for the name and don't wait for it. Sooner or
-         * later we'll have it. */
-
-        return 0;
-
-oom:
-        if (pending) {
-                dbus_pending_call_cancel(pending);
-                dbus_pending_call_unref(pending);
-        }
-
-        if (message)
-                dbus_message_unref(message);
-
-        return -ENOMEM;
-}
-
-static int bus_setup_loop(Manager *m, DBusConnection *bus) {
-        assert(m);
-        assert(bus);
-
-        dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
-        if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
-            !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_init_system(Manager *m) {
-        DBusError error;
-        char *id;
-        int r;
-
-        assert(m);
-
-        dbus_error_init(&error);
-
-        if (m->system_bus)
-                return 0;
-
-        if (m->running_as != MANAGER_SESSION && m->api_bus)
-                m->system_bus = m->api_bus;
-        else {
-                if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
-                        log_debug("Failed to get system D-Bus connection, retrying later: %s", error.message);
-                        dbus_error_free(&error);
-                        return 0;
-                }
-
-                dbus_connection_set_dispatch_status_function(m->system_bus, system_bus_dispatch_status, m, NULL);
-                m->request_system_bus_dispatch = true;
-
-                if ((r = bus_setup_loop(m, m->system_bus)) < 0) {
-                        bus_done_system(m);
-                        return r;
-                }
-        }
-
-        if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
-                bus_done_system(m);
-                return -ENOMEM;
-        }
-
-        dbus_bus_add_match(m->system_bus,
-                           "type='signal',"
-                           "interface='org.freedesktop.systemd1.Agent',"
-                           "path='/org/freedesktop/systemd1/agent'",
-                           &error);
-
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to register match: %s", error.message);
-                dbus_error_free(&error);
-                bus_done_system(m);
-                return -ENOMEM;
-        }
-
-        log_debug("Successfully connected to system D-Bus bus %s as %s",
-                  strnull((id = dbus_connection_get_server_id(m->system_bus))),
-                  strnull(dbus_bus_get_unique_name(m->system_bus)));
-        dbus_free(id);
-
-        return 0;
-}
-
-int bus_init_api(Manager *m) {
-        DBusError error;
-        char *id;
-        int r;
-
-        assert(m);
-
-        dbus_error_init(&error);
-
-        if (m->api_bus)
-                return 0;
-
-        if (m->name_data_slot < 0)
-                if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
-                        return -ENOMEM;
-
-        if (m->running_as != MANAGER_SESSION && m->system_bus)
-                m->api_bus = m->system_bus;
-        else {
-                if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_SESSION ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
-                        log_debug("Failed to get API D-Bus connection, retrying later: %s", error.message);
-                        dbus_error_free(&error);
-                        return 0;
-                }
-
-                dbus_connection_set_dispatch_status_function(m->api_bus, api_bus_dispatch_status, m, NULL);
-                m->request_api_bus_dispatch = true;
-
-                if ((r = bus_setup_loop(m, m->api_bus)) < 0) {
-                        bus_done_api(m);
-                        return r;
-                }
-        }
-
-        if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
-            !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
-            !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
-            !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) {
-                bus_done_api(m);
-                return -ENOMEM;
-        }
-
-        dbus_bus_add_match(m->api_bus,
-                           "type='signal',"
-                           "sender='"DBUS_SERVICE_DBUS"',"
-                           "interface='"DBUS_INTERFACE_DBUS"',"
-                           "path='"DBUS_PATH_DBUS"'",
-                           &error);
-
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to register match: %s", error.message);
-                dbus_error_free(&error);
-                bus_done_api(m);
-                return -ENOMEM;
-        }
-
-        if ((r = request_name(m)) < 0) {
-                bus_done_api(m);
-                return r;
-        }
-
-        log_debug("Successfully connected to API D-Bus bus %s as %s",
-                  strnull((id = dbus_connection_get_server_id(m->api_bus))),
-                  strnull(dbus_bus_get_unique_name(m->api_bus)));
-        dbus_free(id);
-
-        if (!m->subscribed)
-                if (!(m->subscribed = set_new(string_hash_func, string_compare_func)))
-                        return -ENOMEM;
-
-        return 0;
-}
-
-void bus_done_api(Manager *m) {
-        assert(m);
-
-        if (m->api_bus) {
-                if (m->system_bus == m->api_bus)
-                        m->system_bus = NULL;
-
-                dbus_connection_set_dispatch_status_function(m->api_bus, NULL, NULL, NULL);
-                dbus_connection_flush(m->api_bus);
-                dbus_connection_close(m->api_bus);
-                dbus_connection_unref(m->api_bus);
-                m->api_bus = NULL;
-        }
-
-        if (m->subscribed) {
-                char *c;
-
-                while ((c = set_steal_first(m->subscribed)))
-                        free(c);
-
-                set_free(m->subscribed);
-                m->subscribed = NULL;
-        }
-
-       if (m->name_data_slot >= 0)
-               dbus_pending_call_free_data_slot(&m->name_data_slot);
-
-       if (m->queued_message) {
-               dbus_message_unref(m->queued_message);
-               m->queued_message = NULL;
-       }
-}
-
-void bus_done_system(Manager *m) {
-        assert(m);
-
-        if (m->system_bus == m->api_bus)
-                bus_done_api(m);
-
-        if (m->system_bus) {
-                dbus_connection_set_dispatch_status_function(m->system_bus, NULL, NULL, NULL);
-                dbus_connection_flush(m->system_bus);
-                dbus_connection_close(m->system_bus);
-                dbus_connection_unref(m->system_bus);
-                m->system_bus = NULL;
-        }
-}
-
-static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
-        Manager *m = userdata;
-        DBusMessage *reply;
-        DBusError error;
-        const char *name;
-
-        dbus_error_init(&error);
-
-        assert_se(name = dbus_pending_call_get_data(pending, m->name_data_slot));
-        assert_se(reply = dbus_pending_call_steal_reply(pending));
-
-        switch (dbus_message_get_type(reply)) {
-
-        case DBUS_MESSAGE_TYPE_ERROR:
-
-                assert_se(dbus_set_error_from_message(&error, reply));
-                log_warning("GetConnectionUnixProcessID() failed: %s", error.message);
-                break;
-
-        case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
-                uint32_t r;
-
-                if (!dbus_message_get_args(reply,
-                                           &error,
-                                           DBUS_TYPE_UINT32, &r,
-                                           DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", error.message);
-                        break;
-                }
-
-                manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
-                break;
-        }
-
-        default:
-                assert_not_reached("Invalid reply message");
-        }
-
-        dbus_message_unref(reply);
-        dbus_error_free(&error);
-}
-
-int bus_query_pid(Manager *m, const char *name) {
-        DBusMessage *message = NULL;
-        DBusPendingCall *pending = NULL;
-        char *n = NULL;
-
-        assert(m);
-        assert(name);
-
-        if (!(message = dbus_message_new_method_call(
-                              DBUS_SERVICE_DBUS,
-                              DBUS_PATH_DBUS,
-                              DBUS_INTERFACE_DBUS,
-                              "GetConnectionUnixProcessID")))
-                goto oom;
-
-        if (!(dbus_message_append_args(
-                              message,
-                              DBUS_TYPE_STRING, &name,
-                              DBUS_TYPE_INVALID)))
-                goto oom;
-
-        if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
-                goto oom;
-
-        if (!(n = strdup(name)))
-                goto oom;
-
-        if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
-                goto oom;
-
-        n = NULL;
-
-        if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
-                goto oom;
-
-        dbus_message_unref(message);
-        dbus_pending_call_unref(pending);
-
-        return 0;
-
-oom:
-        free(n);
-
-        if (pending) {
-                dbus_pending_call_cancel(pending);
-                dbus_pending_call_unref(pending);
-        }
-
-        if (message)
-                dbus_message_unref(message);
-
-        return -ENOMEM;
-}
-
-DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char*introspection, const BusProperty *properties) {
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(m);
-        assert(message);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) {
-                const char *interface, *property;
-                const BusProperty *p;
-
-                if (!dbus_message_get_args(
-                            message,
-                            &error,
-                            DBUS_TYPE_STRING, &interface,
-                            DBUS_TYPE_STRING, &property,
-                            DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                for (p = properties; p->property; p++)
-                        if (streq(p->interface, interface) && streq(p->property, property))
-                                break;
-
-                if (p->property) {
-                        DBusMessageIter iter, sub;
-
-                        if (!(reply = dbus_message_new_method_return(message)))
-                                goto oom;
-
-                        dbus_message_iter_init_append(reply, &iter);
-
-                        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
-                                goto oom;
-
-                        if ((r = p->append(m, &sub, property, (void*) p->data)) < 0) {
-
-                                if (r == -ENOMEM)
-                                        goto oom;
-
-                                dbus_message_unref(reply);
-                                return bus_send_error_reply(m, message, NULL, r);
-                        }
-
-                        if (!dbus_message_iter_close_container(&iter, &sub))
-                                goto oom;
-                }
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
-                const char *interface;
-                const BusProperty *p;
-                DBusMessageIter iter, sub, sub2, sub3;
-                bool any = false;
-
-                if (!dbus_message_get_args(
-                            message,
-                            &error,
-                            DBUS_TYPE_STRING, &interface,
-                            DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(m, message, &error, -EINVAL);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
-                        goto oom;
-
-                for (p = properties; p->property; p++) {
-                        if (!streq(p->interface, interface))
-                                continue;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
-                            !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
-                                goto oom;
-
-                        if ((r = p->append(m, &sub3, p->property, (void*) p->data)) < 0) {
-
-                                if (r == -ENOMEM)
-                                        goto oom;
-
-                                dbus_message_unref(reply);
-                                return bus_send_error_reply(m, message, NULL, r);
-                        }
-
-                        if (!dbus_message_iter_close_container(&sub2, &sub3) ||
-                            !dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-
-                        any = true;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-        }
-
-        if (reply) {
-                if (!dbus_connection_send(m->api_bus, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-                return DBUS_HANDLER_RESULT_HANDLED;
-        }
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-static const char *error_to_dbus(int error) {
-
-        switch(error) {
-
-        case -EINVAL:
-                return DBUS_ERROR_INVALID_ARGS;
-
-        case -ENOMEM:
-                return DBUS_ERROR_NO_MEMORY;
-
-        case -EPERM:
-        case -EACCES:
-                return DBUS_ERROR_ACCESS_DENIED;
-
-        case -ESRCH:
-                return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
-
-        case -ENOENT:
-                return DBUS_ERROR_FILE_NOT_FOUND;
-
-        case -EEXIST:
-                return DBUS_ERROR_FILE_EXISTS;
-
-        case -ETIMEDOUT:
-                return DBUS_ERROR_TIMEOUT;
-
-        case -EIO:
-                return DBUS_ERROR_IO_ERROR;
-
-        case -ENETRESET:
-        case -ECONNABORTED:
-        case -ECONNRESET:
-                return DBUS_ERROR_DISCONNECTED;
-        }
-
-        return DBUS_ERROR_FAILED;
-}
-
-DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error) {
-        DBusMessage *reply = NULL;
-        const char *name, *text;
-
-        if (bus_error && dbus_error_is_set(bus_error)) {
-                name = bus_error->name;
-                text = bus_error->message;
-        } else {
-                name = error_to_dbus(error);
-                text = strerror(-error);
-        }
-
-        if (!(reply = dbus_message_new_error(message, name, text)))
-                goto oom;
-
-        if (!dbus_connection_send(m->api_bus, reply, NULL))
-                goto oom;
-
-        dbus_message_unref(reply);
-
-        if (bus_error)
-                dbus_error_free(bus_error);
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        if (bus_error)
-                dbus_error_free(bus_error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        const char *t = data;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        if (!t)
-                t = "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        DBusMessageIter sub;
-        char **t = data;
-
-        assert(m);
-        assert(i);
-        assert(property);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
-
-        STRV_FOREACH(t, t)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t))
-                        return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        bool *b = data;
-        dbus_bool_t db;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(b);
-
-        db = *b;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
-
-        /* Let's ensure that pid_t is actually 64bit, and hence this
-         * function can be used for usec_t */
-        assert_cc(sizeof(uint64_t) == sizeof(usec_t));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
-
-        /* Let's ensure that pid_t and mode_t is actually 32bit, and
-         * hence this function can be used for pid_t/mode_t */
-        assert_cc(sizeof(uint32_t) == sizeof(pid_t));
-        assert_cc(sizeof(uint32_t) == sizeof(mode_t));
-        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(data);
-
-        assert_cc(sizeof(int32_t) == sizeof(int));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_parse_strv(DBusMessage *m, char ***_l) {
-        DBusMessageIter iter, sub;
-        unsigned n = 0, i = 0;
-        char **l;
-
-        assert(m);
-        assert(_l);
-
-        if (!dbus_message_iter_init(m, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
-            return -EINVAL;
-
-        dbus_message_iter_recurse(&iter, &sub);
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                n++;
-                dbus_message_iter_next(&sub);
-        }
-
-        if (!(l = new(char*, n+1)))
-                return -ENOMEM;
-
-        assert_se(dbus_message_iter_init(m, &iter));
-        dbus_message_iter_recurse(&iter, &sub);
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *s;
-
-                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
-                dbus_message_iter_get_basic(&sub, &s);
-
-                if (!(l[i++] = strdup(s))) {
-                        strv_free(l);
-                        return -ENOMEM;
-                }
-
-                dbus_message_iter_next(&sub);
-        }
-
-        assert(i == n);
-        l[i] = NULL;
-
-        if (_l)
-                *_l = l;
-
-        return 0;
-}
diff --git a/dbus.h b/dbus.h
deleted file mode 100644
index 51b71ea..0000000
--- a/dbus.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodbushfoo
-#define foodbushfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "manager.h"
-
-typedef int (*BusPropertyCallback)(Manager *m, DBusMessageIter *iter, const char *property, void *data);
-
-typedef struct BusProperty {
-        const char *interface;           /* interface of the property */
-        const char *property;            /* name of the property */
-        BusPropertyCallback append;      /* Function that is called to serialize this property */
-        const char *signature;
-        const void *data;                /* The data of this property */
-} BusProperty;
-
-#define BUS_PROPERTIES_INTERFACE                                        \
-        " <interface name=\"org.freedesktop.DBus.Properties\">"         \
-        "  <method name=\"Get\">"                                       \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>"      \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>"       \
-        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>"         \
-        "  </method>"                                                   \
-        "  <method name=\"GetAll\">"                                    \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>"      \
-        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>" \
-        "  </method>"                                                   \
-        " </interface>"
-
-#define BUS_INTROSPECTABLE_INTERFACE                                    \
-        " <interface name=\"org.freedesktop.DBus.Introspectable\">"     \
-        "  <method name=\"Introspect\">"                                \
-        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"          \
-        "  </method>"                                                   \
-        " </interface>"
-
-int bus_init_system(Manager *m);
-int bus_init_api(Manager *m);
-void bus_done_system(Manager *m);
-void bus_done_api(Manager *m);
-
-unsigned bus_dispatch(Manager *m);
-
-void bus_watch_event(Manager *m, Watch *w, int events);
-void bus_timeout_event(Manager *m, Watch *w, int events);
-
-int bus_query_pid(Manager *m, const char *name);
-
-DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char* introspection, const BusProperty *properties);
-
-DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error);
-
-int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data);
-
-#define bus_property_append_int bus_property_append_int32
-#define bus_property_append_pid bus_property_append_uint32
-#define bus_property_append_mode bus_property_append_uint32
-#define bus_property_append_unsigned bus_property_append_uint32
-#define bus_property_append_usec bus_property_append_uint64
-
-#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type)             \
-        int function(Manager *m, DBusMessageIter *i, const char *property, void *data) { \
-                const char *value;                                      \
-                type *field = data;                                     \
-                                                                        \
-                assert(m);                                              \
-                assert(i);                                              \
-                assert(property);                                       \
-                                                                        \
-                value = name##_to_string(*field);                       \
-                                                                        \
-                if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \
-                        return -ENOMEM;                                 \
-                                                                        \
-                return 0;                                               \
-        }
-
-int bus_parse_strv(DBusMessage *m, char ***_l);
-
-#endif
diff --git a/device.c b/device.c
deleted file mode 100644
index e67d0a6..0000000
--- a/device.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/epoll.h>
-#include <libudev.h>
-
-#include "unit.h"
-#include "device.h"
-#include "strv.h"
-#include "log.h"
-#include "unit-name.h"
-#include "dbus-device.h"
-
-static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
-        [DEVICE_DEAD] = UNIT_INACTIVE,
-        [DEVICE_AVAILABLE] = UNIT_ACTIVE
-};
-
-static void device_done(Unit *u) {
-        Device *d = DEVICE(u);
-
-        assert(d);
-
-        free(d->sysfs);
-        d->sysfs = NULL;
-}
-
-static void device_set_state(Device *d, DeviceState state) {
-        DeviceState old_state;
-        assert(d);
-
-        old_state = d->state;
-        d->state = state;
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(d)->meta.id,
-                          device_state_to_string(old_state),
-                          device_state_to_string(state));
-
-        unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int device_coldplug(Unit *u) {
-        Device *d = DEVICE(u);
-
-        assert(d);
-        assert(d->state == DEVICE_DEAD);
-
-        if (d->sysfs)
-                device_set_state(d, DEVICE_AVAILABLE);
-
-        return 0;
-}
-
-static void device_dump(Unit *u, FILE *f, const char *prefix) {
-        Device *d = DEVICE(u);
-
-        assert(d);
-
-        fprintf(f,
-                "%sDevice State: %s\n"
-                "%sSysfs Path: %s\n",
-                prefix, device_state_to_string(d->state),
-                prefix, strna(d->sysfs));
-}
-
-static UnitActiveState device_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[DEVICE(u)->state];
-}
-
-static const char *device_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return device_state_to_string(DEVICE(u)->state);
-}
-
-static int device_add_escaped_name(Unit *u, const char *dn, bool make_id) {
-        char *e;
-        int r;
-
-        assert(u);
-        assert(dn);
-        assert(dn[0] == '/');
-
-        if (!(e = unit_name_from_path(dn, ".device")))
-                return -ENOMEM;
-
-        r = unit_add_name(u, e);
-
-        if (r >= 0 && make_id)
-                unit_choose_id(u, e);
-
-        free(e);
-
-        if (r < 0 && r != -EEXIST)
-                return r;
-
-        return 0;
-}
-
-static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
-        char *e;
-        Unit *u;
-
-        assert(m);
-        assert(dn);
-        assert(dn[0] == '/');
-        assert(_u);
-
-        if (!(e = unit_name_from_path(dn, ".device")))
-                return -ENOMEM;
-
-        u = manager_get_unit(m, e);
-        free(e);
-
-        if (u) {
-                *_u = u;
-                return 1;
-        }
-
-        return 0;
-}
-
-static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
-        const char *dn, *wants, *sysfs, *expose, *model, *alias;
-        Unit *u = NULL;
-        int r;
-        char *w, *state;
-        size_t l;
-        bool delete;
-        struct udev_list_entry *item = NULL, *first = NULL;
-        int b;
-
-        assert(m);
-
-        if (!(sysfs = udev_device_get_syspath(dev)))
-                return -ENOMEM;
-
-        if (!(expose = udev_device_get_property_value(dev, "SYSTEMD_EXPOSE")))
-                return 0;
-
-        if ((b = parse_boolean(expose)) < 0) {
-                log_error("Failed to parse SYSTEMD_EXPOSE udev property for device %s: %s", sysfs, expose);
-                return 0;
-        }
-
-        if (!b)
-                return 0;
-
-        /* Check whether this entry is even relevant for us. */
-        dn = udev_device_get_devnode(dev);
-        wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
-        alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
-
-        /* We allow exactly one alias to be configured a this time and
-         * it must be a path */
-
-        if (alias && !is_path(alias)) {
-                log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, alias);
-                alias = NULL;
-        }
-
-        if ((r = device_find_escape_name(m, sysfs, &u)) < 0)
-                return r;
-
-        if (r == 0 && dn)
-                if ((r = device_find_escape_name(m, dn, &u)) < 0)
-                        return r;
-
-        if (r == 0) {
-                first = udev_device_get_devlinks_list_entry(dev);
-                udev_list_entry_foreach(item, first) {
-                        if ((r = device_find_escape_name(m, udev_list_entry_get_name(item), &u)) < 0)
-                                return r;
-
-                        if (r > 0)
-                                break;
-                }
-        }
-
-        if (r == 0 && alias)
-                if ((r = device_find_escape_name(m, alias, &u)) < 0)
-                        return r;
-
-        /* FIXME: this needs proper merging */
-
-        assert((r > 0) == !!u);
-
-        /* If this is a different unit, then let's not merge things */
-        if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
-                u = NULL;
-
-        if (!u) {
-                delete = true;
-
-                if (!(u = unit_new(m)))
-                        return -ENOMEM;
-
-                if ((r = device_add_escaped_name(u, sysfs, true)) < 0)
-                        goto fail;
-
-                unit_add_to_load_queue(u);
-        } else
-                delete = false;
-
-        if (!(DEVICE(u)->sysfs))
-                if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-        if (alias)
-                if ((r = device_add_escaped_name(u, alias, true)) < 0)
-                        goto fail;
-
-        if (dn)
-                if ((r = device_add_escaped_name(u, dn, true)) < 0)
-                        goto fail;
-
-        first = udev_device_get_devlinks_list_entry(dev);
-        udev_list_entry_foreach(item, first)
-                if ((r = device_add_escaped_name(u, udev_list_entry_get_name(item), false)) < 0)
-                        goto fail;
-
-        if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
-            (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
-                if ((r = unit_set_description(u, model)) < 0)
-                        goto fail;
-        } else if (dn) {
-                if ((r = unit_set_description(u, dn)) < 0)
-                        goto fail;
-        } else
-                if ((r = unit_set_description(u, sysfs)) < 0)
-                        goto fail;
-
-        if (wants) {
-                FOREACH_WORD(w, l, wants, state) {
-                        char *e;
-
-                        if (!(e = strndup(w, l))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        r = unit_add_dependency_by_name(u, UNIT_WANTS, NULL, e, true);
-                        free(e);
-
-                        if (r < 0)
-                                goto fail;
-                }
-        }
-
-        if (update_state) {
-                manager_dispatch_load_queue(u->meta.manager);
-                device_set_state(DEVICE(u), DEVICE_AVAILABLE);
-        }
-
-        unit_add_to_dbus_queue(u);
-
-        return 0;
-
-fail:
-        if (delete && u)
-                unit_free(u);
-        return r;
-}
-
-static int device_process_path(Manager *m, const char *path, bool update_state) {
-        int r;
-        struct udev_device *dev;
-
-        assert(m);
-        assert(path);
-
-        if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
-                log_warning("Failed to get udev device object from udev for path %s.", path);
-                return -ENOMEM;
-        }
-
-        r = device_process_new_device(m, dev, update_state);
-        udev_device_unref(dev);
-        return r;
-}
-
-static int device_process_removed_device(Manager *m, struct udev_device *dev) {
-        const char *sysfs;
-        char *e;
-        Unit *u;
-        Device *d;
-
-        assert(m);
-        assert(dev);
-
-        if (!(sysfs = udev_device_get_syspath(dev)))
-                return -ENOMEM;
-
-        assert(sysfs[0] == '/');
-        if (!(e = unit_name_from_path(sysfs, ".device")))
-                return -ENOMEM;
-
-        u = manager_get_unit(m, e);
-        free(e);
-
-        if (!u)
-                return 0;
-
-        d = DEVICE(u);
-        free(d->sysfs);
-        d->sysfs = NULL;
-
-        device_set_state(d, DEVICE_DEAD);
-        return 0;
-}
-
-static void device_shutdown(Manager *m) {
-        assert(m);
-
-        if (m->udev_monitor) {
-                udev_monitor_unref(m->udev_monitor);
-                m->udev_monitor = NULL;
-        }
-
-        if (m->udev) {
-                udev_unref(m->udev);
-                m->udev = NULL;
-        }
-}
-
-static int device_enumerate(Manager *m) {
-        struct epoll_event ev;
-        int r;
-        struct udev_enumerate *e = NULL;
-        struct udev_list_entry *item = NULL, *first = NULL;
-
-        assert(m);
-
-        if (!m->udev) {
-                if (!(m->udev = udev_new()))
-                        return -ENOMEM;
-
-                if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
-                        r = -EIO;
-                        goto fail;
-                }
-
-                m->udev_watch.type = WATCH_UDEV;
-                m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
-
-                zero(ev);
-                ev.events = EPOLLIN;
-                ev.data.ptr = &m->udev_watch;
-
-                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
-                        return -errno;
-        }
-
-        if (!(e = udev_enumerate_new(m->udev))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto fail;
-        }
-
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first)
-                device_process_path(m, udev_list_entry_get_name(item), false);
-
-        udev_enumerate_unref(e);
-        return 0;
-
-fail:
-        if (e)
-                udev_enumerate_unref(e);
-
-        device_shutdown(m);
-        return r;
-}
-
-void device_fd_event(Manager *m, int events) {
-        struct udev_device *dev;
-        int r;
-        const char *action;
-
-        assert(m);
-        assert(events == EPOLLIN);
-
-        if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
-                log_error("Failed to receive device.");
-                return;
-        }
-
-        if (!(action = udev_device_get_action(dev))) {
-                log_error("Failed to get udev action string.");
-                goto fail;
-        }
-
-        if (streq(action, "remove")) {
-                if ((r = device_process_removed_device(m, dev)) < 0) {
-                        log_error("Failed to process udev device event: %s", strerror(-r));
-                        goto fail;
-                }
-        } else {
-                if ((r = device_process_new_device(m, dev, true)) < 0) {
-                        log_error("Failed to process udev device event: %s", strerror(-r));
-                        goto fail;
-                }
-        }
-
-fail:
-        udev_device_unref(dev);
-}
-
-static const char* const device_state_table[_DEVICE_STATE_MAX] = {
-        [DEVICE_DEAD] = "dead",
-        [DEVICE_AVAILABLE] = "available"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
-
-const UnitVTable device_vtable = {
-        .suffix = ".device",
-
-        .no_requires = true,
-        .no_instances = true,
-        .no_snapshots = true,
-        .no_isolate = true,
-
-        .load = unit_load_fragment_and_dropin_optional,
-        .done = device_done,
-        .coldplug = device_coldplug,
-
-        .dump = device_dump,
-
-        .active_state = device_active_state,
-        .sub_state_to_string = device_sub_state_to_string,
-
-        .bus_message_handler = bus_device_message_handler,
-
-        .enumerate = device_enumerate,
-        .shutdown = device_shutdown
-};
diff --git a/device.h b/device.h
deleted file mode 100644
index a5c5f74..0000000
--- a/device.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foodevicehfoo
-#define foodevicehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Device Device;
-
-#include "unit.h"
-
-/* We simply watch devices, we cannot plug/unplug them. That
- * simplifies the state engine greatly */
-typedef enum DeviceState {
-        DEVICE_DEAD,
-        DEVICE_AVAILABLE,
-        _DEVICE_STATE_MAX,
-        _DEVICE_STATE_INVALID = -1
-} DeviceState;
-
-struct Device {
-        Meta meta;
-
-        DeviceState state;
-
-        char *sysfs;
-};
-
-extern const UnitVTable device_vtable;
-
-void device_fd_event(Manager *m, int events);
-
-const char* device_state_to_string(DeviceState i);
-DeviceState device_state_from_string(const char *s);
-
-#endif
diff --git a/execute.c b/execute.c
deleted file mode 100644
index 12f5145..0000000
--- a/execute.c
+++ /dev/null
@@ -1,1619 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/prctl.h>
-#include <linux/sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-
-#include "execute.h"
-#include "strv.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "cgroup.h"
-#include "namespace.h"
-
-/* This assumes there is a 'tty' group */
-#define TTY_MODE 0620
-
-static int shift_fds(int fds[], unsigned n_fds) {
-        int start, restart_from;
-
-        if (n_fds <= 0)
-                return 0;
-
-        /* Modifies the fds array! (sorts it) */
-
-        assert(fds);
-
-        start = 0;
-        for (;;) {
-                int i;
-
-                restart_from = -1;
-
-                for (i = start; i < (int) n_fds; i++) {
-                        int nfd;
-
-                        /* Already at right index? */
-                        if (fds[i] == i+3)
-                                continue;
-
-                        if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
-                                return -errno;
-
-                        close_nointr_nofail(fds[i]);
-                        fds[i] = nfd;
-
-                        /* Hmm, the fd we wanted isn't free? Then
-                         * let's remember that and try again from here*/
-                        if (nfd != i+3 && restart_from < 0)
-                                restart_from = i;
-                }
-
-                if (restart_from < 0)
-                        break;
-
-                start = restart_from;
-        }
-
-        return 0;
-}
-
-static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
-        unsigned i;
-        int r;
-
-        if (n_fds <= 0)
-                return 0;
-
-        assert(fds);
-
-        /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
-
-        for (i = 0; i < n_fds; i++) {
-
-                if ((r = fd_nonblock(fds[i], nonblock)) < 0)
-                        return r;
-
-                /* We unconditionally drop FD_CLOEXEC from the fds,
-                 * since after all we want to pass these fds to our
-                 * children */
-
-                if ((r = fd_cloexec(fds[i], false)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static const char *tty_path(const ExecContext *context) {
-        assert(context);
-
-        if (context->tty_path)
-                return context->tty_path;
-
-        return "/dev/console";
-}
-
-static int open_null_as(int flags, int nfd) {
-        int fd, r;
-
-        assert(nfd >= 0);
-
-        if ((fd = open("/dev/null", flags|O_NOCTTY)) < 0)
-                return -errno;
-
-        if (fd != nfd) {
-                r = dup2(fd, nfd) < 0 ? -errno : nfd;
-                close_nointr_nofail(fd);
-        } else
-                r = nfd;
-
-        return r;
-}
-
-static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, int nfd) {
-        int fd, r;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_un un;
-        } sa;
-
-        assert(context);
-        assert(output < _EXEC_OUTPUT_MAX);
-        assert(ident);
-        assert(nfd >= 0);
-
-        if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
-                return -errno;
-
-        zero(sa);
-        sa.sa.sa_family = AF_UNIX;
-        strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
-
-        if (connect(fd, &sa.sa, sizeof(sa)) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        if (shutdown(fd, SHUT_RD) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        /* We speak a very simple protocol between log server
-         * and client: one line for the log destination (kmsg
-         * or syslog), followed by the priority field,
-         * followed by the process name. Since we replaced
-         * stdin/stderr we simple use stdio to write to
-         * it. Note that we use stderr, to minimize buffer
-         * flushing issues. */
-
-        dprintf(fd,
-                "%s\n"
-                "%i\n"
-                "%s\n"
-                "%i\n",
-                output == EXEC_OUTPUT_KERNEL ? "kmsg" : "syslog",
-                context->syslog_priority,
-                context->syslog_identifier ? context->syslog_identifier : ident,
-                !context->syslog_no_prefix);
-
-        if (fd != nfd) {
-                r = dup2(fd, nfd) < 0 ? -errno : nfd;
-                close_nointr_nofail(fd);
-        } else
-                r = nfd;
-
-        return r;
-}
-static int open_terminal_as(const char *path, mode_t mode, int nfd) {
-        int fd, r;
-
-        assert(path);
-        assert(nfd >= 0);
-
-        if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
-                return fd;
-
-        if (fd != nfd) {
-                r = dup2(fd, nfd) < 0 ? -errno : nfd;
-                close_nointr_nofail(fd);
-        } else
-                r = nfd;
-
-        return r;
-}
-
-static bool is_terminal_input(ExecInput i) {
-        return
-                i == EXEC_INPUT_TTY ||
-                i == EXEC_INPUT_TTY_FORCE ||
-                i == EXEC_INPUT_TTY_FAIL;
-}
-
-static int fixup_input(const ExecContext *context, int socket_fd) {
-        assert(context);
-
-        if (socket_fd < 0 && context->std_input == EXEC_INPUT_SOCKET)
-                return EXEC_INPUT_NULL;
-
-        return context->std_input;
-}
-
-static int fixup_output(const ExecContext *context, int socket_fd) {
-        assert(context);
-
-        if (socket_fd < 0 && context->std_output == EXEC_OUTPUT_SOCKET)
-                return EXEC_OUTPUT_INHERIT;
-
-        return context->std_output;
-}
-
-static int fixup_error(const ExecContext *context, int socket_fd) {
-        assert(context);
-
-        if (socket_fd < 0 && context->std_error == EXEC_OUTPUT_SOCKET)
-                return EXEC_OUTPUT_INHERIT;
-
-        return context->std_error;
-}
-
-static int setup_input(const ExecContext *context, int socket_fd) {
-        ExecInput i;
-
-        assert(context);
-
-        i = fixup_input(context, socket_fd);
-
-        switch (i) {
-
-        case EXEC_INPUT_NULL:
-                return open_null_as(O_RDONLY, STDIN_FILENO);
-
-        case EXEC_INPUT_TTY:
-        case EXEC_INPUT_TTY_FORCE:
-        case EXEC_INPUT_TTY_FAIL: {
-                int fd, r;
-
-                if ((fd = acquire_terminal(
-                                     tty_path(context),
-                                     i == EXEC_INPUT_TTY_FAIL,
-                                     i == EXEC_INPUT_TTY_FORCE)) < 0)
-                        return fd;
-
-                if (fd != STDIN_FILENO) {
-                        r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
-                        close_nointr_nofail(fd);
-                } else
-                        r = STDIN_FILENO;
-
-                return r;
-        }
-
-        case EXEC_INPUT_SOCKET:
-                return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
-
-        default:
-                assert_not_reached("Unknown input type");
-        }
-}
-
-static int setup_output(const ExecContext *context, int socket_fd, const char *ident) {
-        ExecOutput o;
-        ExecInput i;
-
-        assert(context);
-        assert(ident);
-
-        i = fixup_input(context, socket_fd);
-        o = fixup_output(context, socket_fd);
-
-        /* This expects the input is already set up */
-
-        switch (o) {
-
-        case EXEC_OUTPUT_INHERIT:
-
-                /* If the input is connected to a terminal, inherit that... */
-                if (is_terminal_input(i) || i == EXEC_INPUT_SOCKET)
-                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
-                return STDIN_FILENO;
-
-        case EXEC_OUTPUT_NULL:
-                return open_null_as(O_WRONLY, STDOUT_FILENO);
-
-        case EXEC_OUTPUT_TTY:
-                if (is_terminal_input(i))
-                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
-                /* We don't reset the terminal if this is just about output */
-                return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
-
-        case EXEC_OUTPUT_SYSLOG:
-        case EXEC_OUTPUT_KERNEL:
-                return connect_logger_as(context, o, ident, STDOUT_FILENO);
-
-        case EXEC_OUTPUT_SOCKET:
-                assert(socket_fd >= 0);
-                return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
-        default:
-                assert_not_reached("Unknown output type");
-        }
-}
-
-static int setup_error(const ExecContext *context, int socket_fd, const char *ident) {
-        ExecOutput o, e;
-        ExecInput i;
-
-        assert(context);
-        assert(ident);
-
-        i = fixup_input(context, socket_fd);
-        o = fixup_output(context, socket_fd);
-        e = fixup_error(context, socket_fd);
-
-        /* This expects the input and output are already set up */
-
-        /* Don't change the stderr file descriptor if we inherit all
-         * the way and are not on a tty */
-        if (e == EXEC_OUTPUT_INHERIT &&
-            o == EXEC_OUTPUT_INHERIT &&
-            !is_terminal_input(i))
-                return STDERR_FILENO;
-
-        /* Duplicate form stdout if possible */
-        if (e == o || e == EXEC_OUTPUT_INHERIT)
-                return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
-
-        switch (e) {
-
-        case EXEC_OUTPUT_NULL:
-                return open_null_as(O_WRONLY, STDERR_FILENO);
-
-        case EXEC_OUTPUT_TTY:
-                if (is_terminal_input(i))
-                        return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
-
-                /* We don't reset the terminal if this is just about output */
-                return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);
-
-        case EXEC_OUTPUT_SYSLOG:
-        case EXEC_OUTPUT_KERNEL:
-                return connect_logger_as(context, e, ident, STDERR_FILENO);
-
-        case EXEC_OUTPUT_SOCKET:
-                assert(socket_fd >= 0);
-                return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
-
-        default:
-                assert_not_reached("Unknown error type");
-        }
-}
-
-static int chown_terminal(int fd, uid_t uid) {
-        struct stat st;
-
-        assert(fd >= 0);
-
-        /* This might fail. What matters are the results. */
-        (void) fchown(fd, uid, -1);
-        (void) fchmod(fd, TTY_MODE);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
-                return -EPERM;
-
-        return 0;
-}
-
-static int setup_confirm_stdio(const ExecContext *context,
-                               int *_saved_stdin,
-                               int *_saved_stdout) {
-        int fd = -1, saved_stdin, saved_stdout = -1, r;
-
-        assert(context);
-        assert(_saved_stdin);
-        assert(_saved_stdout);
-
-        /* This returns positive EXIT_xxx return values instead of
-         * negative errno style values! */
-
-        if ((saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3)) < 0)
-                return EXIT_STDIN;
-
-        if ((saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3)) < 0) {
-                r = EXIT_STDOUT;
-                goto fail;
-        }
-
-        if ((fd = acquire_terminal(
-                             tty_path(context),
-                             context->std_input == EXEC_INPUT_TTY_FAIL,
-                             context->std_input == EXEC_INPUT_TTY_FORCE)) < 0) {
-                r = EXIT_STDIN;
-                goto fail;
-        }
-
-        if (chown_terminal(fd, getuid()) < 0) {
-                r = EXIT_STDIN;
-                goto fail;
-        }
-
-        if (dup2(fd, STDIN_FILENO) < 0) {
-                r = EXIT_STDIN;
-                goto fail;
-        }
-
-        if (dup2(fd, STDOUT_FILENO) < 0) {
-                r = EXIT_STDOUT;
-                goto fail;
-        }
-
-        if (fd >= 2)
-                close_nointr_nofail(fd);
-
-        *_saved_stdin = saved_stdin;
-        *_saved_stdout = saved_stdout;
-
-        return 0;
-
-fail:
-        if (saved_stdout >= 0)
-                close_nointr_nofail(saved_stdout);
-
-        if (saved_stdin >= 0)
-                close_nointr_nofail(saved_stdin);
-
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
-
-static int restore_confirm_stdio(const ExecContext *context,
-                                 int *saved_stdin,
-                                 int *saved_stdout,
-                                 bool *keep_stdin,
-                                 bool *keep_stdout) {
-
-        assert(context);
-        assert(saved_stdin);
-        assert(*saved_stdin >= 0);
-        assert(saved_stdout);
-        assert(*saved_stdout >= 0);
-
-        /* This returns positive EXIT_xxx return values instead of
-         * negative errno style values! */
-
-        if (is_terminal_input(context->std_input)) {
-
-                /* The service wants terminal input. */
-
-                *keep_stdin = true;
-                *keep_stdout =
-                        context->std_output == EXEC_OUTPUT_INHERIT ||
-                        context->std_output == EXEC_OUTPUT_TTY;
-
-        } else {
-                /* If the service doesn't want a controlling terminal,
-                 * then we need to get rid entirely of what we have
-                 * already. */
-
-                if (release_terminal() < 0)
-                        return EXIT_STDIN;
-
-                if (dup2(*saved_stdin, STDIN_FILENO) < 0)
-                        return EXIT_STDIN;
-
-                if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
-                        return EXIT_STDOUT;
-
-                *keep_stdout = *keep_stdin = false;
-        }
-
-        return 0;
-}
-
-static int get_group_creds(const char *groupname, gid_t *gid) {
-        struct group *g;
-        unsigned long lu;
-
-        assert(groupname);
-        assert(gid);
-
-        /* We enforce some special rules for gid=0: in order to avoid
-         * NSS lookups for root we hardcode its data. */
-
-        if (streq(groupname, "root") || streq(groupname, "0")) {
-                *gid = 0;
-                return 0;
-        }
-
-        if (safe_atolu(groupname, &lu) >= 0) {
-                errno = 0;
-                g = getgrgid((gid_t) lu);
-        } else {
-                errno = 0;
-                g = getgrnam(groupname);
-        }
-
-        if (!g)
-                return errno != 0 ? -errno : -ESRCH;
-
-        *gid = g->gr_gid;
-        return 0;
-}
-
-static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
-        struct passwd *p;
-        unsigned long lu;
-
-        assert(username);
-        assert(*username);
-        assert(uid);
-        assert(gid);
-        assert(home);
-
-        /* We enforce some special rules for uid=0: in order to avoid
-         * NSS lookups for root we hardcode its data. */
-
-        if (streq(*username, "root") || streq(*username, "0")) {
-                *username = "root";
-                *uid = 0;
-                *gid = 0;
-                *home = "/root";
-                return 0;
-        }
-
-        if (safe_atolu(*username, &lu) >= 0) {
-                errno = 0;
-                p = getpwuid((uid_t) lu);
-
-                /* If there are multiple users with the same id, make
-                 * sure to leave $USER to the configured value instead
-                 * of the first occurence in the database. However if
-                 * the uid was configured by a numeric uid, then let's
-                 * pick the real username from /etc/passwd. */
-                if (*username && p)
-                        *username = p->pw_name;
-        } else {
-                errno = 0;
-                p = getpwnam(*username);
-        }
-
-        if (!p)
-                return errno != 0 ? -errno : -ESRCH;
-
-        *uid = p->pw_uid;
-        *gid = p->pw_gid;
-        *home = p->pw_dir;
-        return 0;
-}
-
-static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
-        bool keep_groups = false;
-        int r;
-
-        assert(context);
-
-        /* Lookup and ser GID and supplementary group list. Here too
-         * we avoid NSS lookups for gid=0. */
-
-        if (context->group || username) {
-
-                if (context->group)
-                        if ((r = get_group_creds(context->group, &gid)) < 0)
-                                return r;
-
-                /* First step, initialize groups from /etc/groups */
-                if (username && gid != 0) {
-                        if (initgroups(username, gid) < 0)
-                                return -errno;
-
-                        keep_groups = true;
-                }
-
-                /* Second step, set our gids */
-                if (setresgid(gid, gid, gid) < 0)
-                        return -errno;
-        }
-
-        if (context->supplementary_groups) {
-                int ngroups_max, k;
-                gid_t *gids;
-                char **i;
-
-                /* Final step, initialize any manually set supplementary groups */
-                ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);
-
-                if (!(gids = new(gid_t, ngroups_max)))
-                        return -ENOMEM;
-
-                if (keep_groups) {
-                        if ((k = getgroups(ngroups_max, gids)) < 0) {
-                                free(gids);
-                                return -errno;
-                        }
-                } else
-                        k = 0;
-
-                STRV_FOREACH(i, context->supplementary_groups) {
-
-                        if (k >= ngroups_max) {
-                                free(gids);
-                                return -E2BIG;
-                        }
-
-                        if ((r = get_group_creds(*i, gids+k)) < 0) {
-                                free(gids);
-                                return r;
-                        }
-
-                        k++;
-                }
-
-                if (setgroups(k, gids) < 0) {
-                        free(gids);
-                        return -errno;
-                }
-
-                free(gids);
-        }
-
-        return 0;
-}
-
-static int enforce_user(const ExecContext *context, uid_t uid) {
-        int r;
-        assert(context);
-
-        /* Sets (but doesn't lookup) the uid and make sure we keep the
-         * capabilities while doing so. */
-
-        if (context->capabilities) {
-                cap_t d;
-                static const cap_value_t bits[] = {
-                        CAP_SETUID,   /* Necessary so that we can run setresuid() below */
-                        CAP_SETPCAP   /* Necessary so that we can set PR_SET_SECUREBITS later on */
-                };
-
-                /* First step: If we need to keep capabilities but
-                 * drop privileges we need to make sure we keep our
-                 * caps, whiel we drop priviliges. */
-                if (uid != 0) {
-                        int sb = context->secure_bits|SECURE_KEEP_CAPS;
-
-                        if (prctl(PR_GET_SECUREBITS) != sb)
-                                if (prctl(PR_SET_SECUREBITS, sb) < 0)
-                                        return -errno;
-                }
-
-                /* Second step: set the capabilites. This will reduce
-                 * the capabilities to the minimum we need. */
-
-                if (!(d = cap_dup(context->capabilities)))
-                        return -errno;
-
-                if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
-                    cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) {
-                        r = -errno;
-                        cap_free(d);
-                        return r;
-                }
-
-                if (cap_set_proc(d) < 0) {
-                        r = -errno;
-                        cap_free(d);
-                        return r;
-                }
-
-                cap_free(d);
-        }
-
-        /* Third step: actually set the uids */
-        if (setresuid(uid, uid, uid) < 0)
-                return -errno;
-
-        /* At this point we should have all necessary capabilities but
-           are otherwise a normal user. However, the caps might got
-           corrupted due to the setresuid() so we need clean them up
-           later. This is done outside of this call. */
-
-        return 0;
-}
-
-int exec_spawn(ExecCommand *command,
-               char **argv,
-               const ExecContext *context,
-               int fds[], unsigned n_fds,
-               char **environment,
-               bool apply_permissions,
-               bool apply_chroot,
-               bool confirm_spawn,
-               CGroupBonding *cgroup_bondings,
-               pid_t *ret) {
-
-        pid_t pid;
-        int r;
-        char *line;
-        int socket_fd;
-
-        assert(command);
-        assert(context);
-        assert(ret);
-        assert(fds || n_fds <= 0);
-
-        if (context->std_input == EXEC_INPUT_SOCKET ||
-            context->std_output == EXEC_OUTPUT_SOCKET ||
-            context->std_error == EXEC_OUTPUT_SOCKET) {
-
-                if (n_fds != 1)
-                        return -EINVAL;
-
-                socket_fd = fds[0];
-
-                fds = NULL;
-                n_fds = 0;
-        } else
-                socket_fd = -1;
-
-        if (!argv)
-                argv = command->argv;
-
-        if (!(line = exec_command_line(argv)))
-                return -ENOMEM;
-
-        log_debug("About to execute: %s", line);
-        free(line);
-
-        if (cgroup_bondings)
-                if ((r = cgroup_bonding_realize_list(cgroup_bondings)))
-                        return r;
-
-        if ((pid = fork()) < 0)
-                return -errno;
-
-        if (pid == 0) {
-                int i;
-                sigset_t ss;
-                const char *username = NULL, *home = NULL;
-                uid_t uid = (uid_t) -1;
-                gid_t gid = (gid_t) -1;
-                char **our_env = NULL, **final_env = NULL;
-                unsigned n_env = 0;
-                int saved_stdout = -1, saved_stdin = -1;
-                bool keep_stdout = false, keep_stdin = false;
-
-                /* child */
-
-                reset_all_signal_handlers();
-
-                if (sigemptyset(&ss) < 0 ||
-                    sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
-                        r = EXIT_SIGNAL_MASK;
-                        goto fail;
-                }
-
-                if (!context->no_setsid)
-                        if (setsid() < 0) {
-                                r = EXIT_SETSID;
-                                goto fail;
-                        }
-
-                if (confirm_spawn) {
-                        char response;
-
-                        /* Set up terminal for the question */
-                        if ((r = setup_confirm_stdio(context,
-                                                     &saved_stdin, &saved_stdout)))
-                                goto fail;
-
-                        /* Now ask the question. */
-                        if (!(line = exec_command_line(argv))) {
-                                r = EXIT_MEMORY;
-                                goto fail;
-                        }
-
-                        r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line);
-                        free(line);
-
-                        if (r < 0 || response == 'n') {
-                                r = EXIT_CONFIRM;
-                                goto fail;
-                        } else if (response == 's') {
-                                r = 0;
-                                goto fail;
-                        }
-
-                        /* Release terminal for the question */
-                        if ((r = restore_confirm_stdio(context,
-                                                       &saved_stdin, &saved_stdout,
-                                                       &keep_stdin, &keep_stdout)))
-                                goto fail;
-                }
-
-                if (!keep_stdin)
-                        if (setup_input(context, socket_fd) < 0) {
-                                r = EXIT_STDIN;
-                                goto fail;
-                        }
-
-                if (!keep_stdout)
-                        if (setup_output(context, socket_fd, file_name_from_path(command->path)) < 0) {
-                                r = EXIT_STDOUT;
-                                goto fail;
-                        }
-
-                if (setup_error(context, socket_fd, file_name_from_path(command->path)) < 0) {
-                        r = EXIT_STDERR;
-                        goto fail;
-                }
-
-                if (cgroup_bondings)
-                        if ((r = cgroup_bonding_install_list(cgroup_bondings, 0)) < 0) {
-                                r = EXIT_CGROUP;
-                                goto fail;
-                        }
-
-                if (context->oom_adjust_set) {
-                        char t[16];
-
-                        snprintf(t, sizeof(t), "%i", context->oom_adjust);
-                        char_array_0(t);
-
-                        if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
-                                r = EXIT_OOM_ADJUST;
-                                goto fail;
-                        }
-                }
-
-                if (context->nice_set)
-                        if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
-                                r = EXIT_NICE;
-                                goto fail;
-                        }
-
-                if (context->cpu_sched_set) {
-                        struct sched_param param;
-
-                        zero(param);
-                        param.sched_priority = context->cpu_sched_priority;
-
-                        if (sched_setscheduler(0, context->cpu_sched_policy |
-                                               (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), &param) < 0) {
-                                r = EXIT_SETSCHEDULER;
-                                goto fail;
-                        }
-                }
-
-                if (context->cpu_affinity_set)
-                        if (sched_setaffinity(0, sizeof(context->cpu_affinity), &context->cpu_affinity) < 0) {
-                                r = EXIT_CPUAFFINITY;
-                                goto fail;
-                        }
-
-                if (context->ioprio_set)
-                        if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
-                                r = EXIT_IOPRIO;
-                                goto fail;
-                        }
-
-                if (context->timer_slack_ns_set)
-                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_ns_set) < 0) {
-                                r = EXIT_TIMERSLACK;
-                                goto fail;
-                        }
-
-                if (strv_length(context->read_write_dirs) > 0 ||
-                    strv_length(context->read_only_dirs) > 0 ||
-                    strv_length(context->inaccessible_dirs) > 0 ||
-                    context->mount_flags != MS_SHARED ||
-                    context->private_tmp)
-                        if ((r = setup_namespace(
-                                             context->read_write_dirs,
-                                             context->read_only_dirs,
-                                             context->inaccessible_dirs,
-                                             context->private_tmp,
-                                             context->mount_flags)) < 0)
-                                goto fail;
-
-                if (context->user) {
-                        username = context->user;
-                        if (get_user_creds(&username, &uid, &gid, &home) < 0) {
-                                r = EXIT_USER;
-                                goto fail;
-                        }
-
-                        if (is_terminal_input(context->std_input))
-                                if (chown_terminal(STDIN_FILENO, uid) < 0) {
-                                        r = EXIT_STDIN;
-                                        goto fail;
-                                }
-                }
-
-                if (apply_permissions)
-                        if (enforce_groups(context, username, uid) < 0) {
-                                r = EXIT_GROUP;
-                                goto fail;
-                        }
-
-                umask(context->umask);
-
-                if (apply_chroot) {
-                        if (context->root_directory)
-                                if (chroot(context->root_directory) < 0) {
-                                        r = EXIT_CHROOT;
-                                        goto fail;
-                                }
-
-                        if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
-                                r = EXIT_CHDIR;
-                                goto fail;
-                        }
-                } else {
-
-                        char *d;
-
-                        if (asprintf(&d, "%s/%s",
-                                     context->root_directory ? context->root_directory : "",
-                                     context->working_directory ? context->working_directory : "") < 0) {
-                                r = EXIT_MEMORY;
-                                goto fail;
-                        }
-
-                        if (chdir(d) < 0) {
-                                free(d);
-                                r = EXIT_CHDIR;
-                                goto fail;
-                        }
-
-                        free(d);
-                }
-
-                if (close_all_fds(fds, n_fds) < 0 ||
-                    shift_fds(fds, n_fds) < 0 ||
-                    flags_fds(fds, n_fds, context->non_blocking) < 0) {
-                        r = EXIT_FDS;
-                        goto fail;
-                }
-
-                if (apply_permissions) {
-
-                        for (i = 0; i < RLIMIT_NLIMITS; i++) {
-                                if (!context->rlimit[i])
-                                        continue;
-
-                                if (setrlimit(i, context->rlimit[i]) < 0) {
-                                        r = EXIT_LIMITS;
-                                        goto fail;
-                                }
-                        }
-
-                        if (context->user)
-                                if (enforce_user(context, uid) < 0) {
-                                        r = EXIT_USER;
-                                        goto fail;
-                                }
-
-                        /* PR_GET_SECUREBITS is not priviliged, while
-                         * PR_SET_SECUREBITS is. So to suppress
-                         * potential EPERMs we'll try not to call
-                         * PR_SET_SECUREBITS unless necessary. */
-                        if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
-                                if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
-                                        r = EXIT_SECUREBITS;
-                                        goto fail;
-                                }
-
-                        if (context->capabilities)
-                                if (cap_set_proc(context->capabilities) < 0) {
-                                        r = EXIT_CAPABILITIES;
-                                        goto fail;
-                                }
-                }
-
-                if (!(our_env = new0(char*, 6))) {
-                        r = EXIT_MEMORY;
-                        goto fail;
-                }
-
-                if (n_fds > 0)
-                        if (asprintf(our_env + n_env++, "LISTEN_PID=%llu", (unsigned long long) getpid()) < 0 ||
-                            asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
-                                r = EXIT_MEMORY;
-                                goto fail;
-                        }
-
-                if (home)
-                        if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
-                                r = EXIT_MEMORY;
-                                goto fail;
-                        }
-
-                if (username)
-                        if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
-                            asprintf(our_env + n_env++, "USER=%s", username) < 0) {
-                                r = EXIT_MEMORY;
-                                goto fail;
-                        }
-
-                assert(n_env <= 6);
-
-                if (!(final_env = strv_env_merge(environment, our_env, context->environment, NULL))) {
-                        r = EXIT_MEMORY;
-                        goto fail;
-                }
-
-                execve(command->path, argv, final_env);
-                r = EXIT_EXEC;
-
-        fail:
-                strv_free(our_env);
-                strv_free(final_env);
-
-                if (saved_stdin >= 0)
-                        close_nointr_nofail(saved_stdin);
-
-                if (saved_stdout >= 0)
-                        close_nointr_nofail(saved_stdout);
-
-                _exit(r);
-        }
-
-        /* We add the new process to the cgroup both in the child (so
-         * that we can be sure that no user code is ever executed
-         * outside of the cgroup) and in the parent (so that we can be
-         * sure that when we kill the cgroup the process will be
-         * killed too). */
-        if (cgroup_bondings)
-                cgroup_bonding_install_list(cgroup_bondings, pid);
-
-        log_debug("Forked %s as %llu", command->path, (unsigned long long) pid);
-
-        command->exec_status.pid = pid;
-        command->exec_status.start_timestamp = now(CLOCK_REALTIME);
-
-        *ret = pid;
-        return 0;
-}
-
-void exec_context_init(ExecContext *c) {
-        assert(c);
-
-        c->umask = 0002;
-        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
-        c->cpu_sched_policy = SCHED_OTHER;
-        c->syslog_priority = LOG_DAEMON|LOG_INFO;
-        c->mount_flags = MS_SHARED;
-}
-
-void exec_context_done(ExecContext *c) {
-        unsigned l;
-
-        assert(c);
-
-        strv_free(c->environment);
-        c->environment = NULL;
-
-        for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
-                free(c->rlimit[l]);
-                c->rlimit[l] = NULL;
-        }
-
-        free(c->working_directory);
-        c->working_directory = NULL;
-        free(c->root_directory);
-        c->root_directory = NULL;
-
-        free(c->tty_path);
-        c->tty_path = NULL;
-
-        free(c->syslog_identifier);
-        c->syslog_identifier = NULL;
-
-        free(c->user);
-        c->user = NULL;
-
-        free(c->group);
-        c->group = NULL;
-
-        strv_free(c->supplementary_groups);
-        c->supplementary_groups = NULL;
-
-        if (c->capabilities) {
-                cap_free(c->capabilities);
-                c->capabilities = NULL;
-        }
-
-        strv_free(c->read_only_dirs);
-        c->read_only_dirs = NULL;
-
-        strv_free(c->read_write_dirs);
-        c->read_write_dirs = NULL;
-
-        strv_free(c->inaccessible_dirs);
-        c->inaccessible_dirs = NULL;
-}
-
-void exec_command_done(ExecCommand *c) {
-        assert(c);
-
-        free(c->path);
-        c->path = NULL;
-
-        strv_free(c->argv);
-        c->argv = NULL;
-}
-
-void exec_command_done_array(ExecCommand *c, unsigned n) {
-        unsigned i;
-
-        for (i = 0; i < n; i++)
-                exec_command_done(c+i);
-}
-
-void exec_command_free_list(ExecCommand *c) {
-        ExecCommand *i;
-
-        while ((i = c)) {
-                LIST_REMOVE(ExecCommand, command, c, i);
-                exec_command_done(i);
-                free(i);
-        }
-}
-
-void exec_command_free_array(ExecCommand **c, unsigned n) {
-        unsigned i;
-
-        for (i = 0; i < n; i++) {
-                exec_command_free_list(c[i]);
-                c[i] = NULL;
-        }
-}
-
-static void strv_fprintf(FILE *f, char **l) {
-        char **g;
-
-        assert(f);
-
-        STRV_FOREACH(g, l)
-                fprintf(f, " %s", *g);
-}
-
-void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
-        char ** e;
-        unsigned i;
-
-        assert(c);
-        assert(f);
-
-        if (!prefix)
-                prefix = "";
-
-        fprintf(f,
-                "%sUMask: %04o\n"
-                "%sWorkingDirectory: %s\n"
-                "%sRootDirectory: %s\n"
-                "%sNonBlocking: %s\n"
-                "%sPrivateTmp: %s\n",
-                prefix, c->umask,
-                prefix, c->working_directory ? c->working_directory : "/",
-                prefix, c->root_directory ? c->root_directory : "/",
-                prefix, yes_no(c->non_blocking),
-                prefix, yes_no(c->private_tmp));
-
-        if (c->environment)
-                for (e = c->environment; *e; e++)
-                        fprintf(f, "%sEnvironment: %s\n", prefix, *e);
-
-        if (c->nice_set)
-                fprintf(f,
-                        "%sNice: %i\n",
-                        prefix, c->nice);
-
-        if (c->oom_adjust_set)
-                fprintf(f,
-                        "%sOOMAdjust: %i\n",
-                        prefix, c->oom_adjust);
-
-        for (i = 0; i < RLIM_NLIMITS; i++)
-                if (c->rlimit[i])
-                        fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
-
-        if (c->ioprio_set)
-                fprintf(f,
-                        "%sIOSchedulingClass: %s\n"
-                        "%sIOPriority: %i\n",
-                        prefix, ioprio_class_to_string(IOPRIO_PRIO_CLASS(c->ioprio)),
-                        prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
-
-        if (c->cpu_sched_set)
-                fprintf(f,
-                        "%sCPUSchedulingPolicy: %s\n"
-                        "%sCPUSchedulingPriority: %i\n"
-                        "%sCPUSchedulingResetOnFork: %s\n",
-                        prefix, sched_policy_to_string(c->cpu_sched_policy),
-                        prefix, c->cpu_sched_priority,
-                        prefix, yes_no(c->cpu_sched_reset_on_fork));
-
-        if (c->cpu_affinity_set) {
-                fprintf(f, "%sCPUAffinity:", prefix);
-                for (i = 0; i < CPU_SETSIZE; i++)
-                        if (CPU_ISSET(i, &c->cpu_affinity))
-                                fprintf(f, " %i", i);
-                fputs("\n", f);
-        }
-
-        if (c->timer_slack_ns_set)
-                fprintf(f, "%sTimerSlackNS: %lu\n", prefix, c->timer_slack_ns);
-
-        fprintf(f,
-                "%sStandardInput: %s\n"
-                "%sStandardOutput: %s\n"
-                "%sStandardError: %s\n",
-                prefix, exec_input_to_string(c->std_input),
-                prefix, exec_output_to_string(c->std_output),
-                prefix, exec_output_to_string(c->std_error));
-
-        if (c->tty_path)
-                fprintf(f,
-                        "%sTTYPath: %s\n",
-                        prefix, c->tty_path);
-
-        if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KERNEL ||
-            c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KERNEL)
-                fprintf(f,
-                        "%sSyslogFacility: %s\n"
-                        "%sSyslogLevel: %s\n",
-                        prefix, log_facility_to_string(LOG_FAC(c->syslog_priority)),
-                        prefix, log_level_to_string(LOG_PRI(c->syslog_priority)));
-
-        if (c->capabilities) {
-                char *t;
-                if ((t = cap_to_text(c->capabilities, NULL))) {
-                        fprintf(f, "%sCapabilities: %s\n",
-                                prefix, t);
-                        cap_free(t);
-                }
-        }
-
-        if (c->secure_bits)
-                fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
-                        prefix,
-                        (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "",
-                        (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
-                        (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
-                        (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
-                        (c->secure_bits & SECURE_NOROOT) ? " noroot" : "",
-                        (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
-
-        if (c->capability_bounding_set_drop) {
-                fprintf(f, "%sCapabilityBoundingSetDrop:", prefix);
-
-                for (i = 0; i <= CAP_LAST_CAP; i++)
-                        if (c->capability_bounding_set_drop & (1 << i)) {
-                                char *t;
-
-                                if ((t = cap_to_name(i))) {
-                                        fprintf(f, " %s", t);
-                                        free(t);
-                                }
-                        }
-
-                fputs("\n", f);
-        }
-
-        if (c->user)
-                fprintf(f, "%sUser: %s", prefix, c->user);
-        if (c->group)
-                fprintf(f, "%sGroup: %s", prefix, c->group);
-
-        if (strv_length(c->supplementary_groups) > 0) {
-                fprintf(f, "%sSupplementaryGroups:", prefix);
-                strv_fprintf(f, c->supplementary_groups);
-                fputs("\n", f);
-        }
-
-        if (strv_length(c->read_write_dirs) > 0) {
-                fprintf(f, "%sReadWriteDirs:", prefix);
-                strv_fprintf(f, c->read_write_dirs);
-                fputs("\n", f);
-        }
-
-        if (strv_length(c->read_only_dirs) > 0) {
-                fprintf(f, "%sReadOnlyDirs:", prefix);
-                strv_fprintf(f, c->read_only_dirs);
-                fputs("\n", f);
-        }
-
-        if (strv_length(c->inaccessible_dirs) > 0) {
-                fprintf(f, "%sInaccessibleDirs:", prefix);
-                strv_fprintf(f, c->inaccessible_dirs);
-                fputs("\n", f);
-        }
-}
-
-void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
-        assert(s);
-
-        s->pid = pid;
-        s->exit_timestamp = now(CLOCK_REALTIME);
-
-        s->code = code;
-        s->status = status;
-}
-
-void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
-        char buf[FORMAT_TIMESTAMP_MAX];
-
-        assert(s);
-        assert(f);
-
-        if (!prefix)
-                prefix = "";
-
-        if (s->pid <= 0)
-                return;
-
-        fprintf(f,
-                "%sPID: %llu\n",
-                prefix, (unsigned long long) s->pid);
-
-        if (s->start_timestamp > 0)
-                fprintf(f,
-                        "%sStart Timestamp: %s\n",
-                        prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp));
-
-        if (s->exit_timestamp > 0)
-                fprintf(f,
-                        "%sExit Timestamp: %s\n"
-                        "%sExit Code: %s\n"
-                        "%sExit Status: %i\n",
-                        prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp),
-                        prefix, sigchld_code_to_string(s->code),
-                        prefix, s->status);
-}
-
-char *exec_command_line(char **argv) {
-        size_t k;
-        char *n, *p, **a;
-        bool first = true;
-
-        assert(argv);
-
-        k = 1;
-        STRV_FOREACH(a, argv)
-                k += strlen(*a)+3;
-
-        if (!(n = new(char, k)))
-                return NULL;
-
-        p = n;
-        STRV_FOREACH(a, argv) {
-
-                if (!first)
-                        *(p++) = ' ';
-                else
-                        first = false;
-
-                if (strpbrk(*a, WHITESPACE)) {
-                        *(p++) = '\'';
-                        p = stpcpy(p, *a);
-                        *(p++) = '\'';
-                } else
-                        p = stpcpy(p, *a);
-
-        }
-
-        *p = 0;
-
-        /* FIXME: this doesn't really handle arguments that have
-         * spaces and ticks in them */
-
-        return n;
-}
-
-void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
-        char *p2;
-        const char *prefix2;
-
-        char *cmd;
-
-        assert(c);
-        assert(f);
-
-        if (!prefix)
-                prefix = "";
-        p2 = strappend(prefix, "\t");
-        prefix2 = p2 ? p2 : prefix;
-
-        cmd = exec_command_line(c->argv);
-
-        fprintf(f,
-                "%sCommand Line: %s\n",
-                prefix, cmd ? cmd : strerror(ENOMEM));
-
-        free(cmd);
-
-        exec_status_dump(&c->exec_status, f, prefix2);
-
-        free(p2);
-}
-
-void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
-        assert(f);
-
-        if (!prefix)
-                prefix = "";
-
-        LIST_FOREACH(command, c, c)
-                exec_command_dump(c, f, prefix);
-}
-
-void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
-        ExecCommand *end;
-
-        assert(l);
-        assert(e);
-
-        if (*l) {
-                /* It's kinda important that we keep the order here */
-                LIST_FIND_TAIL(ExecCommand, command, *l, end);
-                LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
-        } else
-              *l = e;
-}
-
-int exec_command_set(ExecCommand *c, const char *path, ...) {
-        va_list ap;
-        char **l, *p;
-
-        assert(c);
-        assert(path);
-
-        va_start(ap, path);
-        l = strv_new_ap(path, ap);
-        va_end(ap);
-
-        if (!l)
-                return -ENOMEM;
-
-        if (!(p = strdup(path))) {
-                strv_free(l);
-                return -ENOMEM;
-        }
-
-        free(c->path);
-        c->path = p;
-
-        strv_free(c->argv);
-        c->argv = l;
-
-        return 0;
-}
-
-const char* exit_status_to_string(ExitStatus status) {
-
-        /* We cast to int here, so that -Wenum doesn't complain that
-         * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */
-
-        switch ((int) status) {
-
-        case EXIT_SUCCESS:
-                return "SUCCESS";
-
-        case EXIT_FAILURE:
-                return "FAILURE";
-
-        case EXIT_INVALIDARGUMENT:
-                return "INVALIDARGUMENT";
-
-        case EXIT_NOTIMPLEMENTED:
-                return "NOTIMPLEMENTED";
-
-        case EXIT_NOPERMISSION:
-                return "NOPERMISSION";
-
-        case EXIT_NOTINSTALLED:
-                return "NOTINSSTALLED";
-
-        case EXIT_NOTCONFIGURED:
-                return "NOTCONFIGURED";
-
-        case EXIT_NOTRUNNING:
-                return "NOTRUNNING";
-
-        case EXIT_CHDIR:
-                return "CHDIR";
-
-        case EXIT_NICE:
-                return "NICE";
-
-        case EXIT_FDS:
-                return "FDS";
-
-        case EXIT_EXEC:
-                return "EXEC";
-
-        case EXIT_MEMORY:
-                return "MEMORY";
-
-        case EXIT_LIMITS:
-                return "LIMITS";
-
-        case EXIT_OOM_ADJUST:
-                return "OOM_ADJUST";
-
-        case EXIT_SIGNAL_MASK:
-                return "SIGNAL_MASK";
-
-        case EXIT_STDIN:
-                return "STDIN";
-
-        case EXIT_STDOUT:
-                return "STDOUT";
-
-        case EXIT_CHROOT:
-                return "CHROOT";
-
-        case EXIT_IOPRIO:
-                return "IOPRIO";
-
-        case EXIT_TIMERSLACK:
-                return "TIMERSLACK";
-
-        case EXIT_SECUREBITS:
-                return "SECUREBITS";
-
-        case EXIT_SETSCHEDULER:
-                return "SETSCHEDULER";
-
-        case EXIT_CPUAFFINITY:
-                return "CPUAFFINITY";
-
-        case EXIT_GROUP:
-                return "GROUP";
-
-        case EXIT_USER:
-                return "USER";
-
-        case EXIT_CAPABILITIES:
-                return "CAPABILITIES";
-
-        case EXIT_CGROUP:
-                return "CGROUP";
-
-        case EXIT_SETSID:
-                return "SETSID";
-
-        case EXIT_CONFIRM:
-                return "CONFIRM";
-
-        case EXIT_STDERR:
-                return "STDERR";
-
-        default:
-                return NULL;
-        }
-}
-
-static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
-        [EXEC_INPUT_NULL] = "null",
-        [EXEC_INPUT_TTY] = "tty",
-        [EXEC_INPUT_TTY_FORCE] = "tty-force",
-        [EXEC_INPUT_TTY_FAIL] = "tty-fail",
-        [EXEC_INPUT_SOCKET] = "socket"
-};
-
-static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
-        [EXEC_OUTPUT_INHERIT] = "inherit",
-        [EXEC_OUTPUT_NULL] = "null",
-        [EXEC_OUTPUT_TTY] = "tty",
-        [EXEC_OUTPUT_SYSLOG] = "syslog",
-        [EXEC_OUTPUT_KERNEL] = "kernel",
-        [EXEC_OUTPUT_SOCKET] = "socket"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
-
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
diff --git a/execute.h b/execute.h
deleted file mode 100644
index be73542..0000000
--- a/execute.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooexecutehfoo
-#define fooexecutehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct ExecStatus ExecStatus;
-typedef struct ExecCommand ExecCommand;
-typedef struct ExecContext ExecContext;
-
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/capability.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct CGroupBonding;
-
-#include "list.h"
-#include "util.h"
-
-/* Abstract namespace! */
-#define LOGGER_SOCKET "/org/freedesktop/systemd1/logger"
-
-typedef enum ExecInput {
-        EXEC_INPUT_NULL,
-        EXEC_INPUT_TTY,
-        EXEC_INPUT_TTY_FORCE,
-        EXEC_INPUT_TTY_FAIL,
-        EXEC_INPUT_SOCKET,
-        _EXEC_INPUT_MAX,
-        _EXEC_INPUT_INVALID = -1
-} ExecInput;
-
-typedef enum ExecOutput {
-        EXEC_OUTPUT_INHERIT,
-        EXEC_OUTPUT_NULL,
-        EXEC_OUTPUT_TTY,
-        EXEC_OUTPUT_SYSLOG,
-        EXEC_OUTPUT_KERNEL,
-        EXEC_OUTPUT_SOCKET,
-        _EXEC_OUTPUT_MAX,
-        _EXEC_OUTPUT_INVALID = -1
-} ExecOutput;
-
-struct ExecStatus {
-        usec_t start_timestamp;
-        usec_t exit_timestamp;
-        pid_t pid;
-        int code;     /* as in siginfo_t::si_code */
-        int status;   /* as in sigingo_t::si_status */
-};
-
-struct ExecCommand {
-        char *path;
-        char **argv;
-        ExecStatus exec_status;
-        LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
-};
-
-struct ExecContext {
-        char **environment;
-        struct rlimit *rlimit[RLIMIT_NLIMITS];
-        char *working_directory, *root_directory;
-
-        mode_t umask;
-        int oom_adjust;
-        int nice;
-        int ioprio;
-        int cpu_sched_policy;
-        int cpu_sched_priority;
-
-        cpu_set_t cpu_affinity;
-        unsigned long timer_slack_ns;
-
-        ExecInput std_input;
-        ExecOutput std_output;
-        ExecOutput std_error;
-
-        int syslog_priority;
-        char *syslog_identifier;
-        bool syslog_no_prefix;
-
-        char *tty_path;
-
-        /* Since resolving these names might might involve socket
-         * connections and we don't want to deadlock ourselves these
-         * names are resolved on execution only and in the child
-         * process. */
-        char *user;
-        char *group;
-        char **supplementary_groups;
-
-        char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
-        unsigned long mount_flags;
-
-        uint64_t capability_bounding_set_drop;
-
-        cap_t capabilities;
-        int secure_bits;
-
-        bool cpu_sched_reset_on_fork;
-        bool non_blocking;
-        bool private_tmp;
-
-        bool oom_adjust_set:1;
-        bool nice_set:1;
-        bool ioprio_set:1;
-        bool cpu_sched_set:1;
-        bool cpu_affinity_set:1;
-        bool timer_slack_ns_set:1;
-
-        /* This is not exposed to the user but available
-         * internally. We need it to make sure that whenever we spawn
-         * /bin/mount it is run in the same process group as us so
-         * that the autofs logic detects that it belongs to us and we
-         * don't enter a trigger loop. */
-        bool no_setsid:1;
-};
-
-typedef enum ExitStatus {
-        /* EXIT_SUCCESS defined by libc */
-        /* EXIT_FAILURE defined by libc */
-        EXIT_INVALIDARGUMENT = 2,
-        EXIT_NOTIMPLEMENTED = 3,
-        EXIT_NOPERMISSION = 4,
-        EXIT_NOTINSTALLED = 5,
-        EXIT_NOTCONFIGURED = 6,
-        EXIT_NOTRUNNING = 7,
-
-        /* The LSB suggests that error codes >= 200 are "reserved". We
-         * use them here under the assumption that they hence are
-         * unused by init scripts.
-         *
-         * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */
-
-        EXIT_CHDIR = 200,
-        EXIT_NICE,
-        EXIT_FDS,
-        EXIT_EXEC,
-        EXIT_MEMORY,
-        EXIT_LIMITS,
-        EXIT_OOM_ADJUST,
-        EXIT_SIGNAL_MASK,
-        EXIT_STDIN,
-        EXIT_STDOUT,
-        EXIT_CHROOT,   /* 210 */
-        EXIT_IOPRIO,
-        EXIT_TIMERSLACK,
-        EXIT_SECUREBITS,
-        EXIT_SETSCHEDULER,
-        EXIT_CPUAFFINITY,
-        EXIT_GROUP,
-        EXIT_USER,
-        EXIT_CAPABILITIES,
-        EXIT_CGROUP,
-        EXIT_SETSID,   /* 220 */
-        EXIT_CONFIRM,
-        EXIT_STDERR
-
-} ExitStatus;
-
-int exec_spawn(ExecCommand *command,
-               char **argv,
-               const ExecContext *context,
-               int fds[], unsigned n_fds,
-               char **environment,
-               bool apply_permissions,
-               bool apply_chroot,
-               bool confirm_spawn,
-               struct CGroupBonding *cgroup_bondings,
-               pid_t *ret);
-
-void exec_command_done(ExecCommand *c);
-void exec_command_done_array(ExecCommand *c, unsigned n);
-
-void exec_command_free_list(ExecCommand *c);
-void exec_command_free_array(ExecCommand **c, unsigned n);
-
-char *exec_command_line(char **argv);
-
-void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix);
-void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix);
-void exec_command_append_list(ExecCommand **l, ExecCommand *e);
-int exec_command_set(ExecCommand *c, const char *path, ...);
-
-void exec_context_init(ExecContext *c);
-void exec_context_done(ExecContext *c);
-void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
-
-void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status);
-void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
-
-const char* exec_output_to_string(ExecOutput i);
-int exec_output_from_string(const char *s);
-
-const char* exec_input_to_string(ExecInput i);
-int exec_input_from_string(const char *s);
-
-const char* exit_status_to_string(ExitStatus status);
-
-#endif
diff --git a/fdset.c b/fdset.c
deleted file mode 100644
index b6d5286..0000000
--- a/fdset.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "set.h"
-#include "util.h"
-#include "macro.h"
-#include "fdset.h"
-
-#define MAKE_SET(s) ((Set*) s)
-#define MAKE_FDSET(s) ((FDSet*) s)
-
-/* Make sure we can distuingish fd 0 and NULL */
-#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
-#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
-
-FDSet *fdset_new(void) {
-        return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func));
-}
-
-void fdset_free(FDSet *s) {
-        void *p;
-
-        while ((p = set_steal_first(MAKE_SET(s)))) {
-                /* Valgrind's fd might have ended up in this set here,
-                 * due to fdset_new_fill(). We'll ignore all failures
-                 * here, so that the EBADFD that valgrind will return
-                 * us on close() doesn't influence us */
-
-                log_warning("Closing left-over fd %i", PTR_TO_FD(p));
-                close_nointr(PTR_TO_FD(p));
-        }
-
-        set_free(MAKE_SET(s));
-}
-
-int fdset_put(FDSet *s, int fd) {
-        assert(s);
-        assert(fd >= 0);
-
-        return set_put(MAKE_SET(s), FD_TO_PTR(fd));
-}
-
-int fdset_put_dup(FDSet *s, int fd) {
-        int copy, r;
-
-        assert(s);
-        assert(fd >= 0);
-
-        if ((copy = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0)
-                return -errno;
-
-        if ((r = fdset_put(s, copy)) < 0) {
-                close_nointr_nofail(copy);
-                return r;
-        }
-
-        return copy;
-}
-
-bool fdset_contains(FDSet *s, int fd) {
-        assert(s);
-        assert(fd >= 0);
-
-        return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
-}
-
-int fdset_remove(FDSet *s, int fd) {
-        assert(s);
-        assert(fd >= 0);
-
-        return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
-}
-
-int fdset_new_fill(FDSet **_s) {
-        DIR *d;
-        struct dirent *de;
-        int r = 0;
-        FDSet *s;
-
-        assert(_s);
-
-        /* Creates an fdsets and fills in all currently open file
-         * descriptors. */
-
-        if (!(d = opendir("/proc/self/fd")))
-                return -errno;
-
-        if (!(s = fdset_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        while ((de = readdir(d))) {
-                int fd = -1;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                if ((r = safe_atoi(de->d_name, &fd)) < 0)
-                        goto finish;
-
-                if (fd < 3)
-                        continue;
-
-                if (fd == dirfd(d))
-                        continue;
-
-                if ((r = fdset_put(s, fd)) < 0)
-                        goto finish;
-        }
-
-        r = 0;
-        *_s = s;
-        s = NULL;
-
-finish:
-        closedir(d);
-
-        /* We won't close the fds here! */
-        if (s)
-                set_free(MAKE_SET(s));
-
-        return r;
-
-}
-
-int fdset_cloexec(FDSet *fds, bool b) {
-        Iterator i;
-        void *p;
-        int r;
-
-        assert(fds);
-
-        SET_FOREACH(p, MAKE_SET(fds), i)
-                if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
-                        return r;
-
-        return 0;
-}
diff --git a/fdset.h b/fdset.h
deleted file mode 100644
index 3483fc8..0000000
--- a/fdset.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foofdsethfoo
-#define foofdsethfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct FDSet FDSet;
-
-FDSet* fdset_new(void);
-void fdset_free(FDSet *s);
-
-int fdset_put(FDSet *s, int fd);
-int fdset_put_dup(FDSet *s, int fd);
-
-bool fdset_contains(FDSet *s, int fd);
-int fdset_remove(FDSet *s, int fd);
-
-int fdset_new_fill(FDSet **_s);
-
-int fdset_cloexec(FDSet *fds, bool b);
-
-#endif
diff --git a/hashmap.c b/hashmap.c
deleted file mode 100644
index 5a993b6..0000000
--- a/hashmap.c
+++ /dev/null
@@ -1,543 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "util.h"
-#include "hashmap.h"
-#include "macro.h"
-
-#define NBUCKETS 127
-
-struct hashmap_entry {
-        const void *key;
-        void *value;
-        struct hashmap_entry *bucket_next, *bucket_previous;
-        struct hashmap_entry *iterate_next, *iterate_previous;
-};
-
-struct Hashmap {
-        hash_func_t hash_func;
-        compare_func_t compare_func;
-
-        struct hashmap_entry *iterate_list_head, *iterate_list_tail;
-        unsigned n_entries;
-};
-
-#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap))))
-
-unsigned string_hash_func(const void *p) {
-        unsigned hash = 0;
-        const char *c;
-
-        for (c = p; *c; c++)
-                hash = 31 * hash + (unsigned) *c;
-
-        return hash;
-}
-
-int string_compare_func(const void *a, const void *b) {
-        return strcmp(a, b);
-}
-
-unsigned trivial_hash_func(const void *p) {
-        return PTR_TO_UINT(p);
-}
-
-int trivial_compare_func(const void *a, const void *b) {
-        return a < b ? -1 : (a > b ? 1 : 0);
-}
-
-Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) {
-        Hashmap *h;
-
-        if (!(h = malloc0(ALIGN(sizeof(Hashmap)) + NBUCKETS * ALIGN(sizeof(struct hashmap_entry*)))))
-                return NULL;
-
-        h->hash_func = hash_func ? hash_func : trivial_hash_func;
-        h->compare_func = compare_func ? compare_func : trivial_compare_func;
-
-        h->n_entries = 0;
-        h->iterate_list_head = h->iterate_list_tail = NULL;
-
-        return h;
-}
-
-int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) {
-        assert(h);
-
-        if (*h)
-                return 0;
-
-        if (!(*h = hashmap_new(hash_func, compare_func)))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
-        assert(h);
-        assert(e);
-
-        /* Insert into hash table */
-        e->bucket_next = BY_HASH(h)[hash];
-        e->bucket_previous = NULL;
-        if (BY_HASH(h)[hash])
-                BY_HASH(h)[hash]->bucket_previous = e;
-        BY_HASH(h)[hash] = e;
-
-        /* Insert into iteration list */
-        e->iterate_previous = h->iterate_list_tail;
-        e->iterate_next = NULL;
-        if (h->iterate_list_tail) {
-                assert(h->iterate_list_head);
-                h->iterate_list_tail->iterate_next = e;
-        } else {
-                assert(!h->iterate_list_head);
-                h->iterate_list_head = e;
-        }
-        h->iterate_list_tail = e;
-
-        h->n_entries++;
-        assert(h->n_entries >= 1);
-}
-
-static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
-        assert(h);
-        assert(e);
-
-        /* Remove from iteration list */
-        if (e->iterate_next)
-                e->iterate_next->iterate_previous = e->iterate_previous;
-        else
-                h->iterate_list_tail = e->iterate_previous;
-
-        if (e->iterate_previous)
-                e->iterate_previous->iterate_next = e->iterate_next;
-        else
-                h->iterate_list_head = e->iterate_next;
-
-        /* Remove from hash table bucket list */
-        if (e->bucket_next)
-                e->bucket_next->bucket_previous = e->bucket_previous;
-
-        if (e->bucket_previous)
-                e->bucket_previous->bucket_next = e->bucket_next;
-        else
-                BY_HASH(h)[hash] = e->bucket_next;
-
-        assert(h->n_entries >= 1);
-        h->n_entries--;
-}
-
-static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
-        unsigned hash;
-
-        assert(h);
-        assert(e);
-
-        hash = h->hash_func(e->key) % NBUCKETS;
-
-        unlink_entry(h, e, hash);
-        free(e);
-}
-
-void hashmap_free(Hashmap*h) {
-
-        if (!h)
-                return;
-
-        hashmap_clear(h);
-
-        free(h);
-}
-
-void hashmap_clear(Hashmap *h) {
-        if (!h)
-                return;
-
-        while (h->iterate_list_head)
-                remove_entry(h, h->iterate_list_head);
-}
-
-static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
-        struct hashmap_entry *e;
-        assert(h);
-        assert(hash < NBUCKETS);
-
-        for (e = BY_HASH(h)[hash]; e; e = e->bucket_next)
-                if (h->compare_func(e->key, key) == 0)
-                        return e;
-
-        return NULL;
-}
-
-int hashmap_put(Hashmap *h, const void *key, void *value) {
-        struct hashmap_entry *e;
-        unsigned hash;
-
-        assert(h);
-
-        hash = h->hash_func(key) % NBUCKETS;
-
-        if ((e = hash_scan(h, hash, key))) {
-
-                if (e->value == value)
-                        return 0;
-
-                return -EEXIST;
-        }
-
-        if (!(e = new(struct hashmap_entry, 1)))
-                return -ENOMEM;
-
-        e->key = key;
-        e->value = value;
-
-        link_entry(h, e, hash);
-
-        return 1;
-}
-
-int hashmap_replace(Hashmap *h, const void *key, void *value) {
-        struct hashmap_entry *e;
-        unsigned hash;
-
-        assert(h);
-
-        hash = h->hash_func(key) % NBUCKETS;
-
-        if ((e = hash_scan(h, hash, key))) {
-                e->key = key;
-                e->value = value;
-                return 0;
-        }
-
-        return hashmap_put(h, key, value);
-}
-
-void* hashmap_get(Hashmap *h, const void *key) {
-        unsigned hash;
-        struct hashmap_entry *e;
-
-        if (!h)
-                return NULL;
-
-        hash = h->hash_func(key) % NBUCKETS;
-
-        if (!(e = hash_scan(h, hash, key)))
-                return NULL;
-
-        return e->value;
-}
-
-void* hashmap_remove(Hashmap *h, const void *key) {
-        struct hashmap_entry *e;
-        unsigned hash;
-        void *data;
-
-        if (!h)
-                return NULL;
-
-        hash = h->hash_func(key) % NBUCKETS;
-
-        if (!(e = hash_scan(h, hash, key)))
-                return NULL;
-
-        data = e->value;
-        remove_entry(h, e);
-
-        return data;
-}
-
-int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
-        struct hashmap_entry *e;
-        unsigned old_hash, new_hash;
-
-        if (!h)
-                return -ENOENT;
-
-        old_hash = h->hash_func(old_key) % NBUCKETS;
-        if (!(e = hash_scan(h, old_hash, old_key)))
-                return -ENOENT;
-
-        new_hash = h->hash_func(new_key) % NBUCKETS;
-        if (hash_scan(h, new_hash, new_key))
-                return -EEXIST;
-
-        unlink_entry(h, e, old_hash);
-
-        e->key = new_key;
-        e->value = value;
-
-        link_entry(h, e, new_hash);
-
-        return 0;
-}
-
-void* hashmap_remove_value(Hashmap *h, const void *key, void *value) {
-        struct hashmap_entry *e;
-        unsigned hash;
-
-        if (!h)
-                return NULL;
-
-        hash = h->hash_func(key) % NBUCKETS;
-
-        if (!(e = hash_scan(h, hash, key)))
-                return NULL;
-
-        if (e->value != value)
-                return NULL;
-
-        remove_entry(h, e);
-
-        return value;
-}
-
-void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
-        struct hashmap_entry *e;
-
-        assert(i);
-
-        if (!h)
-                goto at_end;
-
-        if (*i == ITERATOR_LAST)
-                goto at_end;
-
-        if (*i == ITERATOR_FIRST && !h->iterate_list_head)
-                goto at_end;
-
-        e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i;
-
-        if (e->iterate_next)
-                *i = (Iterator) e->iterate_next;
-        else
-                *i = ITERATOR_LAST;
-
-        if (key)
-                *key = e->key;
-
-        return e->value;
-
-at_end:
-        *i = ITERATOR_LAST;
-
-        if (key)
-                *key = NULL;
-
-        return NULL;
-}
-
-void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) {
-        struct hashmap_entry *e;
-
-        assert(i);
-
-        if (!h)
-                goto at_beginning;
-
-        if (*i == ITERATOR_FIRST)
-                goto at_beginning;
-
-        if (*i == ITERATOR_LAST && !h->iterate_list_tail)
-                goto at_beginning;
-
-        e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i;
-
-        if (e->iterate_previous)
-                *i = (Iterator) e->iterate_previous;
-        else
-                *i = ITERATOR_FIRST;
-
-        if (key)
-                *key = e->key;
-
-        return e->value;
-
-at_beginning:
-        *i = ITERATOR_FIRST;
-
-        if (key)
-                *key = NULL;
-
-        return NULL;
-}
-
-void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) {
-        unsigned hash;
-        struct hashmap_entry *e;
-
-        if (!h)
-                return NULL;
-
-        hash = h->hash_func(key) % NBUCKETS;
-
-        if (!(e = hash_scan(h, hash, key)))
-                return NULL;
-
-        *i = (Iterator) e;
-
-        return e->value;
-}
-
-void* hashmap_first(Hashmap *h) {
-
-        if (!h)
-                return NULL;
-
-        if (!h->iterate_list_head)
-                return NULL;
-
-        return h->iterate_list_head->value;
-}
-
-void* hashmap_last(Hashmap *h) {
-
-        if (!h)
-                return NULL;
-
-        if (!h->iterate_list_tail)
-                return NULL;
-
-        return h->iterate_list_tail->value;
-}
-
-void* hashmap_steal_first(Hashmap *h) {
-        void *data;
-
-        if (!h)
-                return NULL;
-
-        if (!h->iterate_list_head)
-                return NULL;
-
-        data = h->iterate_list_head->value;
-        remove_entry(h, h->iterate_list_head);
-
-        return data;
-}
-
-unsigned hashmap_size(Hashmap *h) {
-
-        if (!h)
-                return 0;
-
-        return h->n_entries;
-}
-
-bool hashmap_isempty(Hashmap *h) {
-
-        if (!h)
-                return true;
-
-        return h->n_entries == 0;
-}
-
-int hashmap_merge(Hashmap *h, Hashmap *other) {
-        struct hashmap_entry *e;
-
-        assert(h);
-
-        if (!other)
-                return 0;
-
-        for (e = other->iterate_list_head; e; e = e->iterate_next) {
-                int r;
-
-                if ((r = hashmap_put(h, e->key, e->value)) < 0)
-                        if (r != -EEXIST)
-                                return r;
-        }
-
-        return 0;
-}
-
-void hashmap_move(Hashmap *h, Hashmap *other) {
-        struct hashmap_entry *e, *n;
-
-        assert(h);
-
-        /* The same as hashmap_merge(), but every new item from other
-         * is moved to h. This function is guaranteed to succeed. */
-
-        if (!other)
-                return;
-
-        for (e = other->iterate_list_head; e; e = n) {
-                unsigned h_hash, other_hash;
-
-                n = e->iterate_next;
-
-                h_hash = h->hash_func(e->key) % NBUCKETS;
-
-                if (hash_scan(h, h_hash, e->key))
-                        continue;
-
-                other_hash = other->hash_func(e->key) % NBUCKETS;
-
-                unlink_entry(other, e, other_hash);
-                link_entry(h, e, h_hash);
-        }
-}
-
-int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
-        unsigned h_hash, other_hash;
-        struct hashmap_entry *e;
-
-        if (!other)
-                return 0;
-
-        assert(h);
-
-        h_hash = h->hash_func(key) % NBUCKETS;
-        if (hash_scan(h, h_hash, key))
-                return -EEXIST;
-
-        other_hash = other->hash_func(key) % NBUCKETS;
-        if (!(e = hash_scan(other, other_hash, key)))
-                return -ENOENT;
-
-        unlink_entry(other, e, other_hash);
-        link_entry(h, e, h_hash);
-
-        return 0;
-}
-
-Hashmap *hashmap_copy(Hashmap *h) {
-        Hashmap *copy;
-
-        assert(h);
-
-        if (!(copy = hashmap_new(h->hash_func, h->compare_func)))
-                return NULL;
-
-        if (hashmap_merge(copy, h) < 0) {
-                hashmap_free(copy);
-                return NULL;
-        }
-
-        return copy;
-}
diff --git a/hashmap.h b/hashmap.h
deleted file mode 100644
index 3ff3efe..0000000
--- a/hashmap.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foohashmaphfoo
-#define foohashmaphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-/* Pretty straightforward hash table implementation. As a minor
- * optimization a NULL hashmap object will be treated as empty hashmap
- * for all read operations. That way it is not necessary to
- * instantiate an object for each Hashmap use. */
-
-typedef struct Hashmap Hashmap;
-typedef struct _IteratorStruct _IteratorStruct;
-typedef _IteratorStruct* Iterator;
-
-#define ITERATOR_FIRST ((Iterator) 0)
-#define ITERATOR_LAST ((Iterator) -1)
-
-typedef unsigned (*hash_func_t)(const void *p);
-typedef int (*compare_func_t)(const void *a, const void *b);
-
-unsigned string_hash_func(const void *p);
-int string_compare_func(const void *a, const void *b);
-
-unsigned trivial_hash_func(const void *p);
-int trivial_compare_func(const void *a, const void *b);
-
-Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
-void hashmap_free(Hashmap *h);
-Hashmap *hashmap_copy(Hashmap *h);
-int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
-
-int hashmap_put(Hashmap *h, const void *key, void *value);
-int hashmap_replace(Hashmap *h, const void *key, void *value);
-void* hashmap_get(Hashmap *h, const void *key);
-void* hashmap_remove(Hashmap *h, const void *key);
-void* hashmap_remove_value(Hashmap *h, const void *key, void *value);
-int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
-
-int hashmap_merge(Hashmap *h, Hashmap *other);
-void hashmap_move(Hashmap *h, Hashmap *other);
-int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key);
-
-unsigned hashmap_size(Hashmap *h);
-bool hashmap_isempty(Hashmap *h);
-
-void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key);
-void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key);
-void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i);
-
-void hashmap_clear(Hashmap *h);
-void *hashmap_steal_first(Hashmap *h);
-void* hashmap_first(Hashmap *h);
-void* hashmap_last(Hashmap *h);
-
-#define HASHMAP_FOREACH(e, h, i) \
-        for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL))
-
-#define HASHMAP_FOREACH_KEY(e, k, h, i) \
-        for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k)))
-
-#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \
-        for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL))
-
-#endif
diff --git a/hostname-setup.c b/hostname-setup.c
deleted file mode 100644
index 3b988d4..0000000
--- a/hostname-setup.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "hostname-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-
-#define LINE_MAX 4096
-
-#if defined(TARGET_FEDORA)
-#define FILENAME "/etc/sysconfig/network"
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
-#define FILENAME "/etc/HOSTNAME"
-#elif defined(TARGET_DEBIAN)
-#define FILENAME "/etc/hostname"
-#elif defined(TARGET_ARCH)
-#define FILENAME "/etc/rc.conf"
-#elif defined(TARGET_GENTOO)
-#define FILENAME "/etc/conf.d/hostname"
-#endif
-
-static char* strip_bad_chars(char *s) {
-        char *p, *d;
-
-        for (p = s, d = s; *p; p++)
-                if ((*p >= 'a' && *p <= 'z') ||
-                    (*p >= 'A' && *p <= 'Z') ||
-                    (*p >= '0' && *p <= '9') ||
-                    *p == '-' ||
-                    *p == '_')
-                        *(d++) = *p;
-
-        *d = 0;
-
-        return s;
-}
-
-static int read_hostname(char **hn) {
-
-#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO)
-        int r;
-        FILE *f;
-
-        assert(hn);
-
-        if (!(f = fopen(FILENAME, "re")))
-                return -errno;
-
-        for (;;) {
-                char line[LINE_MAX];
-                char *s, *k;
-
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                break;
-
-                        r = -errno;
-                        goto finish;
-                }
-
-                s = strstrip(line);
-
-                if (!startswith_no_case(s, "HOSTNAME="))
-                        continue;
-
-                if (!(k = strdup(s+9))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                strip_bad_chars(k);
-
-                if (k[0] == 0) {
-                        free(k);
-                        r = -ENOENT;
-                        goto finish;
-                }
-
-                *hn = k;
-                break;
-        }
-
-        r = 0;
-
-finish:
-        fclose(f);
-        return r;
-
-#elif defined(TARGET_SUSE) || defined(TARGET_DEBIAN) || defined(TARGET_SLACKWARE)
-        int r;
-        char *s, *k;
-
-        assert(hn);
-
-        if ((r = read_one_line_file(FILENAME, &s)) < 0)
-                return r;
-
-        k = strdup(strstrip(s));
-        free(s);
-
-        if (!k)
-                return -ENOMEM;
-
-        strip_bad_chars(k);
-
-        if (k[0] == 0) {
-                free(k);
-                return -ENOENT;
-        }
-
-        *hn = k;
-
-#else
-#warning "Don't know how to read the hostname"
-
-        return -ENOENT;
-#endif
-
-        return 0;
-}
-
-int hostname_setup(void) {
-        int r;
-        char *hn;
-
-        if ((r = read_hostname(&hn)) < 0) {
-                if (r != -ENOENT)
-                        log_warning("Failed to read configured hostname: %s", strerror(-r));
-
-                return r;
-        }
-
-        r = sethostname(hn, strlen(hn)) < 0 ? -errno : 0;
-
-        if (r < 0)
-                log_warning("Failed to set hostname to <%s>: %s", hn, strerror(-r));
-        else
-                log_info("Set hostname to <%s>.", hn);
-
-        free(hn);
-
-        return r;
-}
diff --git a/hostname-setup.h b/hostname-setup.h
deleted file mode 100644
index 18a406a..0000000
--- a/hostname-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foohostnamesetuphfoo
-#define foohostnamesetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int hostname_setup(void);
-
-#endif
diff --git a/initctl.c b/initctl.c
deleted file mode 100644
index 9d8ecee..0000000
--- a/initctl.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <time.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/poll.h>
-#include <sys/epoll.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#include <dbus/dbus.h>
-
-#include "util.h"
-#include "log.h"
-#include "list.h"
-#include "initreq.h"
-#include "manager.h"
-#include "sd-daemon.h"
-
-#define SERVER_FD_MAX 16
-#define TIMEOUT ((int) (10*MSEC_PER_SEC))
-
-typedef struct Fifo Fifo;
-
-typedef struct Server {
-        int epoll_fd;
-
-        LIST_HEAD(Fifo, fifos);
-        unsigned n_fifos;
-
-        DBusConnection *bus;
-} Server;
-
-struct Fifo {
-        Server *server;
-
-        int fd;
-
-        struct init_request buffer;
-        size_t bytes_read;
-
-        LIST_FIELDS(Fifo, fifo);
-};
-
-static const char *translate_runlevel(int runlevel) {
-        static const struct {
-                const int runlevel;
-                const char *special;
-        } table[] = {
-                { '0', SPECIAL_RUNLEVEL0_TARGET },
-                { '1', SPECIAL_RUNLEVEL1_TARGET },
-                { 's', SPECIAL_RUNLEVEL1_TARGET },
-                { 'S', SPECIAL_RUNLEVEL1_TARGET },
-                { '2', SPECIAL_RUNLEVEL2_TARGET },
-                { '3', SPECIAL_RUNLEVEL3_TARGET },
-                { '4', SPECIAL_RUNLEVEL4_TARGET },
-                { '5', SPECIAL_RUNLEVEL5_TARGET },
-                { '6', SPECIAL_RUNLEVEL6_TARGET },
-        };
-
-        unsigned i;
-
-        for (i = 0; i < ELEMENTSOF(table); i++)
-                if (table[i].runlevel == runlevel)
-                        return table[i].special;
-
-        return NULL;
-}
-
-static void change_runlevel(Server *s, int runlevel) {
-        const char *target;
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        const char *path, *replace = "isolate";
-
-        assert(s);
-
-        dbus_error_init(&error);
-
-        if (!(target = translate_runlevel(runlevel))) {
-                log_warning("Got request for unknown runlevel %c, ignoring.", runlevel);
-                goto finish;
-        }
-
-        log_debug("Running request %s", target);
-
-        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "LoadUnit"))) {
-                log_error("Could not allocate message.");
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &target,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not attach group information to signal message.");
-                goto finish;
-        }
-
-        if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
-                log_error("Failed to get unit path: %s", error.message);
-                goto finish;
-        }
-
-        if (!dbus_message_get_args(reply, &error,
-                                   DBUS_TYPE_OBJECT_PATH, &path,
-                                   DBUS_TYPE_INVALID)) {
-                log_error("Failed to parse unit path: %s", error.message);
-                goto finish;
-        }
-
-        dbus_message_unref(m);
-        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Unit", "Start"))) {
-                log_error("Could not allocate message.");
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &replace,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not attach group information to signal message.");
-                goto finish;
-        }
-
-        dbus_message_unref(reply);
-        if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
-                log_error("Failed to start unit: %s", error.message);
-                goto finish;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-}
-
-static void request_process(Server *s, const struct init_request *req) {
-        assert(s);
-        assert(req);
-
-        if (req->magic != INIT_MAGIC) {
-                log_error("Got initctl request with invalid magic. Ignoring.");
-                return;
-        }
-
-        switch (req->cmd) {
-
-        case INIT_CMD_RUNLVL:
-                if (!isprint(req->runlevel))
-                        log_error("Got invalid runlevel. Ignoring.");
-                else
-                        change_runlevel(s, req->runlevel);
-                return;
-
-        case INIT_CMD_POWERFAIL:
-        case INIT_CMD_POWERFAILNOW:
-        case INIT_CMD_POWEROK:
-                log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!");
-                return;
-
-        case INIT_CMD_CHANGECONS:
-                log_warning("Received console change initctl request. This is not implemented in systemd.");
-                return;
-
-        case INIT_CMD_SETENV:
-        case INIT_CMD_UNSETENV:
-                log_warning("Received environment initctl request. This is not implemented in systemd.");
-                return;
-
-        default:
-                log_warning("Received unknown initctl request. Ignoring.");
-                return;
-        }
-}
-
-static int fifo_process(Fifo *f) {
-        ssize_t l;
-
-        assert(f);
-
-        errno = EIO;
-        if ((l = read(f->fd, ((uint8_t*) &f->buffer) + f->bytes_read, sizeof(f->buffer) - f->bytes_read)) <= 0) {
-
-                if (errno == EAGAIN)
-                        return 0;
-
-                log_warning("Failed to read from fifo: %s", strerror(errno));
-                return -1;
-        }
-
-        f->bytes_read += l;
-        assert(f->bytes_read <= sizeof(f->buffer));
-
-        if (f->bytes_read == sizeof(f->buffer)) {
-                request_process(f->server, &f->buffer);
-                f->bytes_read = 0;
-        }
-
-        return 0;
-}
-
-static void fifo_free(Fifo *f) {
-        assert(f);
-
-        if (f->server) {
-                assert(f->server->n_fifos > 0);
-                f->server->n_fifos--;
-                LIST_REMOVE(Fifo, fifo, f->server->fifos, f);
-        }
-
-        if (f->fd >= 0) {
-                if (f->server)
-                        epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL);
-
-                close_nointr_nofail(f->fd);
-        }
-
-        free(f);
-}
-
-static void server_done(Server *s) {
-        assert(s);
-
-        while (s->fifos)
-                fifo_free(s->fifos);
-
-        if (s->epoll_fd >= 0)
-                close_nointr_nofail(s->epoll_fd);
-
-        if (s->bus)
-                dbus_connection_unref(s->bus);
-}
-
-static int server_init(Server *s, unsigned n_sockets) {
-        int r;
-        unsigned i;
-        DBusError error;
-
-        assert(s);
-        assert(n_sockets > 0);
-
-        dbus_error_init(&error);
-
-        zero(*s);
-
-        if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
-                r = -errno;
-                log_error("Failed to create epoll object: %s", strerror(errno));
-                goto fail;
-        }
-
-        for (i = 0; i < n_sockets; i++) {
-                struct epoll_event ev;
-                Fifo *f;
-
-                if (!(f = new0(Fifo, 1))) {
-                        r = -ENOMEM;
-                        log_error("Failed to create fifo object: %s", strerror(errno));
-                        goto fail;
-                }
-
-                f->fd = -1;
-
-                zero(ev);
-                ev.events = EPOLLIN;
-                ev.data.ptr = f;
-                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) {
-                        r = -errno;
-                        fifo_free(f);
-                        log_error("Failed to add fifo fd to epoll object: %s", strerror(errno));
-                        goto fail;
-                }
-
-                f->fd = SD_LISTEN_FDS_START+i;
-                LIST_PREPEND(Fifo, fifo, s->fifos, f);
-                f->server = s;
-                s->n_fifos ++;
-        }
-
-        if (!(s->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
-                log_error("Failed to get D-Bus connection: %s", error.message);
-                goto fail;
-        }
-
-        return 0;
-
-fail:
-        server_done(s);
-
-        dbus_error_free(&error);
-        return r;
-}
-
-static int process_event(Server *s, struct epoll_event *ev) {
-        int r;
-        Fifo *f;
-
-        assert(s);
-
-        if (!(ev->events & EPOLLIN)) {
-                log_info("Got invalid event from epoll. (3)");
-                return -EIO;
-        }
-
-        f = (Fifo*) ev->data.ptr;
-
-        if ((r = fifo_process(f)) < 0) {
-                log_info("Got error on fifo: %s", strerror(-r));
-                fifo_free(f);
-                return r;
-        }
-
-        return 0;
-}
-
-int main(int argc, char *argv[]) {
-        Server server;
-        int r = 3, n;
-
-        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
-        log_parse_environment();
-
-        log_info("systemd-initctl running as pid %llu", (unsigned long long) getpid());
-
-        if ((n = sd_listen_fds(true)) < 0) {
-                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
-                return 1;
-        }
-
-        if (n <= 0 || n > SERVER_FD_MAX) {
-                log_error("No or too many file descriptors passed.");
-                return 2;
-        }
-
-        if (server_init(&server, (unsigned) n) < 0)
-                return 2;
-
-        for (;;) {
-                struct epoll_event event;
-                int k;
-
-                if ((k = epoll_wait(server.epoll_fd,
-                                    &event, 1,
-                                    TIMEOUT)) < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        log_error("epoll_wait() failed: %s", strerror(errno));
-                        goto fail;
-                }
-
-                if (k <= 0)
-                        break;
-
-                if ((k = process_event(&server, &event)) < 0)
-                        goto fail;
-        }
-        r = 0;
-
-fail:
-        server_done(&server);
-
-        log_info("systemd-initctl stopped as pid %llu", (unsigned long long) getpid());
-
-        dbus_shutdown();
-
-        return r;
-}
diff --git a/initreq.h b/initreq.h
deleted file mode 100644
index 6f6547b..0000000
--- a/initreq.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * initreq.h	Interface to talk to init through /dev/initctl.
- *
- *		Copyright (C) 1995-2004 Miquel van Smoorenburg
- *
- *		This library 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 of the License, or (at your option) any later version.
- *
- * Version:     @(#)initreq.h  1.28  31-Mar-2004 MvS
- *
- */
-#ifndef _INITREQ_H
-#define _INITREQ_H
-
-#include <sys/param.h>
-
-#if defined(__FreeBSD_kernel__)
-#  define INIT_FIFO  "/etc/.initctl"
-#else
-#  define INIT_FIFO  "/dev/initctl"
-#endif
-
-#define INIT_MAGIC 0x03091969
-#define INIT_CMD_START		0
-#define INIT_CMD_RUNLVL		1
-#define INIT_CMD_POWERFAIL	2
-#define INIT_CMD_POWERFAILNOW	3
-#define INIT_CMD_POWEROK	4
-#define INIT_CMD_BSD		5
-#define INIT_CMD_SETENV		6
-#define INIT_CMD_UNSETENV	7
-
-#define INIT_CMD_CHANGECONS	12345
-
-#ifdef MAXHOSTNAMELEN
-#  define INITRQ_HLEN	MAXHOSTNAMELEN
-#else
-#  define INITRQ_HLEN	64
-#endif
-
-/*
- *	This is what BSD 4.4 uses when talking to init.
- *	Linux doesn't use this right now.
- */
-struct init_request_bsd {
-	char	gen_id[8];		/* Beats me.. telnetd uses "fe" */
-	char	tty_id[16];		/* Tty name minus /dev/tty      */
-	char	host[INITRQ_HLEN];	/* Hostname                     */
-	char	term_type[16];		/* Terminal type                */
-	int	signal;			/* Signal to send               */
-	int	pid;			/* Process to send to           */
-	char	exec_name[128];	        /* Program to execute           */
-	char	reserved[128];		/* For future expansion.        */
-};
-
-
-/*
- *	Because of legacy interfaces, "runlevel" and "sleeptime"
- *	aren't in a seperate struct in the union.
- *
- *	The weird sizes are because init expects the whole
- *	struct to be 384 bytes.
- */
-struct init_request {
-	int	magic;			/* Magic number                 */
-	int	cmd;			/* What kind of request         */
-	int	runlevel;		/* Runlevel to change to        */
-	int	sleeptime;		/* Time between TERM and KILL   */
-	union {
-		struct init_request_bsd	bsd;
-		char			data[368];
-	} i;
-};
-
-#endif
diff --git a/ioprio.h b/ioprio.h
deleted file mode 100644
index 9800fc2..0000000
--- a/ioprio.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef IOPRIO_H
-#define IOPRIO_H
-
-/* This is minimal version of Linux' linux/ioprio.h header file, which
- * is licensed GPL2 */
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-/*
- * Gives us 8 prio classes with 13-bits of data for each class
- */
-#define IOPRIO_BITS             (16)
-#define IOPRIO_CLASS_SHIFT      (13)
-#define IOPRIO_PRIO_MASK        ((1UL << IOPRIO_CLASS_SHIFT) - 1)
-
-#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
-#define IOPRIO_PRIO_DATA(mask)  ((mask) & IOPRIO_PRIO_MASK)
-#define IOPRIO_PRIO_VALUE(class, data)  (((class) << IOPRIO_CLASS_SHIFT) | data)
-
-#define ioprio_valid(mask)      (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE)
-
-/*
- * These are the io priority groups as implemented by CFQ. RT is the realtime
- * class, it always gets premium service. BE is the best-effort scheduling
- * class, the default for any process. IDLE is the idle scheduling class, it
- * is only served when no one else is using the disk.
- */
-enum {
-        IOPRIO_CLASS_NONE,
-        IOPRIO_CLASS_RT,
-        IOPRIO_CLASS_BE,
-        IOPRIO_CLASS_IDLE,
-};
-
-/*
- * 8 best effort priority levels are supported
- */
-#define IOPRIO_BE_NR    (8)
-
-enum {
-        IOPRIO_WHO_PROCESS = 1,
-        IOPRIO_WHO_PGRP,
-        IOPRIO_WHO_USER,
-};
-
-static inline int ioprio_set(int which, int who, int ioprio)
-{
-        return syscall(__NR_ioprio_set, which, who, ioprio);
-}
-
-static inline int ioprio_get(int which, int who)
-{
-        return syscall(__NR_ioprio_get, which, who);
-}
-
-#endif
diff --git a/job.c b/job.c
deleted file mode 100644
index 887de92..0000000
--- a/job.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <errno.h>
-
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "dbus-job.h"
-
-Job* job_new(Manager *m, JobType type, Unit *unit) {
-        Job *j;
-
-        assert(m);
-        assert(type < _JOB_TYPE_MAX);
-        assert(unit);
-
-        if (!(j = new0(Job, 1)))
-                return NULL;
-
-        j->manager = m;
-        j->id = m->current_job_id++;
-        j->type = type;
-        j->unit = unit;
-
-        /* We don't link it here, that's what job_dependency() is for */
-
-        return j;
-}
-
-void job_free(Job *j) {
-        assert(j);
-
-        /* Detach from next 'bigger' objects */
-        if (j->installed) {
-                bus_job_send_removed_signal(j);
-
-                if (j->unit->meta.job == j) {
-                        j->unit->meta.job = NULL;
-                        unit_add_to_gc_queue(j->unit);
-                }
-
-                hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
-                j->installed = false;
-        }
-
-        /* Detach from next 'smaller' objects */
-        manager_transaction_unlink_job(j->manager, j, true);
-
-        if (j->in_run_queue)
-                LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
-
-        if (j->in_dbus_queue)
-                LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
-
-        free(j);
-}
-
-JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
-        JobDependency *l;
-
-        assert(object);
-
-        /* Adds a new job link, which encodes that the 'subject' job
-         * needs the 'object' job in some way. If 'subject' is NULL
-         * this means the 'anchor' job (i.e. the one the user
-         * explcitily asked for) is the requester. */
-
-        if (!(l = new0(JobDependency, 1)))
-                return NULL;
-
-        l->subject = subject;
-        l->object = object;
-        l->matters = matters;
-
-        if (subject)
-                LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
-        else
-                LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l);
-
-        LIST_PREPEND(JobDependency, object, object->object_list, l);
-
-        return l;
-}
-
-void job_dependency_free(JobDependency *l) {
-        assert(l);
-
-        if (l->subject)
-                LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
-        else
-                LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l);
-
-        LIST_REMOVE(JobDependency, object, l->object->object_list, l);
-
-        free(l);
-}
-
-void job_dependency_delete(Job *subject, Job *object, bool *matters) {
-        JobDependency *l;
-
-        assert(object);
-
-        LIST_FOREACH(object, l, object->object_list) {
-                assert(l->object == object);
-
-                if (l->subject == subject)
-                        break;
-        }
-
-        if (!l) {
-                if (matters)
-                        *matters = false;
-                return;
-        }
-
-        if (matters)
-                *matters = l->matters;
-
-        job_dependency_free(l);
-}
-
-void job_dump(Job *j, FILE*f, const char *prefix) {
-
-
-        assert(j);
-        assert(f);
-
-        fprintf(f,
-                "%s-> Job %u:\n"
-                "%s\tAction: %s -> %s\n"
-                "%s\tState: %s\n"
-                "%s\tForced: %s\n",
-                prefix, j->id,
-                prefix, j->unit->meta.id, job_type_to_string(j->type),
-                prefix, job_state_to_string(j->state),
-                prefix, yes_no(j->override));
-}
-
-bool job_is_anchor(Job *j) {
-        JobDependency *l;
-
-        assert(j);
-
-        LIST_FOREACH(object, l, j->object_list)
-                if (!l->subject)
-                        return true;
-
-        return false;
-}
-
-static bool types_match(JobType a, JobType b, JobType c, JobType d) {
-        return
-                (a == c && b == d) ||
-                (a == d && b == c);
-}
-
-int job_type_merge(JobType *a, JobType b) {
-        if (*a == b)
-                return 0;
-
-        /* Merging is associative! a merged with b merged with c is
-         * the same as a merged with c merged with b. */
-
-        /* Mergeability is transitive! if a can be merged with b and b
-         * with c then a also with c */
-
-        /* Also, if a merged with b cannot be merged with c, then
-         * either a or b cannot be merged with c either */
-
-        if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE))
-                *a = JOB_START;
-        else if (types_match(*a, b, JOB_START, JOB_RELOAD) ||
-                 types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) ||
-                 types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) ||
-                 types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START))
-                *a = JOB_RELOAD_OR_START;
-        else if (types_match(*a, b, JOB_START, JOB_RESTART) ||
-                 types_match(*a, b, JOB_START, JOB_TRY_RESTART) ||
-                 types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD, JOB_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) ||
-                 types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART))
-                *a = JOB_RESTART;
-        else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD))
-                *a = JOB_RELOAD;
-        else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART))
-                *a = JOB_TRY_RESTART;
-        else
-                return -EEXIST;
-
-        return 0;
-}
-
-bool job_type_is_mergeable(JobType a, JobType b) {
-        return job_type_merge(&a, b) >= 0;
-}
-
-bool job_type_is_superset(JobType a, JobType b) {
-
-        /* Checks whether operation a is a "superset" of b in its
-         * actions */
-
-        if (a == b)
-                return true;
-
-        switch (a) {
-                case JOB_START:
-                        return b == JOB_VERIFY_ACTIVE;
-
-                case JOB_RELOAD:
-                        return
-                                b == JOB_VERIFY_ACTIVE;
-
-                case JOB_RELOAD_OR_START:
-                        return
-                                b == JOB_RELOAD ||
-                                b == JOB_START ||
-                                b == JOB_VERIFY_ACTIVE;
-
-                case JOB_RESTART:
-                        return
-                                b == JOB_START ||
-                                b == JOB_VERIFY_ACTIVE ||
-                                b == JOB_RELOAD ||
-                                b == JOB_RELOAD_OR_START ||
-                                b == JOB_TRY_RESTART;
-
-                case JOB_TRY_RESTART:
-                        return
-                                b == JOB_VERIFY_ACTIVE ||
-                                b == JOB_RELOAD;
-                default:
-                        return false;
-
-        }
-}
-
-bool job_type_is_conflicting(JobType a, JobType b) {
-        assert(a >= 0 && a < _JOB_TYPE_MAX);
-        assert(b >= 0 && b < _JOB_TYPE_MAX);
-
-        return (a == JOB_STOP) != (b == JOB_STOP);
-}
-
-bool job_type_is_redundant(JobType a, UnitActiveState b) {
-        switch (a) {
-
-        case JOB_START:
-                return
-                        b == UNIT_ACTIVE ||
-                        b == UNIT_ACTIVE_RELOADING;
-
-        case JOB_STOP:
-                return
-                        b == UNIT_INACTIVE;
-
-        case JOB_VERIFY_ACTIVE:
-                return
-                        b == UNIT_ACTIVE ||
-                        b == UNIT_ACTIVE_RELOADING;
-
-        case JOB_RELOAD:
-                return
-                        b == UNIT_ACTIVE_RELOADING;
-
-        case JOB_RELOAD_OR_START:
-                return
-                        b == UNIT_ACTIVATING ||
-                        b == UNIT_ACTIVE_RELOADING;
-
-        case JOB_RESTART:
-                return
-                        b == UNIT_ACTIVATING;
-
-        case JOB_TRY_RESTART:
-                return
-                        b == UNIT_ACTIVATING;
-
-        default:
-                assert_not_reached("Invalid job type");
-        }
-}
-
-bool job_is_runnable(Job *j) {
-        Iterator i;
-        Unit *other;
-
-        assert(j);
-        assert(j->installed);
-
-        /* Checks whether there is any job running for the units this
-         * job needs to be running after (in the case of a 'positive'
-         * job type) or before (in the case of a 'negative' job type
-         * . */
-
-        if (j->type == JOB_START ||
-            j->type == JOB_VERIFY_ACTIVE ||
-            j->type == JOB_RELOAD ||
-            j->type == JOB_RELOAD_OR_START) {
-
-                /* Immediate result is that the job is or might be
-                 * started. In this case lets wait for the
-                 * dependencies, regardless whether they are
-                 * starting or stopping something. */
-
-                SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i)
-                        if (other->meta.job)
-                                return false;
-        }
-
-        /* Also, if something else is being stopped and we should
-         * change state after it, then lets wait. */
-
-        SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i)
-                if (other->meta.job &&
-                    (other->meta.job->type == JOB_STOP ||
-                     other->meta.job->type == JOB_RESTART ||
-                     other->meta.job->type == JOB_TRY_RESTART))
-                        return false;
-
-        /* This means that for a service a and a service b where b
-         * shall be started after a:
-         *
-         *  start a + start b → 1st step start a, 2nd step start b
-         *  start a + stop b  → 1st step stop b,  2nd step start a
-         *  stop a  + start b → 1st step stop a,  2nd step start b
-         *  stop a  + stop b  → 1st step stop b,  2nd step stop a
-         *
-         *  This has the side effect that restarts are properly
-         *  synchronized too. */
-
-        return true;
-}
-
-int job_run_and_invalidate(Job *j) {
-        int r;
-
-        assert(j);
-        assert(j->installed);
-
-        if (j->in_run_queue) {
-                LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
-                j->in_run_queue = false;
-        }
-
-        if (j->state != JOB_WAITING)
-                return 0;
-
-        if (!job_is_runnable(j))
-                return -EAGAIN;
-
-        j->state = JOB_RUNNING;
-        job_add_to_dbus_queue(j);
-
-        switch (j->type) {
-
-                case JOB_START:
-                        r = unit_start(j->unit);
-                        if (r == -EBADR)
-                                r = 0;
-                        break;
-
-                case JOB_VERIFY_ACTIVE: {
-                        UnitActiveState t = unit_active_state(j->unit);
-                        if (UNIT_IS_ACTIVE_OR_RELOADING(t))
-                                r = -EALREADY;
-                        else if (t == UNIT_ACTIVATING)
-                                r = -EAGAIN;
-                        else
-                                r = -ENOEXEC;
-                        break;
-                }
-
-                case JOB_STOP:
-                        r = unit_stop(j->unit);
-                        break;
-
-                case JOB_RELOAD:
-                        r = unit_reload(j->unit);
-                        break;
-
-                case JOB_RELOAD_OR_START:
-                        if (unit_active_state(j->unit) == UNIT_ACTIVE)
-                                r = unit_reload(j->unit);
-                        else
-                                r = unit_start(j->unit);
-                        break;
-
-                case JOB_RESTART: {
-                        UnitActiveState t = unit_active_state(j->unit);
-                        if (t == UNIT_INACTIVE || t == UNIT_ACTIVATING) {
-                                j->type = JOB_START;
-                                r = unit_start(j->unit);
-                        } else
-                                r = unit_stop(j->unit);
-                        break;
-                }
-
-                case JOB_TRY_RESTART: {
-                        UnitActiveState t = unit_active_state(j->unit);
-                        if (t == UNIT_INACTIVE || t == UNIT_DEACTIVATING)
-                                r = -ENOEXEC;
-                        else if (t == UNIT_ACTIVATING) {
-                                j->type = JOB_START;
-                                r = unit_start(j->unit);
-                        } else
-                                r = unit_stop(j->unit);
-                        break;
-                }
-
-                default:
-                        assert_not_reached("Unknown job type");
-        }
-
-        if (r == -EALREADY)
-                r = job_finish_and_invalidate(j, true);
-        else if (r == -EAGAIN) {
-                j->state = JOB_WAITING;
-                return -EAGAIN;
-        } else if (r < 0)
-                r = job_finish_and_invalidate(j, false);
-
-        return r;
-}
-
-int job_finish_and_invalidate(Job *j, bool success) {
-        Unit *u;
-        Unit *other;
-        JobType t;
-        Iterator i;
-
-        assert(j);
-        assert(j->installed);
-
-        log_debug("Job %s/%s finished, success=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(success));
-        job_add_to_dbus_queue(j);
-
-        /* Patch restart jobs so that they become normal start jobs */
-        if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
-
-                log_debug("Converting job %s/%s -> %s/%s",
-                          j->unit->meta.id, job_type_to_string(j->type),
-                          j->unit->meta.id, job_type_to_string(JOB_START));
-
-                j->state = JOB_RUNNING;
-                j->type = JOB_START;
-
-                job_add_to_run_queue(j);
-                return 0;
-        }
-
-        u = j->unit;
-        t = j->type;
-        job_free(j);
-
-        /* Fail depending jobs on failure */
-        if (!success) {
-
-                if (t == JOB_START ||
-                    t == JOB_VERIFY_ACTIVE ||
-                    t == JOB_RELOAD_OR_START) {
-
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
-                                if (other->meta.job &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
-                                        job_finish_and_invalidate(other->meta.job, false);
-
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
-                                if (other->meta.job &&
-                                    !other->meta.job->override &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
-                                        job_finish_and_invalidate(other->meta.job, false);
-
-                } else if (t == JOB_STOP) {
-
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
-                                if (other->meta.job &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
-                                        job_finish_and_invalidate(other->meta.job, false);
-                }
-        }
-
-        /* Try to start the next jobs that can be started */
-        SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
-                if (other->meta.job)
-                        job_add_to_run_queue(other->meta.job);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i)
-                if (other->meta.job)
-                        job_add_to_run_queue(other->meta.job);
-
-        return 0;
-}
-
-void job_add_to_run_queue(Job *j) {
-        assert(j);
-        assert(j->installed);
-
-        if (j->in_run_queue)
-                return;
-
-        LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
-        j->in_run_queue = true;
-}
-
-void job_add_to_dbus_queue(Job *j) {
-        assert(j);
-        assert(j->installed);
-
-        if (j->in_dbus_queue)
-                return;
-
-        if (set_isempty(j->manager->subscribed)) {
-                j->sent_dbus_new_signal = true;
-                return;
-        }
-
-        LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
-        j->in_dbus_queue = true;
-}
-
-char *job_dbus_path(Job *j) {
-        char *p;
-
-        assert(j);
-
-        if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
-                return NULL;
-
-        return p;
-}
-
-static const char* const job_state_table[_JOB_STATE_MAX] = {
-        [JOB_WAITING] = "waiting",
-        [JOB_RUNNING] = "running"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
-
-static const char* const job_type_table[_JOB_TYPE_MAX] = {
-        [JOB_START] = "start",
-        [JOB_VERIFY_ACTIVE] = "verify-active",
-        [JOB_STOP] = "stop",
-        [JOB_RELOAD] = "reload",
-        [JOB_RELOAD_OR_START] = "reload-or-start",
-        [JOB_RESTART] = "restart",
-        [JOB_TRY_RESTART] = "try-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
-
-static const char* const job_mode_table[_JOB_MODE_MAX] = {
-        [JOB_FAIL] = "fail",
-        [JOB_REPLACE] = "replace",
-        [JOB_ISOLATE] = "isolate"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
diff --git a/job.h b/job.h
deleted file mode 100644
index 1ae97b7..0000000
--- a/job.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foojobhfoo
-#define foojobhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <inttypes.h>
-
-typedef struct Job Job;
-typedef struct JobDependency JobDependency;
-typedef enum JobType JobType;
-typedef enum JobState JobState;
-typedef enum JobMode JobMode;
-
-#include "manager.h"
-#include "unit.h"
-#include "hashmap.h"
-#include "list.h"
-
-enum JobType {
-        JOB_START,                  /* if a unit does not support being started, we'll just wait until it becomes active */
-        JOB_VERIFY_ACTIVE,
-
-        JOB_STOP,
-
-        JOB_RELOAD,                 /* if running reload */
-        JOB_RELOAD_OR_START,        /* if running reload, if not running start */
-
-        /* Note that restarts are first treated like JOB_STOP, but
-         * then instead of finishing are patched to become
-         * JOB_START. */
-        JOB_RESTART,                /* if running stop, then start unconditionally */
-        JOB_TRY_RESTART,            /* if running stop and then start */
-
-        _JOB_TYPE_MAX,
-        _JOB_TYPE_INVALID = -1
-};
-
-enum JobState {
-        JOB_WAITING,
-        JOB_RUNNING,
-        _JOB_STATE_MAX,
-        _JOB_STATE_INVALID = -1
-};
-
-enum JobMode {
-        JOB_FAIL,
-        JOB_REPLACE,
-        JOB_ISOLATE,
-        _JOB_MODE_MAX,
-        _JOB_MODE_INVALID = -1
-};
-
-struct JobDependency {
-        /* Encodes that the 'subject' job needs the 'object' job in
-         * some way. This structure is used only while building a transaction. */
-        Job *subject;
-        Job *object;
-
-        LIST_FIELDS(JobDependency, subject);
-        LIST_FIELDS(JobDependency, object);
-
-        bool matters;
-};
-
-struct Job {
-        Manager *manager;
-        Unit *unit;
-
-        LIST_FIELDS(Job, transaction);
-        LIST_FIELDS(Job, run_queue);
-        LIST_FIELDS(Job, dbus_queue);
-
-        LIST_HEAD(JobDependency, subject_list);
-        LIST_HEAD(JobDependency, object_list);
-
-        /* Used for graph algs as a "I have been here" marker */
-        Job* marker;
-        unsigned generation;
-
-        uint32_t id;
-
-        JobType type;
-        JobState state;
-
-        bool installed:1;
-        bool in_run_queue:1;
-        bool matters_to_anchor:1;
-        bool override:1;
-        bool in_dbus_queue:1;
-        bool sent_dbus_new_signal:1;
-};
-
-Job* job_new(Manager *m, JobType type, Unit *unit);
-void job_free(Job *job);
-void job_dump(Job *j, FILE*f, const char *prefix);
-
-JobDependency* job_dependency_new(Job *subject, Job *object, bool matters);
-void job_dependency_free(JobDependency *l);
-void job_dependency_delete(Job *subject, Job *object, bool *matters);
-
-bool job_is_anchor(Job *j);
-
-int job_merge(Job *j, Job *other);
-
-int job_type_merge(JobType *a, JobType b);
-bool job_type_is_mergeable(JobType a, JobType b);
-bool job_type_is_superset(JobType a, JobType b);
-bool job_type_is_conflicting(JobType a, JobType b);
-bool job_type_is_redundant(JobType a, UnitActiveState b);
-
-bool job_is_runnable(Job *j);
-
-void job_add_to_run_queue(Job *j);
-void job_add_to_dbus_queue(Job *j);
-
-int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, bool success);
-
-const char* job_type_to_string(JobType t);
-JobType job_type_from_string(const char *s);
-
-const char* job_state_to_string(JobState t);
-JobState job_state_from_string(const char *s);
-
-const char* job_mode_to_string(JobMode t);
-JobMode job_mode_from_string(const char *s);
-
-char *job_dbus_path(Job *j);
-
-#endif
diff --git a/linux/auto_dev-ioctl.h b/linux/auto_dev-ioctl.h
deleted file mode 100644
index 850f39b..0000000
--- a/linux/auto_dev-ioctl.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2008 Red Hat, Inc. All rights reserved.
- * Copyright 2008 Ian Kent <raven at themaw.net>
- *
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- */
-
-#ifndef _LINUX_AUTO_DEV_IOCTL_H
-#define _LINUX_AUTO_DEV_IOCTL_H
-
-#include <linux/auto_fs.h>
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-#else
-#include <string.h>
-#endif /* __KERNEL__ */
-
-#define AUTOFS_DEVICE_NAME		"autofs"
-
-#define AUTOFS_DEV_IOCTL_VERSION_MAJOR	1
-#define AUTOFS_DEV_IOCTL_VERSION_MINOR	0
-
-#define AUTOFS_DEVID_LEN		16
-
-#define AUTOFS_DEV_IOCTL_SIZE		sizeof(struct autofs_dev_ioctl)
-
-/*
- * An ioctl interface for autofs mount point control.
- */
-
-struct args_protover {
-	__u32	version;
-};
-
-struct args_protosubver {
-	__u32	sub_version;
-};
-
-struct args_openmount {
-	__u32	devid;
-};
-
-struct args_ready {
-	__u32	token;
-};
-
-struct args_fail {
-	__u32	token;
-	__s32	status;
-};
-
-struct args_setpipefd {
-	__s32	pipefd;
-};
-
-struct args_timeout {
-	__u64	timeout;
-};
-
-struct args_requester {
-	__u32	uid;
-	__u32	gid;
-};
-
-struct args_expire {
-	__u32	how;
-};
-
-struct args_askumount {
-	__u32	may_umount;
-};
-
-struct args_ismountpoint {
-	union {
-		struct args_in {
-			__u32	type;
-		} in;
-		struct args_out {
-			__u32	devid;
-			__u32	magic;
-		} out;
-	};
-};
-
-/*
- * All the ioctls use this structure.
- * When sending a path size must account for the total length
- * of the chunk of memory otherwise is is the size of the
- * structure.
- */
-
-struct autofs_dev_ioctl {
-	__u32 ver_major;
-	__u32 ver_minor;
-	__u32 size;		/* total size of data passed in
-				 * including this struct */
-	__s32 ioctlfd;		/* automount command fd */
-
-	/* Command parameters */
-
-	union {
-		struct args_protover		protover;
-		struct args_protosubver		protosubver;
-		struct args_openmount		openmount;
-		struct args_ready		ready;
-		struct args_fail		fail;
-		struct args_setpipefd		setpipefd;
-		struct args_timeout		timeout;
-		struct args_requester		requester;
-		struct args_expire		expire;
-		struct args_askumount		askumount;
-		struct args_ismountpoint	ismountpoint;
-	};
-
-	char path[0];
-};
-
-static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
-{
-	memset(in, 0, sizeof(struct autofs_dev_ioctl));
-	in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
-	in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
-	in->size = sizeof(struct autofs_dev_ioctl);
-	in->ioctlfd = -1;
-	return;
-}
-
-/*
- * If you change this make sure you make the corresponding change
- * to autofs-dev-ioctl.c:lookup_ioctl()
- */
-enum {
-	/* Get various version info */
-	AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71,
-	AUTOFS_DEV_IOCTL_PROTOVER_CMD,
-	AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD,
-
-	/* Open mount ioctl fd */
-	AUTOFS_DEV_IOCTL_OPENMOUNT_CMD,
-
-	/* Close mount ioctl fd */
-	AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD,
-
-	/* Mount/expire status returns */
-	AUTOFS_DEV_IOCTL_READY_CMD,
-	AUTOFS_DEV_IOCTL_FAIL_CMD,
-
-	/* Activate/deactivate autofs mount */
-	AUTOFS_DEV_IOCTL_SETPIPEFD_CMD,
-	AUTOFS_DEV_IOCTL_CATATONIC_CMD,
-
-	/* Expiry timeout */
-	AUTOFS_DEV_IOCTL_TIMEOUT_CMD,
-
-	/* Get mount last requesting uid and gid */
-	AUTOFS_DEV_IOCTL_REQUESTER_CMD,
-
-	/* Check for eligible expire candidates */
-	AUTOFS_DEV_IOCTL_EXPIRE_CMD,
-
-	/* Request busy status */
-	AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD,
-
-	/* Check if path is a mountpoint */
-	AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD,
-};
-
-#define AUTOFS_IOCTL 0x93
-
-#define AUTOFS_DEV_IOCTL_VERSION \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_PROTOVER \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_PROTOSUBVER \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_OPENMOUNT \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_READY \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_FAIL \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_SETPIPEFD \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_CATATONIC \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_TIMEOUT \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_REQUESTER \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_EXPIRE \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_ASKUMOUNT \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl)
-
-#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \
-	_IOWR(AUTOFS_IOCTL, \
-	      AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl)
-
-#endif	/* _LINUX_AUTO_DEV_IOCTL_H */
diff --git a/list.h b/list.h
deleted file mode 100644
index 012dd12..0000000
--- a/list.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foolisthfoo
-#define foolisthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/* The head of the linked list. Use this in the structure that shall
- * contain the head of the linked list */
-#define LIST_HEAD(t,name)                                               \
-        t *name
-
-/* The pointers in the linked list's items. Use this in the item structure */
-#define LIST_FIELDS(t,name)                                             \
-        t *name##_next, *name##_prev
-
-/* Initialize the list's head */
-#define LIST_HEAD_INIT(t,head)                                          \
-        do {                                                            \
-                (head) = NULL; }                                        \
-        while(false)
-
-/* Initialize a list item */
-#define LIST_INIT(t,name,item)                                          \
-        do {                                                            \
-                t *_item = (item);                                      \
-                assert(_item);                                          \
-                _item->name##_prev = _item->name##_next = NULL;         \
-        } while(false)
-
-/* Prepend an item to the list */
-#define LIST_PREPEND(t,name,head,item)                                  \
-        do {                                                            \
-                t **_head = &(head), *_item = (item);                   \
-                assert(_item);                                          \
-                if ((_item->name##_next = *_head))                      \
-                        _item->name##_next->name##_prev = _item;        \
-                _item->name##_prev = NULL;                              \
-                *_head = _item;                                         \
-        } while(false)
-
-/* Remove an item from the list */
-#define LIST_REMOVE(t,name,head,item)                                   \
-        do {                                                            \
-                t **_head = &(head), *_item = (item);                   \
-                assert(_item);                                          \
-                if (_item->name##_next)                                 \
-                        _item->name##_next->name##_prev = _item->name##_prev; \
-                if (_item->name##_prev)                                 \
-                        _item->name##_prev->name##_next = _item->name##_next; \
-                else {                                                  \
-                        assert(*_head == _item);                        \
-                        *_head = _item->name##_next;                    \
-                }                                                       \
-                _item->name##_next = _item->name##_prev = NULL;         \
-        } while(false)
-
-/* Find the head of the list */
-#define LIST_FIND_HEAD(t,name,item,head)                                \
-        do {                                                            \
-                t *_item = (item);                                      \
-                assert(_item);                                          \
-                while ((_item->name##_prev)                             \
-                       _item = _item->name##_prev;                      \
-                (head) = _item;                                         \
-        } while (false)
-
-/* Find the head of the list */
-#define LIST_FIND_TAIL(t,name,item,tail)                                \
-        do {                                                            \
-                t *_item = (item);                                      \
-                assert(_item);                                          \
-                while (_item->name##_next)                              \
-                        _item = _item->name##_next;                     \
-                (tail) = _item;                                         \
-        } while (false)
-
-/* Insert an item after another one (a = where, b = what) */
-#define LIST_INSERT_AFTER(t,name,head,a,b)                              \
-        do {                                                            \
-                t **_head = &(head), *_a = (a), *_b = (b);              \
-                assert(_b);                                             \
-                if (!_a) {                                              \
-                        if ((_b->name##_next = *_head))                 \
-                                _b->name##_next->name##_prev = _b;      \
-                        _b->name##_prev = NULL;                         \
-                        *_head = _b;                                    \
-                } else {                                                \
-                        if ((_b->name##_next = _a->name##_next))        \
-                                _b->name##_next->name##_prev = _b;      \
-                        _b->name##_prev = _a;                           \
-                        _a->name##_next = _b;                           \
-                }                                                       \
-        } while(false)
-
-#define LIST_FOREACH(name,i,head)                                       \
-        for ((i) = (head); (i); (i) = (i)->name##_next)
-
-#define LIST_FOREACH_SAFE(name,i,n,head)                                \
-        for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
-
-#endif
diff --git a/load-dropin.c b/load-dropin.c
deleted file mode 100644
index 2101e33..0000000
--- a/load-dropin.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dirent.h>
-#include <errno.h>
-
-#include "unit.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-
-static int iterate_dir(Unit *u, const char *path) {
-        DIR *d;
-        struct dirent *de;
-        int r;
-
-        if (!(d = opendir(path))) {
-
-                if (errno == ENOENT)
-                        return 0;
-
-                return -errno;
-        }
-
-        while ((de = readdir(d))) {
-                char *f;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                if (asprintf(&f, "%s/%s", path, de->d_name) < 0) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                r = unit_add_dependency_by_name(u, UNIT_WANTS, de->d_name, f, true);
-                free(f);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        closedir(d);
-        return r;
-}
-
-int unit_load_dropin(Unit *u) {
-        Iterator i;
-        int r;
-        char *t;
-
-        assert(u);
-
-        /* Load dependencies from supplementary drop-in directories */
-
-        SET_FOREACH(t, u->meta.names, i) {
-                char *path;
-                char **p;
-
-                STRV_FOREACH(p, u->meta.manager->unit_path) {
-
-                        if (asprintf(&path, "%s/%s.wants", *p, t) < 0)
-                                return -ENOMEM;
-
-                        r = iterate_dir(u, path);
-                        free(path);
-
-                        if (r < 0)
-                                return r;
-
-                        if (u->meta.instance) {
-                                char *template;
-                                /* Also try the template dir */
-
-                                if (!(template = unit_name_template(t)))
-                                        return -ENOMEM;
-
-                                r = asprintf(&path, "%s/%s.wants", *p, template);
-                                free(template);
-
-                                if (r < 0)
-                                        return -ENOMEM;
-
-                                r = iterate_dir(u, path);
-                                free(path);
-
-                                if (r < 0)
-                                        return r;
-                        }
-
-                }
-        }
-
-        return 0;
-}
diff --git a/load-dropin.h b/load-dropin.h
deleted file mode 100644
index b39580b..0000000
--- a/load-dropin.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooloaddropinhfoo
-#define fooloaddropinhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
-
-/* Read service data supplementary drop-in directories */
-
-int unit_load_dropin(Unit *u);
-
-#endif
diff --git a/load-fragment.c b/load-fragment.c
deleted file mode 100644
index 148a579..0000000
--- a/load-fragment.c
+++ /dev/null
@@ -1,1483 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <linux/oom.h>
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/prctl.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-
-#include "unit.h"
-#include "strv.h"
-#include "conf-parser.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "missing.h"
-#include "unit-name.h"
-
-#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg)                \
-        static int function(                                            \
-                        const char *filename,                           \
-                        unsigned line,                                  \
-                        const char *section,                            \
-                        const char *lvalue,                             \
-                        const char *rvalue,                             \
-                        void *data,                                     \
-                        void *userdata) {                               \
-                                                                        \
-                type *i = data, x;                                      \
-                                                                        \
-                assert(filename);                                       \
-                assert(lvalue);                                         \
-                assert(rvalue);                                         \
-                assert(data);                                           \
-                                                                        \
-                if ((x = name##_from_string(rvalue)) < 0) {             \
-                        log_error("[%s:%u] " msg ": %s", filename, line, rvalue); \
-                        return -EBADMSG;                                \
-                }                                                       \
-                                                                        \
-                *i = x;                                                 \
-                                                                        \
-                return 0;                                               \
-        }
-
-static int config_parse_deps(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        UnitDependency d = PTR_TO_UINT(data);
-        Unit *u = userdata;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                char *t, *k;
-                int r;
-
-                if (!(t = strndup(w, l)))
-                        return -ENOMEM;
-
-                k = unit_name_printf(u, t);
-                free(t);
-
-                if (!k)
-                        return -ENOMEM;
-
-                r = unit_add_dependency_by_name(u, d, k, NULL, true);
-                free(k);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int config_parse_names(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                char *t, *k;
-                int r;
-
-                if (!(t = strndup(w, l)))
-                        return -ENOMEM;
-
-                k = unit_name_printf(u, t);
-                free(t);
-
-                if (!k)
-                        return -ENOMEM;
-
-                r = unit_merge_by_name(u, k);
-                free(k);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int config_parse_description(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *k;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (!(k = unit_full_printf(u, rvalue)))
-                return -ENOMEM;
-
-        free(u->meta.description);
-
-        if (*k)
-                u->meta.description = k;
-        else {
-                free(k);
-                u->meta.description = NULL;
-        }
-
-        return 0;
-}
-
-static int config_parse_listen(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int r;
-        SocketPort *p;
-        Socket *s;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        s = (Socket*) data;
-
-        if (!(p = new0(SocketPort, 1)))
-                return -ENOMEM;
-
-        if (streq(lvalue, "ListenFIFO")) {
-                p->type = SOCKET_FIFO;
-
-                if (!(p->path = strdup(rvalue))) {
-                        free(p);
-                        return -ENOMEM;
-                }
-        } else {
-                p->type = SOCKET_SOCKET;
-
-                if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
-                        log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
-                        free(p);
-                        return r;
-                }
-
-                if (streq(lvalue, "ListenStream"))
-                        p->address.type = SOCK_STREAM;
-                else if (streq(lvalue, "ListenDatagram"))
-                        p->address.type = SOCK_DGRAM;
-                else {
-                        assert(streq(lvalue, "ListenSequentialPacket"));
-                        p->address.type = SOCK_SEQPACKET;
-                }
-
-                if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
-                        free(p);
-                        return -EPROTONOSUPPORT;
-                }
-        }
-
-        p->fd = -1;
-        LIST_PREPEND(SocketPort, port, s->ports, p);
-
-        return 0;
-}
-
-static int config_parse_socket_bind(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int r;
-        Socket *s;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        s = (Socket*) data;
-
-        if ((r = parse_boolean(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
-
-        return 0;
-}
-
-static int config_parse_nice(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int priority, r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atoi(rvalue, &priority)) < 0) {
-                log_error("[%s:%u] Failed to parse nice priority: %s", filename, line, rvalue);
-                return r;
-        }
-
-        if (priority < PRIO_MIN || priority >= PRIO_MAX) {
-                log_error("[%s:%u] Nice priority out of range: %s", filename, line, rvalue);
-                return -ERANGE;
-        }
-
-        c->nice = priority;
-        c->nice_set = false;
-
-        return 0;
-}
-
-static int config_parse_oom_adjust(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int oa, r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atoi(rvalue, &oa)) < 0) {
-                log_error("[%s:%u] Failed to parse OOM adjust value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        if (oa < OOM_DISABLE || oa > OOM_ADJUST_MAX) {
-                log_error("[%s:%u] OOM adjust value out of range: %s", filename, line, rvalue);
-                return -ERANGE;
-        }
-
-        c->oom_adjust = oa;
-        c->oom_adjust_set = true;
-
-        return 0;
-}
-
-static int config_parse_mode(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        mode_t *m = data;
-        long l;
-        char *x = NULL;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        errno = 0;
-        l = strtol(rvalue, &x, 8);
-        if (!x || *x || errno) {
-                log_error("[%s:%u] Failed to parse mode value: %s", filename, line, rvalue);
-                return errno ? -errno : -EINVAL;
-        }
-
-        if (l < 0000 || l > 07777) {
-                log_error("[%s:%u] mode value out of range: %s", filename, line, rvalue);
-                return -ERANGE;
-        }
-
-        *m = (mode_t) l;
-        return 0;
-}
-
-static int config_parse_exec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecCommand **e = data, *nce = NULL;
-        char **n;
-        char *w;
-        unsigned k;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        k = 0;
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
-
-        if (!(n = new(char*, k+1)))
-                return -ENOMEM;
-
-        k = 0;
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                if (!(n[k++] = strndup(w, l)))
-                        goto fail;
-
-        n[k] = NULL;
-
-        if (!n[0] || !path_is_absolute(n[0])) {
-                log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
-                strv_free(n);
-                return -EINVAL;
-        }
-
-        if (!(nce = new0(ExecCommand, 1)))
-                goto fail;
-
-        nce->argv = n;
-        if (!(nce->path = strdup(n[0])))
-                goto fail;
-
-        exec_command_append_list(e, nce);
-
-        return 0;
-
-fail:
-        for (; k > 0; k--)
-                free(n[k-1]);
-        free(n);
-
-        free(nce);
-
-        return -ENOMEM;
-}
-
-static int config_parse_usec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        usec_t *usec = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = parse_usec(rvalue, usec)) < 0) {
-                log_error("[%s:%u] Failed to parse time value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
-
-static int config_parse_bindtodevice(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Socket *s = data;
-        char *n;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (rvalue[0] && !streq(rvalue, "*")) {
-                if (!(n = strdup(rvalue)))
-                        return -ENOMEM;
-        } else
-                n = NULL;
-
-        free(s->bind_to_device);
-        s->bind_to_device = n;
-
-        return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
-
-static int config_parse_facility(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-
-        int *o = data, x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((x = log_facility_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse log facility: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        *o = LOG_MAKEPRI(x, LOG_PRI(*o));
-
-        return 0;
-}
-
-static int config_parse_level(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-
-        int *o = data, x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((x = log_level_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse log level: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        *o = LOG_MAKEPRI(LOG_FAC(*o), x);
-        return 0;
-}
-
-static int config_parse_io_class(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((x = ioprio_class_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse IO scheduling class: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
-        c->ioprio_set = true;
-
-        return 0;
-}
-
-static int config_parse_io_priority(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int i;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
-                log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
-        c->ioprio_set = true;
-
-        return 0;
-}
-
-static int config_parse_cpu_sched_policy(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-
-        ExecContext *c = data;
-        int x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((x = sched_policy_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse CPU scheduling policy: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        c->cpu_sched_policy = x;
-        c->cpu_sched_set = true;
-
-        return 0;
-}
-
-static int config_parse_cpu_sched_prio(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int i;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        /* On Linux RR/FIFO have the same range */
-        if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
-                log_error("[%s:%u] Failed to parse CPU scheduling priority: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        c->cpu_sched_priority = i;
-        c->cpu_sched_set = true;
-
-        return 0;
-}
-
-static int config_parse_cpu_affinity(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                char *t;
-                int r;
-                unsigned cpu;
-
-                if (!(t = strndup(w, l)))
-                        return -ENOMEM;
-
-                r = safe_atou(t, &cpu);
-                free(t);
-
-                if (r < 0 || cpu >= CPU_SETSIZE) {
-                        log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
-                        return -EBADMSG;
-                }
-
-                CPU_SET(cpu, &c->cpu_affinity);
-        }
-
-        c->cpu_affinity_set = true;
-
-        return 0;
-}
-
-static int config_parse_capabilities(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        cap_t cap;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (!(cap = cap_from_text(rvalue))) {
-                if (errno == ENOMEM)
-                        return -ENOMEM;
-
-                log_error("[%s:%u] Failed to parse capabilities: %s", filename, line, rvalue);
-                return -EBADMSG;
-        }
-
-        if (c->capabilities)
-                cap_free(c->capabilities);
-        c->capabilities = cap;
-
-        return 0;
-}
-
-static int config_parse_secure_bits(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                if (first_word(w, "keep-caps"))
-                        c->secure_bits |= SECURE_KEEP_CAPS;
-                else if (first_word(w, "keep-caps-locked"))
-                        c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
-                else if (first_word(w, "no-setuid-fixup"))
-                        c->secure_bits |= SECURE_NO_SETUID_FIXUP;
-                else if (first_word(w, "no-setuid-fixup-locked"))
-                        c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
-                else if (first_word(w, "noroot"))
-                        c->secure_bits |= SECURE_NOROOT;
-                else if (first_word(w, "noroot-locked"))
-                        c->secure_bits |= SECURE_NOROOT_LOCKED;
-                else {
-                        log_error("[%s:%u] Failed to parse secure bits: %s", filename, line, rvalue);
-                        return -EBADMSG;
-                }
-        }
-
-        return 0;
-}
-
-static int config_parse_bounding_set(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                char *t;
-                int r;
-                cap_value_t cap;
-
-                if (!(t = strndup(w, l)))
-                        return -ENOMEM;
-
-                r = cap_from_name(t, &cap);
-                free(t);
-
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to parse capability bounding set: %s", filename, line, rvalue);
-                        return -EBADMSG;
-                }
-
-                c->capability_bounding_set_drop |= 1 << cap;
-        }
-
-        return 0;
-}
-
-static int config_parse_timer_slack_ns(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        unsigned long u;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atolu(rvalue, &u)) < 0) {
-                log_error("[%s:%u] Failed to parse time slack value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        c->timer_slack_ns = u;
-
-        return 0;
-}
-
-static int config_parse_limit(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        struct rlimit **rl = data;
-        unsigned long long u;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atollu(rvalue, &u)) < 0) {
-                log_error("[%s:%u] Failed to parse resource value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        if (!*rl)
-                if (!(*rl = new(struct rlimit, 1)))
-                        return -ENOMEM;
-
-        (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
-        return 0;
-}
-
-static int config_parse_cgroup(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *w;
-        size_t l;
-        char *state;
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                char *t;
-                int r;
-
-                if (!(t = strndup(w, l)))
-                        return -ENOMEM;
-
-                r = unit_add_cgroup_from_text(u, t);
-                free(t);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int config_parse_sysv_priority(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *priority = data;
-        int r, i;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atoi(rvalue, &i)) < 0 || i < 0) {
-                log_error("[%s:%u] Failed to parse SysV start priority: %s", filename, line, rvalue);
-                return r;
-        }
-
-        *priority = (int) i;
-        return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
-
-static int config_parse_mount_flags(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        char *w;
-        size_t l;
-        char *state;
-        unsigned long flags = 0;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        FOREACH_WORD(w, l, rvalue, state) {
-                if (strncmp(w, "shared", l) == 0)
-                        flags |= MS_SHARED;
-                else if (strncmp(w, "slave", l) == 0)
-                        flags |= MS_SLAVE;
-                else if (strncmp(w, "private", l) == 0)
-                        flags |= MS_PRIVATE;
-                else {
-                        log_error("[%s:%u] Failed to parse mount flags: %s", filename, line, rvalue);
-                        return -EINVAL;
-                }
-        }
-
-        c->mount_flags = flags;
-        return 0;
-}
-
-#define FOLLOW_MAX 8
-
-static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
-        unsigned c = 0;
-        int fd, r;
-        FILE *f;
-        char *id = NULL;
-
-        assert(filename);
-        assert(*filename);
-        assert(_f);
-        assert(names);
-
-        /* This will update the filename pointer if the loaded file is
-         * reached by a symlink. The old string will be freed. */
-
-        for (;;) {
-                char *target, *k, *name;
-
-                if (c++ >= FOLLOW_MAX)
-                        return -ELOOP;
-
-                path_kill_slashes(*filename);
-
-                /* Add the file name we are currently looking at to
-                 * the names of this unit */
-                name = file_name_from_path(*filename);
-                if (!(id = set_get(names, name))) {
-
-                        if (!(id = strdup(name)))
-                                return -ENOMEM;
-
-                        if ((r = set_put(names, id)) < 0) {
-                                free(id);
-                                return r;
-                        }
-                }
-
-                /* Try to open the file name, but don't if its a symlink */
-                if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
-                        break;
-
-                if (errno != ELOOP)
-                        return -errno;
-
-                /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
-                if ((r = readlink_malloc(*filename, &target)) < 0)
-                        return r;
-
-                k = file_in_same_dir(*filename, target);
-                free(target);
-
-                if (!k)
-                        return -ENOMEM;
-
-                free(*filename);
-                *filename = k;
-        }
-
-        if (!(f = fdopen(fd, "r"))) {
-                r = -errno;
-                close_nointr_nofail(fd);
-                return r;
-        }
-
-        *_f = f;
-        *_final = id;
-        return 0;
-}
-
-static int merge_by_names(Unit **u, Set *names, const char *id) {
-        char *k;
-        int r;
-
-        assert(u);
-        assert(*u);
-        assert(names);
-
-        /* Let's try to add in all symlink names we found */
-        while ((k = set_steal_first(names))) {
-
-                /* First try to merge in the other name into our
-                 * unit */
-                if ((r = unit_merge_by_name(*u, k)) < 0) {
-                        Unit *other;
-
-                        /* Hmm, we couldn't merge the other unit into
-                         * ours? Then let's try it the other way
-                         * round */
-
-                        other = manager_get_unit((*u)->meta.manager, k);
-                        free(k);
-
-                        if (other)
-                                if ((r = unit_merge(other, *u)) >= 0) {
-                                        *u = other;
-                                        return merge_by_names(u, names, NULL);
-                                }
-
-                        return r;
-                }
-
-                if (id == k)
-                        unit_choose_id(*u, id);
-
-                free(k);
-        }
-
-        return 0;
-}
-
-static void dump_items(FILE *f, const ConfigItem *items) {
-        const ConfigItem *i;
-        const char *prev_section = NULL;
-        bool not_first = false;
-
-        struct {
-                ConfigParserCallback callback;
-                const char *rvalue;
-        } table[] = {
-                { config_parse_int,              "INTEGER" },
-                { config_parse_unsigned,         "UNSIGNED" },
-                { config_parse_size,             "SIZE" },
-                { config_parse_bool,             "BOOLEAN" },
-                { config_parse_string,           "STRING" },
-                { config_parse_path,             "PATH" },
-                { config_parse_strv,             "STRING [...]" },
-                { config_parse_nice,             "NICE" },
-                { config_parse_oom_adjust,       "OOMADJUST" },
-                { config_parse_io_class,         "IOCLASS" },
-                { config_parse_io_priority,      "IOPRIORITY" },
-                { config_parse_cpu_sched_policy, "CPUSCHEDPOLICY" },
-                { config_parse_cpu_sched_prio,   "CPUSCHEDPRIO" },
-                { config_parse_cpu_affinity,     "CPUAFFINITY" },
-                { config_parse_mode,             "MODE" },
-                { config_parse_output,           "OUTPUT" },
-                { config_parse_input,            "INPUT" },
-                { config_parse_facility,         "FACILITY" },
-                { config_parse_level,            "LEVEL" },
-                { config_parse_capabilities,     "CAPABILITIES" },
-                { config_parse_secure_bits,      "SECUREBITS" },
-                { config_parse_bounding_set,     "BOUNDINGSET" },
-                { config_parse_timer_slack_ns,   "TIMERSLACK" },
-                { config_parse_limit,            "LIMIT" },
-                { config_parse_cgroup,           "CGROUP [...]" },
-                { config_parse_deps,             "UNIT [...]" },
-                { config_parse_names,            "UNIT [...]" },
-                { config_parse_exec,             "PATH [ARGUMENT [...]]" },
-                { config_parse_service_type,     "SERVICETYPE" },
-                { config_parse_service_restart,  "SERVICERESTART" },
-                { config_parse_sysv_priority,    "SYSVPRIORITY" },
-                { config_parse_kill_mode,        "KILLMODE" },
-                { config_parse_listen,           "SOCKET [...]" },
-                { config_parse_socket_bind,      "SOCKETBIND" },
-                { config_parse_bindtodevice,     "NETWORKINTERFACE" },
-                { config_parse_usec,             "SECONDS" },
-                { config_parse_path_strv,        "PATH [...]" },
-                { config_parse_mount_flags,      "MOUNTFLAG [...]" },
-                { config_parse_description,      "DESCRIPTION" },
-        };
-
-        assert(f);
-        assert(items);
-
-        for (i = items; i->lvalue; i++) {
-                unsigned j;
-                const char *rvalue = "OTHER";
-
-                if (!streq_ptr(i->section, prev_section)) {
-                        if (!not_first)
-                                not_first = true;
-                        else
-                                fputc('\n', f);
-
-                        fprintf(f, "[%s]\n", i->section);
-                        prev_section = i->section;
-                }
-
-                for (j = 0; j < ELEMENTSOF(table); j++)
-                        if (i->parse == table[j].callback) {
-                                rvalue = table[j].rvalue;
-                                break;
-                        }
-
-                fprintf(f, "%s=%s\n", i->lvalue, rvalue);
-        }
-}
-
-static int load_from_path(Unit *u, const char *path) {
-
-        static const char* const section_table[_UNIT_TYPE_MAX] = {
-                [UNIT_SERVICE]   = "Service",
-                [UNIT_TIMER]     = "Timer",
-                [UNIT_SOCKET]    = "Socket",
-                [UNIT_TARGET]    = "Target",
-                [UNIT_DEVICE]    = "Device",
-                [UNIT_MOUNT]     = "Mount",
-                [UNIT_AUTOMOUNT] = "Automount",
-                [UNIT_SNAPSHOT]  = "Snapshot",
-                [UNIT_SWAP]      = "Swap"
-        };
-
-#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
-                { "WorkingDirectory",       config_parse_path,            &(context).working_directory,                    section   }, \
-                { "RootDirectory",          config_parse_path,            &(context).root_directory,                       section   }, \
-                { "User",                   config_parse_string,          &(context).user,                                 section   }, \
-                { "Group",                  config_parse_string,          &(context).group,                                section   }, \
-                { "SupplementaryGroups",    config_parse_strv,            &(context).supplementary_groups,                 section   }, \
-                { "Nice",                   config_parse_nice,            &(context),                                      section   }, \
-                { "OOMAdjust",              config_parse_oom_adjust,      &(context),                                      section   }, \
-                { "IOSchedulingClass",      config_parse_io_class,        &(context),                                      section   }, \
-                { "IOSchedulingPriority",   config_parse_io_priority,     &(context),                                      section   }, \
-                { "CPUSchedulingPolicy",    config_parse_cpu_sched_policy,&(context),                                      section   }, \
-                { "CPUSchedulingPriority",  config_parse_cpu_sched_prio,  &(context),                                      section   }, \
-                { "CPUSchedulingResetOnFork", config_parse_bool,          &(context).cpu_sched_reset_on_fork,              section   }, \
-                { "CPUAffinity",            config_parse_cpu_affinity,    &(context),                                      section   }, \
-                { "UMask",                  config_parse_mode,            &(context).umask,                                section   }, \
-                { "Environment",            config_parse_strv,            &(context).environment,                          section   }, \
-                { "StandardInput",          config_parse_input,           &(context).std_input,                            section   }, \
-                { "StandardOutput",         config_parse_output,          &(context).std_output,                           section   }, \
-                { "StandardError",          config_parse_output,          &(context).std_output,                           section   }, \
-                { "TTYPath",                config_parse_path,            &(context).tty_path,                             section   }, \
-                { "SyslogIdentifier",       config_parse_string,          &(context).syslog_identifier,                    section   }, \
-                { "SyslogFacility",         config_parse_facility,        &(context).syslog_priority,                      section   }, \
-                { "SyslogLevel",            config_parse_level,           &(context).syslog_priority,                      section   }, \
-                { "SyslogNoPrefix",         config_parse_bool,            &(context).syslog_no_prefix,                     section   }, \
-                { "Capabilities",           config_parse_capabilities,    &(context),                                      section   }, \
-                { "SecureBits",             config_parse_secure_bits,     &(context),                                      section   }, \
-                { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context),                                      section   }, \
-                { "TimerSlackNS",           config_parse_timer_slack_ns,  &(context),                                      section   }, \
-                { "LimitCPU",               config_parse_limit,           &(context).rlimit[RLIMIT_CPU],                   section   }, \
-                { "LimitFSIZE",             config_parse_limit,           &(context).rlimit[RLIMIT_FSIZE],                 section   }, \
-                { "LimitDATA",              config_parse_limit,           &(context).rlimit[RLIMIT_DATA],                  section   }, \
-                { "LimitSTACK",             config_parse_limit,           &(context).rlimit[RLIMIT_STACK],                 section   }, \
-                { "LimitCORE",              config_parse_limit,           &(context).rlimit[RLIMIT_CORE],                  section   }, \
-                { "LimitRSS",               config_parse_limit,           &(context).rlimit[RLIMIT_RSS],                   section   }, \
-                { "LimitNOFILE",            config_parse_limit,           &(context).rlimit[RLIMIT_NOFILE],                section   }, \
-                { "LimitAS",                config_parse_limit,           &(context).rlimit[RLIMIT_AS],                    section   }, \
-                { "LimitNPROC",             config_parse_limit,           &(context).rlimit[RLIMIT_NPROC],                 section   }, \
-                { "LimitMEMLOCK",           config_parse_limit,           &(context).rlimit[RLIMIT_MEMLOCK],               section   }, \
-                { "LimitLOCKS",             config_parse_limit,           &(context).rlimit[RLIMIT_LOCKS],                 section   }, \
-                { "LimitSIGPENDING",        config_parse_limit,           &(context).rlimit[RLIMIT_SIGPENDING],            section   }, \
-                { "LimitMSGQUEUE",          config_parse_limit,           &(context).rlimit[RLIMIT_MSGQUEUE],              section   }, \
-                { "LimitNICE",              config_parse_limit,           &(context).rlimit[RLIMIT_NICE],                  section   }, \
-                { "LimitRTPRIO",            config_parse_limit,           &(context).rlimit[RLIMIT_RTPRIO],                section   }, \
-                { "LimitRTTIME",            config_parse_limit,           &(context).rlimit[RLIMIT_RTTIME],                section   }, \
-                { "ControlGroup",           config_parse_cgroup,          u,                                               section   }, \
-                { "ReadWriteDirectories",   config_parse_path_strv,       &(context).read_write_dirs,                      section   }, \
-                { "ReadOnlyDirectories",    config_parse_path_strv,       &(context).read_only_dirs,                       section   }, \
-                { "InaccessibleDirectories",config_parse_path_strv,       &(context).inaccessible_dirs,                    section   }, \
-                { "PrivateTmp",             config_parse_bool,            &(context).private_tmp,                          section   }, \
-                { "MountFlags",             config_parse_mount_flags,     &(context),                                      section   }
-
-        const ConfigItem items[] = {
-                { "Names",                  config_parse_names,           u,                                               "Unit"    },
-                { "Description",            config_parse_description,     u,                                               "Unit"    },
-                { "Requires",               config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES),                      "Unit"    },
-                { "RequiresOverridable",    config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES_OVERRIDABLE),          "Unit"    },
-                { "Requisite",              config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE),                     "Unit"    },
-                { "RequisiteOverridable",   config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE),         "Unit"    },
-                { "Wants",                  config_parse_deps,            UINT_TO_PTR(UNIT_WANTS),                         "Unit"    },
-                { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Unit"    },
-                { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Unit"    },
-                { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Unit"    },
-                { "RecursiveStop",          config_parse_bool,            &u->meta.recursive_stop,                         "Unit"    },
-                { "StopWhenUnneeded",       config_parse_bool,            &u->meta.stop_when_unneeded,                     "Unit"    },
-
-                { "PIDFile",                config_parse_path,            &u->service.pid_file,                            "Service" },
-                { "ExecStartPre",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
-                { "ExecStart",              config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START,      "Service" },
-                { "ExecStartPost",          config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
-                { "ExecReload",             config_parse_exec,            u->service.exec_command+SERVICE_EXEC_RELOAD,     "Service" },
-                { "ExecStop",               config_parse_exec,            u->service.exec_command+SERVICE_EXEC_STOP,       "Service" },
-                { "ExecStopPost",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_STOP_POST,  "Service" },
-                { "RestartSec",             config_parse_usec,            &u->service.restart_usec,                        "Service" },
-                { "TimeoutSec",             config_parse_usec,            &u->service.timeout_usec,                        "Service" },
-                { "Type",                   config_parse_service_type,    &u->service.type,                                "Service" },
-                { "Restart",                config_parse_service_restart, &u->service.restart,                             "Service" },
-                { "PermissionsStartOnly",   config_parse_bool,            &u->service.permissions_start_only,              "Service" },
-                { "RootDirectoryStartOnly", config_parse_bool,            &u->service.root_directory_start_only,           "Service" },
-                { "ValidNoProcess",         config_parse_bool,            &u->service.valid_no_process,                    "Service" },
-                { "SysVStartPriority",      config_parse_sysv_priority,   &u->service.sysv_start_priority,                 "Service" },
-                { "KillMode",               config_parse_kill_mode,       &u->service.kill_mode,                           "Service" },
-                { "NonBlocking",            config_parse_bool,            &u->service.exec_context.non_blocking,           "Service" },
-                { "BusName",                config_parse_string,          &u->service.bus_name,                            "Service" },
-                EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
-
-                { "ListenStream",           config_parse_listen,          &u->socket,                                      "Socket"  },
-                { "ListenDatagram",         config_parse_listen,          &u->socket,                                      "Socket"  },
-                { "ListenSequentialPacket", config_parse_listen,          &u->socket,                                      "Socket"  },
-                { "ListenFIFO",             config_parse_listen,          &u->socket,                                      "Socket"  },
-                { "BindIPv6Only",           config_parse_socket_bind,     &u->socket,                                      "Socket"  },
-                { "Backlog",                config_parse_unsigned,        &u->socket.backlog,                              "Socket"  },
-                { "BindToDevice",           config_parse_bindtodevice,    &u->socket,                                      "Socket"  },
-                { "ExecStartPre",           config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_START_PRE,    "Socket"  },
-                { "ExecStartPost",          config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_START_POST,   "Socket"  },
-                { "ExecStopPre",            config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_STOP_PRE,     "Socket"  },
-                { "ExecStopPost",           config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_STOP_POST,    "Socket"  },
-                { "TimeoutSec",             config_parse_usec,            &u->socket.timeout_usec,                         "Socket"  },
-                { "DirectoryMode",          config_parse_mode,            &u->socket.directory_mode,                       "Socket"  },
-                { "SocketMode",             config_parse_mode,            &u->socket.socket_mode,                          "Socket"  },
-                { "KillMode",               config_parse_kill_mode,       &u->socket.kill_mode,                            "Socket"  },
-                { "Accept",                 config_parse_bool,            &u->socket.accept,                               "Socket"  },
-                EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
-
-                { "What",                   config_parse_string,          &u->mount.parameters_fragment.what,              "Mount"   },
-                { "Where",                  config_parse_path,            &u->mount.where,                                 "Mount"   },
-                { "Options",                config_parse_string,          &u->mount.parameters_fragment.options,           "Mount"   },
-                { "Type",                   config_parse_string,          &u->mount.parameters_fragment.fstype,            "Mount"   },
-                { "TimeoutSec",             config_parse_usec,            &u->mount.timeout_usec,                          "Mount"   },
-                { "KillMode",               config_parse_kill_mode,       &u->mount.kill_mode,                             "Mount"   },
-                EXEC_CONTEXT_CONFIG_ITEMS(u->mount.exec_context, "Mount"),
-
-                { "Where",                  config_parse_path,            &u->automount.where,                             "Automount" },
-
-                { "What",                   config_parse_path,            &u->swap.parameters_fragment.what,               "Swap" },
-                { "Priority",               config_parse_int,             &u->swap.parameters_fragment.priority,           "Swap" },
-
-                { NULL, NULL, NULL, NULL }
-        };
-
-#undef EXEC_CONTEXT_CONFIG_ITEMS
-
-        const char *sections[3];
-        char *k;
-        int r;
-        Set *symlink_names;
-        FILE *f = NULL;
-        char *filename = NULL, *id = NULL;
-        Unit *merged;
-
-        if (!u) {
-                /* Dirty dirty hack. */
-                dump_items((FILE*) path, items);
-                return 0;
-        }
-
-        assert(u);
-        assert(path);
-
-        sections[0] = "Unit";
-        sections[1] = section_table[u->meta.type];
-        sections[2] = NULL;
-
-        if (!(symlink_names = set_new(string_hash_func, string_compare_func)))
-                return -ENOMEM;
-
-        if (path_is_absolute(path)) {
-
-                if (!(filename = strdup(path))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
-                        free(filename);
-                        filename = NULL;
-
-                        if (r != -ENOENT)
-                                goto finish;
-                }
-
-        } else  {
-                char **p;
-
-                STRV_FOREACH(p, u->meta.manager->unit_path) {
-
-                        /* Instead of opening the path right away, we manually
-                         * follow all symlinks and add their name to our unit
-                         * name set while doing so */
-                        if (!(filename = path_make_absolute(path, *p))) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
-                                char *sn;
-
-                                free(filename);
-                                filename = NULL;
-
-                                if (r != -ENOENT)
-                                        goto finish;
-
-                                /* Empty the symlink names for the next run */
-                                while ((sn = set_steal_first(symlink_names)))
-                                        free(sn);
-
-                                continue;
-                        }
-
-                        break;
-                }
-        }
-
-        if (!filename) {
-                r = 0;
-                goto finish;
-        }
-
-        merged = u;
-        if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
-                goto finish;
-
-        if (merged != u) {
-                u->meta.load_state = UNIT_MERGED;
-                r = 0;
-                goto finish;
-        }
-
-        /* Now, parse the file contents */
-        if ((r = config_parse(filename, f, sections, items, u)) < 0)
-                goto finish;
-
-        free(u->meta.fragment_path);
-        u->meta.fragment_path = filename;
-        filename = NULL;
-
-        u->meta.load_state = UNIT_LOADED;
-        r = 0;
-
-finish:
-        while ((k = set_steal_first(symlink_names)))
-                free(k);
-
-        set_free(symlink_names);
-        free(filename);
-
-        if (f)
-                fclose(f);
-
-        return r;
-}
-
-int unit_load_fragment(Unit *u) {
-        int r;
-
-        assert(u);
-
-        if (u->meta.fragment_path) {
-
-                if ((r = load_from_path(u, u->meta.fragment_path)) < 0)
-                        return r;
-
-        } else {
-                Iterator i;
-                const char *t;
-
-                /* Try to find the unit under its id */
-                if ((r = load_from_path(u, u->meta.id)) < 0)
-                        return r;
-
-                /* Try to find an alias we can load this with */
-                if (u->meta.load_state == UNIT_STUB)
-                        SET_FOREACH(t, u->meta.names, i) {
-
-                                if (t == u->meta.id)
-                                        continue;
-
-                                if ((r = load_from_path(u, t)) < 0)
-                                        return r;
-
-                                if (u->meta.load_state != UNIT_STUB)
-                                        break;
-                        }
-
-                /* Now, follow the same logic, but look for a template */
-                if (u->meta.load_state == UNIT_STUB && u->meta.instance) {
-                        char *k;
-
-                        if (!(k = unit_name_template(u->meta.id)))
-                                return -ENOMEM;
-
-                        r = load_from_path(u, k);
-                        free(k);
-
-                        if (r < 0)
-                                return r;
-
-                        if (u->meta.load_state == UNIT_STUB)
-                                SET_FOREACH(t, u->meta.names, i) {
-
-                                        if (t == u->meta.id)
-                                                continue;
-
-                                        if (!(k = unit_name_template(t)))
-                                                return -ENOMEM;
-
-                                        r = load_from_path(u, k);
-                                        free(k);
-
-                                        if (r < 0)
-                                                return r;
-
-                                        if (u->meta.load_state != UNIT_STUB)
-                                                break;
-                                }
-                }
-        }
-
-        return 0;
-}
-
-void unit_dump_config_items(FILE *f) {
-        /* OK, this wins a prize for extreme ugliness. */
-
-        load_from_path(NULL, (const void*) f);
-}
diff --git a/load-fragment.h b/load-fragment.h
deleted file mode 100644
index beba87c..0000000
--- a/load-fragment.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooloadfragmenthfoo
-#define fooloadfragmenthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
-
-/* Read service data from .desktop file style configuration fragments */
-
-int unit_load_fragment(Unit *u);
-
-void unit_dump_config_items(FILE *f);
-
-#endif
diff --git a/log.c b/log.c
deleted file mode 100644
index 5d17955..0000000
--- a/log.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-
-#define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC)
-#define LOG_BUFFER_MAX 1024
-
-static LogTarget log_target = LOG_TARGET_CONSOLE;
-static int log_max_level = LOG_DEBUG;
-
-static int console_fd = STDERR_FILENO;
-static int syslog_fd = -1;
-static int kmsg_fd = -1;
-
-/* Akin to glibc's __abort_msg; which is private and we hance cannot
- * use here. */
-static char *log_abort_msg = NULL;
-
-void log_close_console(void) {
-
-        if (console_fd < 0)
-                return;
-
-        if (getpid() == 1 || console_fd != STDERR_FILENO) {
-                close_nointr_nofail(console_fd);
-                console_fd = -1;
-        }
-}
-
-static int log_open_console(void) {
-
-        if (console_fd >= 0)
-                return 0;
-
-        if (getpid() == 1) {
-
-                if ((console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
-                        log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
-                        return console_fd;
-                }
-
-                log_info("Succesfully opened /dev/console for logging.");
-        } else
-                console_fd = STDERR_FILENO;
-
-        return 0;
-}
-
-void log_close_kmsg(void) {
-
-        if (kmsg_fd < 0)
-                return;
-
-        close_nointr_nofail(kmsg_fd);
-        kmsg_fd = -1;
-}
-
-static int log_open_kmsg(void) {
-
-        if (kmsg_fd >= 0)
-                return 0;
-
-        if ((kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
-                log_info("Failed to open /dev/kmsg for logging: %s", strerror(errno));
-                return -errno;
-        }
-
-        log_info("Succesfully opened /dev/kmsg for logging.");
-
-        return 0;
-}
-
-void log_close_syslog(void) {
-
-        if (syslog_fd < 0)
-                return;
-
-        close_nointr_nofail(syslog_fd);
-        syslog_fd = -1;
-}
-
-static int log_open_syslog(void) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_un un;
-        } sa;
-        struct timeval tv;
-        int r;
-
-        if (syslog_fd >= 0)
-                return 0;
-
-        if ((syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* Make sure we don't block for more than 5s when talking to
-         * syslog */
-        timeval_store(&tv, SYSLOG_TIMEOUT_USEC);
-        if (setsockopt(syslog_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        zero(sa);
-        sa.un.sun_family = AF_UNIX;
-        strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
-
-        if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        log_info("Succesfully opened syslog for logging.");
-
-        return 0;
-
-fail:
-        log_close_syslog();
-        log_info("Failed to open syslog for logging: %s", strerror(-r));
-        return r;
-}
-
-int log_open(void) {
-        int r;
-
-        /* If we don't use the console we close it here, to not get
-         * killed by SAK. If we don't use syslog we close it here so
-         * that we are not confused by somebody deleting the socket in
-         * the fs. If we don't use /dev/kmsg we still keep it open,
-         * because there is no reason to close it. */
-
-        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-            log_target == LOG_TARGET_SYSLOG)
-                if ((r = log_open_syslog()) >= 0) {
-                        log_close_console();
-                        return r;
-                }
-
-        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-            log_target == LOG_TARGET_KMSG)
-                if ((r = log_open_kmsg()) >= 0) {
-                        log_close_syslog();
-                        log_close_console();
-                        return r;
-                }
-
-        log_close_syslog();
-        return log_open_console();
-}
-
-void log_set_target(LogTarget target) {
-        assert(target >= 0);
-        assert(target < _LOG_TARGET_MAX);
-
-        log_target = target;
-}
-
-void log_set_max_level(int level) {
-        assert((level & LOG_PRIMASK) == level);
-
-        log_max_level = level;
-}
-
-static int write_to_console(
-        int level,
-        const char*file,
-        int line,
-        const char *func,
-        const char *buffer) {
-
-        char location[64];
-        struct iovec iovec[5];
-        unsigned n = 0;
-        bool highlight;
-
-        if (console_fd < 0)
-                return 0;
-
-        snprintf(location, sizeof(location), "(%s:%u) ", file, line);
-        char_array_0(location);
-
-        highlight = LOG_PRI(level) <= LOG_ERR;
-
-        zero(iovec);
-        IOVEC_SET_STRING(iovec[n++], location);
-        if (highlight)
-                IOVEC_SET_STRING(iovec[n++], "\x1B[1;31m");
-        IOVEC_SET_STRING(iovec[n++], buffer);
-        if (highlight)
-                IOVEC_SET_STRING(iovec[n++], "\x1B[0m");
-        IOVEC_SET_STRING(iovec[n++], "\n");
-
-        if (writev(console_fd, iovec, n) < 0)
-                return -errno;
-
-        return 1;
-}
-
-static int write_to_syslog(
-        int level,
-        const char*file,
-        int line,
-        const char *func,
-        const char *buffer) {
-
-        char header_priority[16], header_time[64], header_pid[16];
-        struct iovec iovec[5];
-        struct msghdr msghdr;
-        time_t t;
-        struct tm *tm;
-
-        if (syslog_fd < 0)
-                return 0;
-
-        snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(level)));
-        char_array_0(header_priority);
-
-        t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
-        if (!(tm = localtime(&t)))
-                return -EINVAL;
-
-        if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
-                return -EINVAL;
-
-        snprintf(header_pid, sizeof(header_pid), "[%llu]: ", (unsigned long long) getpid());
-        char_array_0(header_pid);
-
-        zero(iovec);
-        IOVEC_SET_STRING(iovec[0], header_priority);
-        IOVEC_SET_STRING(iovec[1], header_time);
-        IOVEC_SET_STRING(iovec[2], __progname);
-        IOVEC_SET_STRING(iovec[3], header_pid);
-        IOVEC_SET_STRING(iovec[4], buffer);
-
-        zero(msghdr);
-        msghdr.msg_iov = iovec;
-        msghdr.msg_iovlen = ELEMENTSOF(iovec);
-
-        if (sendmsg(syslog_fd, &msghdr, 0) < 0)
-                return -errno;
-
-        return 1;
-}
-
-static int write_to_kmsg(
-        int level,
-        const char*file,
-        int line,
-        const char *func,
-        const char *buffer) {
-
-        char header_priority[16], header_pid[16];
-        struct iovec iovec[5];
-
-        if (kmsg_fd < 0)
-                return 0;
-
-        snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_PRI(level));
-        char_array_0(header_priority);
-
-        snprintf(header_pid, sizeof(header_pid), "[%llu]: ", (unsigned long long) getpid());
-        char_array_0(header_pid);
-
-        zero(iovec);
-        IOVEC_SET_STRING(iovec[0], header_priority);
-        IOVEC_SET_STRING(iovec[1], __progname);
-        IOVEC_SET_STRING(iovec[2], header_pid);
-        IOVEC_SET_STRING(iovec[3], buffer);
-        IOVEC_SET_STRING(iovec[4], "\n");
-
-        if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
-                return -errno;
-
-        return 1;
-}
-
-static int log_dispatch(
-        int level,
-        const char*file,
-        int line,
-        const char *func,
-        const char *buffer) {
-
-        int r;
-
-        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-            log_target == LOG_TARGET_SYSLOG) {
-
-                if ((r = write_to_syslog(level, file, line, func, buffer)) < 0) {
-                        log_close_syslog();
-                        log_open_kmsg();
-                } else if (r > 0)
-                        return r;
-        }
-
-        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-            log_target == LOG_TARGET_KMSG) {
-
-                if ((r = write_to_kmsg(level, file, line, func, buffer)) < 0) {
-                        log_close_kmsg();
-                        log_open_console();
-                } else if (r > 0)
-                        return r;
-        }
-
-        return write_to_console(level, file, line, func, buffer);
-}
-
-int log_meta(
-        int level,
-        const char*file,
-        int line,
-        const char *func,
-        const char *format, ...) {
-
-        char buffer[LOG_BUFFER_MAX];
-        int saved_errno, r;
-        va_list ap;
-
-        if (_likely(LOG_PRI(level) > log_max_level))
-                return 0;
-
-        saved_errno = errno;
-
-        va_start(ap, format);
-        vsnprintf(buffer, sizeof(buffer), format, ap);
-        va_end(ap);
-
-        char_array_0(buffer);
-
-        r = log_dispatch(level, file, line, func, buffer);
-        errno = saved_errno;
-
-        return r;
-}
-
-void log_assert(
-        const char*file,
-        int line,
-        const char *func,
-        const char *format, ...) {
-
-        static char buffer[LOG_BUFFER_MAX];
-        int saved_errno = errno;
-        va_list ap;
-
-        va_start(ap, format);
-        vsnprintf(buffer, sizeof(buffer), format, ap);
-        va_end(ap);
-
-        char_array_0(buffer);
-        log_abort_msg = buffer;
-
-        log_dispatch(LOG_CRIT, file, line, func, buffer);
-        abort();
-
-        /* If the user chose to ignore this SIGABRT, we are happy to go on, as if nothing happened. */
-        errno = saved_errno;
-}
-
-int log_set_target_from_string(const char *e) {
-        LogTarget t;
-
-        if ((t = log_target_from_string(e)) < 0)
-                return -EINVAL;
-
-        log_set_target(t);
-        return 0;
-}
-
-int log_set_max_level_from_string(const char *e) {
-        int t;
-
-        if ((t = log_level_from_string(e)) < 0)
-                return -EINVAL;
-
-        log_set_max_level(t);
-        return 0;
-}
-
-void log_parse_environment(void) {
-        const char *e;
-
-        if ((e = getenv("SYSTEMD_LOG_TARGET")))
-                if (log_set_target_from_string(e) < 0)
-                        log_warning("Failed to parse log target %s. Ignoring.", e);
-
-        if ((e = getenv("SYSTEMD_LOG_LEVEL")))
-                if (log_set_max_level_from_string(e) < 0)
-                        log_warning("Failed to parse log level %s. Ignoring.", e);
-}
-
-LogTarget log_get_target(void) {
-        return log_target;
-}
-
-int log_get_max_level(void) {
-        return log_max_level;
-}
-
-static const char *const log_target_table[] = {
-        [LOG_TARGET_CONSOLE] = "console",
-        [LOG_TARGET_SYSLOG] = "syslog",
-        [LOG_TARGET_KMSG] = "kmsg",
-        [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
diff --git a/log.h b/log.h
deleted file mode 100644
index 6df1d59..0000000
--- a/log.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foologhfoo
-#define foologhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <syslog.h>
-
-#include "macro.h"
-
-/* If set to SYSLOG and /dev/log can not be opened we fall back to
- * KSMG. If KMSG fails, we fall back to CONSOLE */
-typedef enum LogTarget{
-        LOG_TARGET_CONSOLE,
-        LOG_TARGET_KMSG,
-        LOG_TARGET_SYSLOG,
-        LOG_TARGET_SYSLOG_OR_KMSG,
-        _LOG_TARGET_MAX,
-        _LOG_TARGET_INVALID = -1
-}  LogTarget;
-
-void log_set_target(LogTarget target);
-void log_set_max_level(int level);
-
-int log_set_target_from_string(const char *e);
-int log_set_max_level_from_string(const char *e);
-
-LogTarget log_get_target(void);
-int log_get_max_level(void);
-
-int log_open(void);
-
-void log_close_syslog(void);
-void log_close_kmsg(void);
-void log_close_console(void);
-
-void log_parse_environment(void);
-
-int log_meta(
-        int level,
-        const char*file,
-        int line,
-        const char *func,
-        const char *format, ...) _printf_attr(5,6);
-
-_noreturn void log_assert(
-        const char*file,
-        int line,
-        const char *func,
-        const char *format, ...) _printf_attr(4,5);
-
-#define log_debug(...)   log_meta(LOG_DEBUG,   __FILE__, __LINE__, __func__, __VA_ARGS__)
-#define log_info(...)    log_meta(LOG_INFO,    __FILE__, __LINE__, __func__, __VA_ARGS__)
-#define log_notice(...)  log_meta(LOG_NOTICE,  __FILE__, __LINE__, __func__, __VA_ARGS__)
-#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__)
-#define log_error(...)   log_meta(LOG_ERR,     __FILE__, __LINE__, __func__, __VA_ARGS__)
-
-const char *log_target_to_string(LogTarget target);
-LogTarget log_target_from_string(const char *s);
-
-#endif
diff --git a/logger.c b/logger.c
deleted file mode 100644
index f81d2c5..0000000
--- a/logger.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <time.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/poll.h>
-#include <sys/epoll.h>
-#include <sys/un.h>
-#include <fcntl.h>
-
-#include "util.h"
-#include "log.h"
-#include "list.h"
-#include "sd-daemon.h"
-
-#define STREAM_BUFFER 2048
-#define STREAMS_MAX 256
-#define SERVER_FD_MAX 16
-#define TIMEOUT ((int) (10*MSEC_PER_SEC))
-
-typedef struct Stream Stream;
-
-typedef struct Server {
-        int syslog_fd;
-        int kmsg_fd;
-        int epoll_fd;
-
-        unsigned n_server_fd;
-
-        LIST_HEAD(Stream, streams);
-        unsigned n_streams;
-} Server;
-
-typedef enum StreamTarget {
-        STREAM_SYSLOG,
-        STREAM_KMSG
-} StreamTarget;
-
-typedef enum StreamState {
-        STREAM_TARGET,
-        STREAM_PRIORITY,
-        STREAM_PROCESS,
-        STREAM_PREFIX,
-        STREAM_RUNNING
-} StreamState;
-
-struct Stream {
-        Server *server;
-
-        StreamState state;
-
-        int fd;
-
-        LogTarget target;
-        int priority;
-        char *process;
-        pid_t pid;
-        uid_t uid;
-
-        bool prefix;
-
-        char buffer[STREAM_BUFFER];
-        size_t length;
-
-        LIST_FIELDS(Stream, stream);
-};
-
-static int stream_log(Stream *s, char *p, usec_t timestamp) {
-
-        char header_priority[16], header_time[64], header_pid[16];
-        struct iovec iovec[5];
-        int priority;
-
-        assert(s);
-        assert(p);
-
-        priority = s->priority;
-
-        if (s->prefix &&
-            p[0] == '<' &&
-            p[1] >= '0' && p[1] <= '7' &&
-            p[2] == '>') {
-
-                /* Detected priority prefix */
-                priority = LOG_MAKEPRI(LOG_FAC(priority), (p[1] - '0'));
-
-                p += 3;
-        }
-
-        if (*p == 0)
-                return 0;
-
-        /*
-         * The format glibc uses to talk to the syslog daemon is:
-         *
-         *     <priority>time process[pid]: msg
-         *
-         * The format the kernel uses is:
-         *
-         *     <priority>msg\n
-         *
-         *  We extend the latter to include the process name and pid.
-         */
-
-        snprintf(header_priority, sizeof(header_priority), "<%i>",
-                 s->target == STREAM_SYSLOG ? priority : LOG_PRI(priority));
-        char_array_0(header_priority);
-
-        if (s->target == STREAM_SYSLOG) {
-                time_t t;
-                struct tm *tm;
-
-                t = (time_t) (timestamp / USEC_PER_SEC);
-                if (!(tm = localtime(&t)))
-                        return -EINVAL;
-
-                if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
-                        return -EINVAL;
-        }
-
-        snprintf(header_pid, sizeof(header_pid), "[%llu]: ", (unsigned long long) s->pid);
-        char_array_0(header_pid);
-
-        zero(iovec);
-        IOVEC_SET_STRING(iovec[0], header_priority);
-
-        if (s->target == STREAM_SYSLOG) {
-                struct msghdr msghdr;
-
-                IOVEC_SET_STRING(iovec[1], header_time);
-                IOVEC_SET_STRING(iovec[2], s->process);
-                IOVEC_SET_STRING(iovec[3], header_pid);
-                IOVEC_SET_STRING(iovec[4], p);
-
-                zero(msghdr);
-                msghdr.msg_iov = iovec;
-                msghdr.msg_iovlen = ELEMENTSOF(iovec);
-
-                if (sendmsg(s->server->syslog_fd, &msghdr, MSG_NOSIGNAL) < 0)
-                        return -errno;
-
-        } else if (s->target == STREAM_KMSG) {
-                IOVEC_SET_STRING(iovec[1], s->process);
-                IOVEC_SET_STRING(iovec[2], header_pid);
-                IOVEC_SET_STRING(iovec[3], p);
-                IOVEC_SET_STRING(iovec[4], (char*) "\n");
-
-                if (writev(s->server->kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
-                        return -errno;
-        } else
-                assert_not_reached("Unknown log target");
-
-        return 0;
-}
-
-static int stream_line(Stream *s, char *p, usec_t timestamp) {
-        int r;
-
-        assert(s);
-        assert(p);
-
-        p = strstrip(p);
-
-        switch (s->state) {
-
-        case STREAM_TARGET:
-                if (streq(p, "syslog"))
-                        s->target = STREAM_SYSLOG;
-                else if (streq(p, "kmsg")) {
-
-                        if (s->server->kmsg_fd >= 0 && s->uid == 0)
-                                s->target = STREAM_KMSG;
-                        else {
-                                log_warning("/dev/kmsg logging not available.");
-                                return -EPERM;
-                        }
-                } else {
-                        log_warning("Failed to parse log target line.");
-                        return -EBADMSG;
-                }
-                s->state = STREAM_PRIORITY;
-                return 0;
-
-        case STREAM_PRIORITY:
-                if ((r = safe_atoi(p, &s->priority)) < 0) {
-                        log_warning("Failed to parse log priority line: %s", strerror(errno));
-                        return r;
-                }
-
-                if (s->priority < 0) {
-                        log_warning("Log priority negative: %s", strerror(errno));
-                        return -ERANGE;
-                }
-
-                s->state = STREAM_PROCESS;
-                return 0;
-
-        case STREAM_PROCESS:
-                if (!(s->process = strdup(p)))
-                        return -ENOMEM;
-
-                s->state = STREAM_PREFIX;
-                return 0;
-
-        case STREAM_PREFIX:
-
-                if ((r = parse_boolean(p)) < 0)
-                        return r;
-
-                s->prefix = r;
-                s->state = STREAM_RUNNING;
-                return 0;
-
-        case STREAM_RUNNING:
-                return stream_log(s, p, timestamp);
-        }
-
-        assert_not_reached("Unknown stream state");
-}
-
-static int stream_scan(Stream *s, usec_t timestamp) {
-        char *p;
-        size_t remaining;
-        int r = 0;
-
-        assert(s);
-
-        p = s->buffer;
-        remaining = s->length;
-        for (;;) {
-                char *newline;
-
-                if (!(newline = memchr(p, '\n', remaining)))
-                        break;
-
-                *newline = 0;
-
-                if ((r = stream_line(s, p, timestamp)) >= 0) {
-                        remaining -= newline-p+1;
-                        p = newline+1;
-                }
-        }
-
-        if (p > s->buffer) {
-                memmove(s->buffer, p, remaining);
-                s->length = remaining;
-        }
-
-        return r;
-}
-
-static int stream_process(Stream *s, usec_t timestamp) {
-        ssize_t l;
-        int r;
-        assert(s);
-
-        if ((l = read(s->fd, s->buffer+s->length, STREAM_BUFFER-s->length)) < 0) {
-
-                if (errno == EAGAIN)
-                        return 0;
-
-                log_warning("Failed to read from stream: %s", strerror(errno));
-                return -1;
-        }
-
-
-        if (l == 0)
-                return 0;
-
-        s->length += l;
-        r = stream_scan(s, timestamp);
-
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static void stream_free(Stream *s) {
-        assert(s);
-
-        if (s->server) {
-                assert(s->server->n_streams > 0);
-                s->server->n_streams--;
-                LIST_REMOVE(Stream, stream, s->server->streams, s);
-
-        }
-
-        if (s->fd >= 0) {
-                if (s->server)
-                        epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
-
-                close_nointr_nofail(s->fd);
-        }
-
-        free(s->process);
-        free(s);
-}
-
-static int stream_new(Server *s, int server_fd) {
-        Stream *stream;
-        int fd;
-        struct ucred ucred;
-        socklen_t len = sizeof(ucred);
-        struct epoll_event ev;
-        int r;
-
-        assert(s);
-
-        if ((fd = accept4(server_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC)) < 0)
-                return -errno;
-
-        if (s->n_streams >= STREAMS_MAX) {
-                log_warning("Too many connections, refusing connection.");
-                close_nointr_nofail(fd);
-                return 0;
-        }
-
-        if (!(stream = new0(Stream, 1))) {
-                close_nointr_nofail(fd);
-                return -ENOMEM;
-        }
-
-        stream->fd = fd;
-
-        if (getsockopt(stream->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if (shutdown(fd, SHUT_WR) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        zero(ev);
-        ev.data.ptr = stream;
-        ev.events = EPOLLIN;
-        if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        stream->pid = ucred.pid;
-        stream->uid = ucred.uid;
-
-        stream->server = s;
-        LIST_PREPEND(Stream, stream, s->streams, stream);
-        s->n_streams ++;
-
-        return 0;
-
-fail:
-        stream_free(stream);
-        return r;
-}
-
-static void server_done(Server *s) {
-        unsigned i;
-        assert(s);
-
-        while (s->streams)
-                stream_free(s->streams);
-
-        for (i = 0; i < s->n_server_fd; i++)
-                close_nointr_nofail(SD_LISTEN_FDS_START+i);
-
-        if (s->syslog_fd >= 0)
-                close_nointr_nofail(s->syslog_fd);
-
-        if (s->epoll_fd >= 0)
-                close_nointr_nofail(s->epoll_fd);
-
-        if (s->kmsg_fd >= 0)
-                close_nointr_nofail(s->kmsg_fd);
-}
-
-static int server_init(Server *s, unsigned n_sockets) {
-        int r;
-        unsigned i;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_un un;
-        } sa;
-
-        assert(s);
-        assert(n_sockets > 0);
-
-        zero(*s);
-
-        s->n_server_fd = n_sockets;
-        s->syslog_fd = -1;
-        s->kmsg_fd = -1;
-
-        if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
-                r = -errno;
-                log_error("Failed to create epoll object: %s", strerror(errno));
-                goto fail;
-        }
-
-        for (i = 0; i < n_sockets; i++) {
-                struct epoll_event ev;
-
-                zero(ev);
-                ev.events = EPOLLIN;
-                ev.data.ptr = UINT_TO_PTR(SD_LISTEN_FDS_START+i);
-                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) {
-                        r = -errno;
-                        log_error("Failed to add server fd to epoll object: %s", strerror(errno));
-                        goto fail;
-                }
-        }
-
-        if ((s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
-                r = -errno;
-                log_error("Failed to create log fd: %s", strerror(errno));
-                goto fail;
-        }
-
-        zero(sa);
-        sa.un.sun_family = AF_UNIX;
-        strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
-
-        if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) {
-                r = -errno;
-                log_error("Failed to connect log socket to /dev/log: %s", strerror(errno));
-                goto fail;
-        }
-
-        /* /dev/kmsg logging is strictly optional */
-        if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
-                log_debug("Failed to open /dev/kmsg for logging, disabling kernel log buffer support: %s", strerror(errno));
-
-        return 0;
-
-fail:
-        server_done(s);
-        return r;
-}
-
-static int process_event(Server *s, struct epoll_event *ev) {
-        int r;
-
-        assert(s);
-
-        /* Yes, this is a bit ugly, we assume that that valid pointers
-         * are > SD_LISTEN_FDS_START+SERVER_FD_MAX. Which is certainly
-         * true on Linux (and probably most other OSes, too, since the
-         * first 4k usually are part of a seperate null pointer
-         * dereference page. */
-
-        if (PTR_TO_UINT(ev->data.ptr) >= SD_LISTEN_FDS_START &&
-            PTR_TO_UINT(ev->data.ptr) < SD_LISTEN_FDS_START+s->n_server_fd) {
-
-                if (ev->events != EPOLLIN) {
-                        log_info("Got invalid event from epoll. (1)");
-                        return -EIO;
-                }
-
-                if ((r = stream_new(s, PTR_TO_UINT(ev->data.ptr))) < 0) {
-                        log_info("Failed to accept new connection: %s", strerror(-r));
-                        return r;
-                }
-
-        } else {
-                usec_t timestamp;
-                Stream *stream = ev->data.ptr;
-
-                timestamp = now(CLOCK_REALTIME);
-
-                if (!(ev->events & EPOLLIN)) {
-                        log_info("Got invalid event from epoll. (2)");
-                        stream_free(stream);
-                        return 0;
-                }
-
-                if ((r = stream_process(stream, timestamp)) <= 0) {
-
-                        if (r < 0)
-                                log_info("Got error on stream: %s", strerror(-r));
-
-                        stream_free(stream);
-                        return 0;
-                }
-        }
-
-        return 0;
-}
-
-int main(int argc, char *argv[]) {
-        Server server;
-        int r = 3, n;
-
-        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
-        log_parse_environment();
-
-        log_info("systemd-logger running as pid %llu", (unsigned long long) getpid());
-
-        if ((n = sd_listen_fds(true)) < 0) {
-                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
-                return 1;
-        }
-
-        if (n <= 0 || n > SERVER_FD_MAX) {
-                log_error("No or too many file descriptors passed.");
-                return 2;
-        }
-
-        if (server_init(&server, (unsigned) n) < 0)
-                return 3;
-
-        for (;;) {
-                struct epoll_event event;
-                int k;
-
-                if ((k = epoll_wait(server.epoll_fd,
-                                    &event, 1,
-                                    server.n_streams <= 0 ? TIMEOUT : -1)) < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        log_error("epoll_wait() failed: %s", strerror(errno));
-                        goto fail;
-                }
-
-                if (k <= 0)
-                        break;
-
-                if ((k = process_event(&server, &event)) < 0)
-                        goto fail;
-        }
-        r = 0;
-
-fail:
-        server_done(&server);
-
-        log_info("systemd-logger stopped as pid %llu", (unsigned long long) getpid());
-
-        return r;
-}
diff --git a/loopback-setup.c b/loopback-setup.c
deleted file mode 100644
index e37bf41..0000000
--- a/loopback-setup.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <asm/types.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#include "util.h"
-#include "macro.h"
-#include "loopback-setup.h"
-
-enum {
-        REQUEST_NONE = 0,
-        REQUEST_ADDRESS_IPV4 = 1,
-        REQUEST_ADDRESS_IPV6 = 2,
-        REQUEST_FLAGS = 4,
-        REQUEST_ALL = 7
-};
-
-#define NLMSG_TAIL(nmsg)                                                \
-        ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
-
-static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) {
-        size_t length;
-        struct rtattr *rta;
-
-        length = RTA_LENGTH(data_length);
-
-        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
-                return -E2BIG;
-
-        rta = NLMSG_TAIL(n);
-        rta->rta_type = type;
-        rta->rta_len = length;
-        memcpy(RTA_DATA(rta), data, data_length);
-        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
-
-        return 0;
-}
-
-static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) {
-
-        for (;;) {
-                ssize_t l;
-
-                if ((l = sendto(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
-                        return l;
-
-                if (errno != EINTR)
-                        return -errno;
-        }
-}
-
-static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) {
-
-        for (;;) {
-                ssize_t l;
-
-                if ((l = recvfrom(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
-                        return l;
-
-                if (errno != EINTR)
-                        return -errno;
-        }
-}
-
-static int add_adresses(int fd, int if_loopback) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sa;
-        union {
-                struct nlmsghdr header;
-                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
-                            NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
-                            RTA_LENGTH(sizeof(struct in6_addr))];
-        } request;
-
-        struct ifaddrmsg *ifaddrmsg;
-        uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
-        int r;
-
-        zero(request);
-
-        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-        request.header.nlmsg_type = RTM_NEWADDR;
-        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
-        request.header.nlmsg_seq = REQUEST_ADDRESS_IPV4;
-
-        ifaddrmsg = NLMSG_DATA(&request.header);
-        ifaddrmsg->ifa_family = AF_INET;
-        ifaddrmsg->ifa_prefixlen = 8;
-        ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
-        ifaddrmsg->ifa_scope = RT_SCOPE_HOST;
-        ifaddrmsg->ifa_index = if_loopback;
-
-        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address))) < 0)
-                return r;
-
-        zero(sa);
-        sa.nl.nl_family = AF_NETLINK;
-
-        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
-                return -errno;
-
-        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-        request.header.nlmsg_seq = REQUEST_ADDRESS_IPV6;
-
-        ifaddrmsg->ifa_family = AF_INET6;
-        ifaddrmsg->ifa_prefixlen = 128;
-
-        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback))) < 0)
-                return r;
-
-        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int start_interface(int fd, int if_loopback) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sa;
-        union {
-                struct nlmsghdr header;
-                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
-                            NLMSG_ALIGN(sizeof(struct ifinfomsg))];
-        } request;
-
-        struct ifinfomsg *ifinfomsg;
-
-        zero(request);
-
-        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-        request.header.nlmsg_type = RTM_NEWLINK;
-        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
-        request.header.nlmsg_seq = REQUEST_FLAGS;
-
-        ifinfomsg = NLMSG_DATA(&request.header);
-        ifinfomsg->ifi_family = AF_UNSPEC;
-        ifinfomsg->ifi_index = if_loopback;
-        ifinfomsg->ifi_flags = IFF_UP;
-        ifinfomsg->ifi_change = IFF_UP;
-
-        zero(sa);
-        sa.nl.nl_family = AF_NETLINK;
-
-        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int read_response(int fd) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sa;
-        union {
-                struct nlmsghdr header;
-                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
-                            NLMSG_ALIGN(sizeof(struct nlmsgerr))];
-        } response;
-
-        ssize_t l;
-        socklen_t sa_len = sizeof(sa);
-        struct nlmsgerr *nlmsgerr;
-
-        if ((l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len)) < 0)
-                return -errno;
-
-        if (sa_len != sizeof(sa.nl) ||
-            sa.nl.nl_family != AF_NETLINK)
-                return -EIO;
-
-        if (sa.nl.nl_pid != 0)
-                return 0;
-
-        if ((size_t) l < sizeof(struct nlmsghdr))
-                return -EIO;
-
-        if (response.header.nlmsg_type != NLMSG_ERROR ||
-            (pid_t) response.header.nlmsg_pid != getpid() ||
-            response.header.nlmsg_seq >= REQUEST_ALL)
-                return 0;
-
-        if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
-            response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
-                return -EIO;
-
-        nlmsgerr = NLMSG_DATA(&response.header);
-
-        if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST)
-                return nlmsgerr->error;
-
-        return response.header.nlmsg_seq;
-}
-
-int loopback_setup(void) {
-        int r, if_loopback;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-                struct sockaddr_storage storage;
-        } sa;
-        int requests = REQUEST_NONE;
-
-        int fd;
-
-        errno = 0;
-        if ((if_loopback = (int) if_nametoindex("lo")) <= 0)
-                return errno ? -errno : -ENODEV;
-
-        if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
-                return -errno;
-
-        zero(sa);
-        sa.nl.nl_family = AF_NETLINK;
-
-        if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if ((r = add_adresses(fd, if_loopback)) < 0)
-                goto finish;
-
-        if ((r = start_interface(fd, if_loopback)) < 0)
-                goto finish;
-
-        do {
-                if ((r = read_response(fd)) < 0)
-                        goto finish;
-
-                requests |= r;
-
-        } while (requests != REQUEST_ALL);
-
-        r = 0;
-
-finish:
-        if (r < 0)
-                log_error("Failed to configure loopback device: %s", strerror(-r));
-
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
diff --git a/loopback-setup.h b/loopback-setup.h
deleted file mode 100644
index b4614fa..0000000
--- a/loopback-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooloopbacksetuphfoo
-#define fooloopbacksetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int loopback_setup(void);
-
-#endif
diff --git a/macro.h b/macro.h
deleted file mode 100644
index 622c08e..0000000
--- a/macro.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foomacrohfoo
-#define foomacrohfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <sys/types.h>
-
-#define _printf_attr(a,b) __attribute__ ((format (printf, a, b)))
-#define _sentinel __attribute__ ((sentinel))
-#define _noreturn __attribute__((noreturn))
-#define _unused __attribute__ ((unused))
-#define _destructor __attribute__ ((destructor))
-#define _pure __attribute__ ((pure))
-#define _const __attribute__ ((const))
-#define _deprecated __attribute__ ((deprecated))
-#define _packed __attribute__ ((packed))
-#define _malloc __attribute__ ((malloc))
-#define _weak __attribute__ ((weak))
-#define _likely(x) (__builtin_expect(!!(x),1))
-#define _unlikely(x) (__builtin_expect(!!(x),0))
-
-/* Rounds up */
-static inline size_t ALIGN(size_t l) {
-        return ((l + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
-}
-
-#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
-
-#define MAX(a,b)                                \
-        __extension__ ({                        \
-                        typeof(a) _a = (a);     \
-                        typeof(b) _b = (b);     \
-                        _a > _b ? _a : _b;      \
-                })
-
-#define MIN(a,b)                                \
-        __extension__ ({                        \
-                        typeof(a) _a = (a);     \
-                        typeof(b) _b = (b);     \
-                        _a < _b ? _a : _b;      \
-                })
-
-#define CLAMP(x, low, high)                                             \
-        __extension__ ({                                                \
-                        typeof(x) _x = (x);                             \
-                        typeof(low) _low = (low);                       \
-                        typeof(high) _high = (high);                    \
-                        ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
-                })
-
-#define assert_se(expr)                                                 \
-        do {                                                            \
-                if (_unlikely(!(expr)))                                 \
-                        log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
-                                   "Assertion '%s' failed at %s:%u, function %s(). Aborting.", \
-                                   #expr , __FILE__, __LINE__, __PRETTY_FUNCTION__); \
-        } while (false)                                                 \
-
-/* We override the glibc assert() here. */
-#undef assert
-#ifdef NDEBUG
-#define assert(expr) do {} while(false)
-#else
-#define assert(expr) assert_se(expr)
-#endif
-
-#define assert_not_reached(t)                                           \
-        do {                                                            \
-                log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__,     \
-                           "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", \
-                           t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
-        } while (false)
-
-#define assert_cc(expr)                            \
-        do {                                       \
-                switch (0) {                       \
-                        case 0:                    \
-                        case !!(expr):             \
-                                ;                  \
-                }                                  \
-        } while (false)
-
-#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
-#define UINT_TO_PTR(u) ((void*) ((uintptr_t) (u)))
-
-#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
-#define UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))
-
-#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
-#define INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
-
-#define TO_INT32(p) ((int32_t) ((intptr_t) (p)))
-#define INT32_TO_PTR(u) ((void*) ((intptr_t) (u)))
-
-#define memzero(x,l) (memset((x), 0, (l)))
-#define zero(x) (memzero(&(x), sizeof(x)))
-
-#define char_array_0(x) x[sizeof(x)-1] = 0;
-
-#define IOVEC_SET_STRING(i, s)                  \
-        do {                                    \
-                struct iovec *_i = &(i);        \
-                char *_s = (char *)(s);         \
-                _i->iov_base = _s;              \
-                _i->iov_len = strlen(_s);       \
-        } while(false);
-
-#include "log.h"
-
-#endif
diff --git a/main.c b/main.c
deleted file mode 100644
index bba2975..0000000
--- a/main.c
+++ /dev/null
@@ -1,787 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <getopt.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-
-#include "manager.h"
-#include "log.h"
-#include "mount-setup.h"
-#include "hostname-setup.h"
-#include "loopback-setup.h"
-#include "load-fragment.h"
-#include "fdset.h"
-
-static enum {
-        ACTION_RUN,
-        ACTION_HELP,
-        ACTION_TEST,
-        ACTION_DUMP_CONFIGURATION_ITEMS
-} action = ACTION_RUN;
-
-static char *default_unit = NULL;
-static ManagerRunningAs running_as = _MANAGER_RUNNING_AS_INVALID;
-
-static bool dump_core = true;
-static bool crash_shell = false;
-static int crash_chvt = -1;
-static bool confirm_spawn = false;
-static FILE* serialization = NULL;
-
-_noreturn static void freeze(void) {
-        for (;;)
-                pause();
-}
-
-static void nop_handler(int sig) {
-}
-
-_noreturn static void crash(int sig) {
-
-        if (!dump_core)
-                log_error("Caught <%s>, not dumping core.", strsignal(sig));
-        else {
-                struct sigaction sa;
-                pid_t pid;
-
-                /* We want to wait for the core process, hence let's enable SIGCHLD */
-                zero(sa);
-                sa.sa_handler = nop_handler;
-                sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
-                assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
-                if ((pid = fork()) < 0)
-                        log_error("Caught <%s>, cannot fork for core dump: %s", strsignal(sig), strerror(errno));
-
-                else if (pid == 0) {
-                        struct rlimit rl;
-
-                        /* Enable default signal handler for core dump */
-                        zero(sa);
-                        sa.sa_handler = SIG_DFL;
-                        assert_se(sigaction(sig, &sa, NULL) == 0);
-
-                        /* Don't limit the core dump size */
-                        zero(rl);
-                        rl.rlim_cur = RLIM_INFINITY;
-                        rl.rlim_max = RLIM_INFINITY;
-                        setrlimit(RLIMIT_CORE, &rl);
-
-                        /* Just to be sure... */
-                        assert_se(chdir("/") == 0);
-
-                        /* Raise the signal again */
-                        raise(sig);
-
-                        assert_not_reached("We shouldn't be here...");
-                        _exit(1);
-
-                } else {
-                        int status, r;
-
-                        /* Order things nicely. */
-                        if ((r = waitpid(pid, &status, 0)) < 0)
-                                log_error("Caught <%s>, waitpid() failed: %s", strsignal(sig), strerror(errno));
-                        else if (!WCOREDUMP(status))
-                                log_error("Caught <%s>, core dump failed.", strsignal(sig));
-                        else
-                                log_error("Caught <%s>, dumped core as pid %llu.", strsignal(sig), (unsigned long long) pid);
-                }
-        }
-
-        if (crash_chvt)
-                chvt(crash_chvt);
-
-        if (crash_shell) {
-                struct sigaction sa;
-                pid_t pid;
-
-                log_info("Executing crash shell in 10s...");
-                sleep(10);
-
-                /* Let the kernel reap children for us */
-                zero(sa);
-                sa.sa_handler = SIG_IGN;
-                sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
-                assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
-                if ((pid = fork()) < 0)
-                        log_error("Failed to fork off crash shell: %s", strerror(errno));
-                else if (pid == 0) {
-                        int fd, r;
-
-                        if ((fd = acquire_terminal("/dev/console", false, true)) < 0) {
-                                log_error("Failed to acquire terminal: %s", strerror(-fd));
-                                _exit(1);
-                        }
-
-                        if ((r = make_stdio(fd)) < 0) {
-                                log_error("Failed to duplicate terminal fd: %s", strerror(-r));
-                                _exit(1);
-                        }
-
-                        execl("/bin/sh", "/bin/sh", NULL);
-
-                        log_error("execl() failed: %s", strerror(errno));
-                        _exit(1);
-                }
-
-                log_info("Successfully spawned crash shall as pid %llu.", (unsigned long long) pid);
-        }
-
-        log_info("Freezing execution.");
-        freeze();
-}
-
-static void install_crash_handler(void) {
-        struct sigaction sa;
-
-        zero(sa);
-
-        sa.sa_handler = crash;
-        sa.sa_flags = SA_NODEFER;
-
-        assert_se(sigaction(SIGSEGV, &sa, NULL) == 0);
-        assert_se(sigaction(SIGILL, &sa, NULL) == 0);
-        assert_se(sigaction(SIGFPE, &sa, NULL) == 0);
-        assert_se(sigaction(SIGBUS, &sa, NULL) == 0);
-        assert_se(sigaction(SIGQUIT, &sa, NULL) == 0);
-        assert_se(sigaction(SIGABRT, &sa, NULL) == 0);
-}
-
-static int make_null_stdio(void) {
-        int null_fd, r;
-
-        if ((null_fd = open("/dev/null", O_RDWR)) < 0) {
-                log_error("Failed to open /dev/null: %m");
-                return -errno;
-        }
-
-        if ((r = make_stdio(null_fd)) < 0)
-                log_warning("Failed to dup2() device: %s", strerror(-r));
-
-        return r;
-}
-
-static int console_setup(bool do_reset) {
-        int tty_fd, r;
-
-        /* If we are init, we connect stdin/stdout/stderr to /dev/null
-         * and make sure we don't have a controlling tty. */
-
-        release_terminal();
-
-        if (!do_reset)
-                return 0;
-
-        if ((tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
-                log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
-                return -tty_fd;
-        }
-
-        if ((r = reset_terminal(tty_fd)) < 0)
-                log_error("Failed to reset /dev/console: %s", strerror(-r));
-
-        close_nointr_nofail(tty_fd);
-        return r;
-}
-
-static int set_default_unit(const char *u) {
-        char *c;
-
-        assert(u);
-
-        if (!(c = strdup(u)))
-                return -ENOMEM;
-
-        free(default_unit);
-        default_unit = c;
-        return 0;
-}
-
-static int parse_proc_cmdline_word(const char *word) {
-
-        static const char * const rlmap[] = {
-                "single", SPECIAL_RUNLEVEL1_TARGET,
-                "-s",     SPECIAL_RUNLEVEL1_TARGET,
-                "s",      SPECIAL_RUNLEVEL1_TARGET,
-                "S",      SPECIAL_RUNLEVEL1_TARGET,
-                "1",      SPECIAL_RUNLEVEL1_TARGET,
-                "2",      SPECIAL_RUNLEVEL2_TARGET,
-                "3",      SPECIAL_RUNLEVEL3_TARGET,
-                "4",      SPECIAL_RUNLEVEL4_TARGET,
-                "5",      SPECIAL_RUNLEVEL5_TARGET
-        };
-
-        if (startswith(word, "systemd.default="))
-                return set_default_unit(word + 16);
-
-        else if (startswith(word, "systemd.log_target=")) {
-
-                if (log_set_target_from_string(word + 19) < 0)
-                        log_warning("Failed to parse log target %s. Ignoring.", word + 19);
-
-        } else if (startswith(word, "systemd.log_level=")) {
-
-                if (log_set_max_level_from_string(word + 18) < 0)
-                        log_warning("Failed to parse log level %s. Ignoring.", word + 18);
-
-        } else if (startswith(word, "systemd.dump_core=")) {
-                int r;
-
-                if ((r = parse_boolean(word + 18)) < 0)
-                        log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18);
-                else
-                        dump_core = r;
-
-        } else if (startswith(word, "systemd.crash_shell=")) {
-                int r;
-
-                if ((r = parse_boolean(word + 20)) < 0)
-                        log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20);
-                else
-                        crash_shell = r;
-
-
-        } else if (startswith(word, "systemd.confirm_spawn=")) {
-                int r;
-
-                if ((r = parse_boolean(word + 22)) < 0)
-                        log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22);
-                else
-                        confirm_spawn = r;
-
-        } else if (startswith(word, "systemd.crash_chvt=")) {
-                int k;
-
-                if (safe_atoi(word + 19, &k) < 0)
-                        log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19);
-                else
-                        crash_chvt = k;
-
-        } else if (startswith(word, "systemd.")) {
-
-                log_warning("Unknown kernel switch %s. Ignoring.", word);
-
-                log_info("Supported kernel switches:");
-                log_info("systemd.default=UNIT                     Default unit to start");
-                log_info("systemd.log_target=console|kmsg|syslog   Log target");
-                log_info("systemd.log_level=LEVEL                  Log level");
-                log_info("systemd.dump_core=0|1                    Dump core on crash");
-                log_info("systemd.crash_shell=0|1                  On crash run shell");
-                log_info("systemd.crash_chvt=N                     Change to VT #N on crash");
-                log_info("systemd.confirm_spawn=0|1                Confirm every process spawn");
-
-        } else {
-                unsigned i;
-
-                /* SysV compatibility */
-                for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
-                        if (streq(word, rlmap[i]))
-                                return set_default_unit(rlmap[i+1]);
-        }
-
-        return 0;
-}
-
-static int parse_proc_cmdline(void) {
-        char *line;
-        int r;
-        char *w;
-        size_t l;
-        char *state;
-
-        if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
-                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(errno));
-                return 0;
-        }
-
-        FOREACH_WORD_QUOTED(w, l, line, state) {
-                char *word;
-
-                if (!(word = strndup(w, l))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                r = parse_proc_cmdline_word(word);
-                free(word);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        free(line);
-        return r;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
-        enum {
-                ARG_LOG_LEVEL = 0x100,
-                ARG_LOG_TARGET,
-                ARG_DEFAULT,
-                ARG_RUNNING_AS,
-                ARG_TEST,
-                ARG_DUMP_CONFIGURATION_ITEMS,
-                ARG_CONFIRM_SPAWN,
-                ARG_DESERIALIZE
-        };
-
-        static const struct option options[] = {
-                { "log-level",                required_argument, NULL, ARG_LOG_LEVEL                },
-                { "log-target",               required_argument, NULL, ARG_LOG_TARGET               },
-                { "default",                  required_argument, NULL, ARG_DEFAULT                  },
-                { "running-as",               required_argument, NULL, ARG_RUNNING_AS               },
-                { "test",                     no_argument,       NULL, ARG_TEST                     },
-                { "help",                     no_argument,       NULL, 'h'                          },
-                { "dump-configuration-items", no_argument,       NULL, ARG_DUMP_CONFIGURATION_ITEMS },
-                { "confirm-spawn",            no_argument,       NULL, ARG_CONFIRM_SPAWN            },
-                { "deserialize",              required_argument, NULL, ARG_DESERIALIZE              },
-                { NULL,                       0,                 NULL, 0                            }
-        };
-
-        int c, r;
-
-        assert(argc >= 1);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
-
-                switch (c) {
-
-                case ARG_LOG_LEVEL:
-                        if ((r = log_set_max_level_from_string(optarg)) < 0) {
-                                log_error("Failed to parse log level %s.", optarg);
-                                return r;
-                        }
-
-                        break;
-
-                case ARG_LOG_TARGET:
-
-                        if ((r = log_set_target_from_string(optarg)) < 0) {
-                                log_error("Failed to parse log target %s.", optarg);
-                                return r;
-                        }
-
-                        break;
-
-                case ARG_DEFAULT:
-
-                        if ((r = set_default_unit(optarg)) < 0) {
-                                log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
-                                return r;
-                        }
-
-                        break;
-
-                case ARG_RUNNING_AS: {
-                        ManagerRunningAs as;
-
-                        if ((as = manager_running_as_from_string(optarg)) < 0) {
-                                log_error("Failed to parse running as value %s", optarg);
-                                return -EINVAL;
-                        }
-
-                        running_as = as;
-                        break;
-                }
-
-                case ARG_TEST:
-                        action = ACTION_TEST;
-                        break;
-
-                case ARG_DUMP_CONFIGURATION_ITEMS:
-                        action = ACTION_DUMP_CONFIGURATION_ITEMS;
-                        break;
-
-                case ARG_CONFIRM_SPAWN:
-                        confirm_spawn = true;
-                        break;
-
-                case ARG_DESERIALIZE: {
-                        int fd;
-                        FILE *f;
-
-                        if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
-                                log_error("Failed to parse deserialize option %s.", optarg);
-                                return r;
-                        }
-
-                        if (!(f = fdopen(fd, "r"))) {
-                                log_error("Failed to open serialization fd: %m");
-                                return r;
-                        }
-
-                        if (serialization)
-                                fclose(serialization);
-
-                        serialization = f;
-
-                        break;
-                }
-
-                case 'h':
-                        action = ACTION_HELP;
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
-                }
-
-        /* PID 1 will get the kernel arguments as parameters, which we
-         * ignore and unconditionally read from
-         * /proc/cmdline. However, we need to ignore those arguments
-         * here. */
-        if (running_as != MANAGER_INIT && optind < argc) {
-                log_error("Excess arguments.");
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int help(void) {
-
-        printf("%s [options]\n\n"
-               "  -h --help                      Show this help\n"
-               "     --default=UNIT              Set default unit\n"
-               "     --log-level=LEVEL           Set log level\n"
-               "     --log-target=TARGET         Set log target (console, syslog, kmsg, syslog-or-kmsg)\n"
-               "     --running-as=AS             Set running as (init, system, session)\n"
-               "     --test                      Determine startup sequence, dump it and exit\n"
-               "     --dump-configuration-items  Dump understood unit configuration items\n"
-               "     --confirm-spawn             Ask for confirmation when spawning processes\n",
-               __progname);
-
-        return 0;
-}
-
-static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) {
-        FILE *f = NULL;
-        FDSet *fds = NULL;
-        int r;
-
-        assert(m);
-        assert(_f);
-        assert(_fds);
-
-        if ((r = manager_open_serialization(&f)) < 0) {
-                log_error("Failed to create serialization faile: %s", strerror(-r));
-                goto fail;
-        }
-
-        if (!(fds = fdset_new())) {
-                r = -ENOMEM;
-                log_error("Failed to allocate fd set: %s", strerror(-r));
-                goto fail;
-        }
-
-        if ((r = manager_serialize(m, f, fds)) < 0) {
-                log_error("Failed to serialize state: %s", strerror(-r));
-                goto fail;
-        }
-
-        if (fseeko(f, 0, SEEK_SET) < 0) {
-                log_error("Failed to rewind serialization fd: %m");
-                goto fail;
-        }
-
-        if ((r = fd_cloexec(fileno(f), false)) < 0) {
-                log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
-                goto fail;
-        }
-
-        if ((r = fdset_cloexec(fds, false)) < 0) {
-                log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
-                goto fail;
-        }
-
-        *_f = f;
-        *_fds = fds;
-
-        return 0;
-
-fail:
-        fdset_free(fds);
-
-        if (f)
-                fclose(f);
-
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        Manager *m = NULL;
-        Unit *target = NULL;
-        Job *job = NULL;
-        int r, retval = 1;
-        FDSet *fds = NULL;
-        bool reexecute = false;
-
-        if (getpid() == 1) {
-                running_as = MANAGER_INIT;
-                log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
-        } else
-                running_as = MANAGER_SESSION;
-
-        if (set_default_unit(SPECIAL_DEFAULT_TARGET) < 0)
-                goto finish;
-
-        /* Mount /proc, /sys and friends, so that /proc/cmdline and
-         * /proc/$PID/fd is available. */
-        if (mount_setup() < 0)
-                goto finish;
-
-        /* Reset all signal handlers. */
-        assert_se(reset_all_signal_handlers() == 0);
-
-        /* If we are init, we can block sigkill. Yay. */
-        ignore_signal(SIGKILL);
-        ignore_signal(SIGPIPE);
-
-        if (running_as != MANAGER_SESSION)
-                if (parse_proc_cmdline() < 0)
-                        goto finish;
-
-        log_parse_environment();
-
-        if (parse_argv(argc, argv) < 0)
-                goto finish;
-
-        if (action == ACTION_HELP) {
-                retval = help();
-                goto finish;
-        } else if (action == ACTION_DUMP_CONFIGURATION_ITEMS) {
-                unit_dump_config_items(stdout);
-                retval = 0;
-                goto finish;
-        }
-
-        assert_se(action == ACTION_RUN || action == ACTION_TEST);
-
-        /* Remember open file descriptors for later deserialization */
-        if (serialization) {
-                if ((r = fdset_new_fill(&fds)) < 0) {
-                        log_error("Failed to allocate fd set: %s", strerror(-r));
-                        goto finish;
-                }
-
-                assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
-        } else
-                close_all_fds(NULL, 0);
-
-        /* Set up PATH unless it is already set */
-        setenv("PATH",
-               "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
-               running_as == MANAGER_INIT);
-
-        /* Move out of the way, so that we won't block unmounts */
-        assert_se(chdir("/")  == 0);
-
-        if (running_as != MANAGER_SESSION) {
-                /* Become a session leader if we aren't one yet. */
-                setsid();
-
-                /* Disable the umask logic */
-                umask(0);
-        }
-
-        /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
-        dbus_connection_set_change_sigpipe(FALSE);
-
-        /* Reset the console, but only if this is really init and we
-         * are freshly booted */
-        if (running_as != MANAGER_SESSION && action == ACTION_RUN) {
-                console_setup(getpid() == 1 && !serialization);
-                make_null_stdio();
-        }
-
-        /* Open the logging devices, if possible and necessary */
-        log_open();
-
-        /* Make sure we leave a core dump without panicing the
-         * kernel. */
-        if (getpid() == 1)
-                install_crash_handler();
-
-        log_debug("systemd running in %s mode.", manager_running_as_to_string(running_as));
-
-        if (running_as == MANAGER_INIT) {
-                hostname_setup();
-                loopback_setup();
-        }
-
-        if ((r = manager_new(running_as, confirm_spawn, &m)) < 0) {
-                log_error("Failed to allocate manager object: %s", strerror(-r));
-                goto finish;
-        }
-
-        if ((r = manager_startup(m, serialization, fds)) < 0)
-                log_error("Failed to fully start up daemon: %s", strerror(-r));
-
-        if (fds) {
-                /* This will close all file descriptors that were opened, but
-                 * not claimed by any unit. */
-
-                fdset_free(fds);
-                fds = NULL;
-        }
-
-        if (serialization) {
-                fclose(serialization);
-                serialization = NULL;
-        } else {
-                log_debug("Activating default unit: %s", default_unit);
-
-                if ((r = manager_load_unit(m, default_unit, NULL, &target)) < 0) {
-                        log_error("Failed to load default target: %s", strerror(-r));
-
-                        log_info("Trying to load rescue target...");
-                        if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &target)) < 0) {
-                                log_error("Failed to load rescue target: %s", strerror(-r));
-                                goto finish;
-                        }
-                }
-
-                if (action == ACTION_TEST) {
-                        printf("-> By units:\n");
-                        manager_dump_units(m, stdout, "\t");
-                }
-
-                if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) {
-                        log_error("Failed to start default target: %s", strerror(-r));
-                        goto finish;
-                }
-
-                if (action == ACTION_TEST) {
-                        printf("-> By jobs:\n");
-                        manager_dump_jobs(m, stdout, "\t");
-                        retval = 0;
-                        goto finish;
-                }
-        }
-
-        for (;;) {
-                if ((r = manager_loop(m)) < 0) {
-                        log_error("Failed to run mainloop: %s", strerror(-r));
-                        goto finish;
-                }
-
-                switch (m->exit_code) {
-
-                case MANAGER_EXIT:
-                        retval = 0;
-                        log_debug("Exit.");
-                        goto finish;
-
-                case MANAGER_RELOAD:
-                        if ((r = manager_reload(m)) < 0)
-                                log_error("Failed to reload: %s", strerror(-r));
-                        break;
-
-                case MANAGER_REEXECUTE:
-                        if (prepare_reexecute(m, &serialization, &fds) < 0)
-                                goto finish;
-
-                        reexecute = true;
-                        log_debug("Reexecuting.");
-                        goto finish;
-
-                default:
-                        assert_not_reached("Unknown exit code.");
-                }
-        }
-
-finish:
-        if (m)
-                manager_free(m);
-
-        free(default_unit);
-
-        dbus_shutdown();
-
-        if (reexecute) {
-                const char *args[11];
-                unsigned i = 0;
-                char sfd[16];
-
-                assert(serialization);
-                assert(fds);
-
-                args[i++] = SYSTEMD_BINARY_PATH;
-
-                args[i++] = "--log-level";
-                args[i++] = log_level_to_string(log_get_max_level());
-
-                args[i++] = "--log-target";
-                args[i++] = log_target_to_string(log_get_target());
-
-                args[i++] = "--running-as";
-                args[i++] = manager_running_as_to_string(running_as);
-
-                snprintf(sfd, sizeof(sfd), "%i", fileno(serialization));
-                char_array_0(sfd);
-
-                args[i++] = "--deserialize";
-                args[i++] = sfd;
-
-                if (confirm_spawn)
-                        args[i++] = "--confirm-spawn";
-
-                args[i++] = NULL;
-
-                assert(i <= ELEMENTSOF(args));
-
-                execv(args[0], (char* const*) args);
-
-                log_error("Failed to reexecute: %m");
-        }
-
-        if (serialization)
-                fclose(serialization);
-
-        if (fds)
-                fdset_free(fds);
-
-        if (getpid() == 1)
-                freeze();
-
-        return retval;
-}
diff --git a/manager.c b/manager.c
deleted file mode 100644
index 688d9fa..0000000
--- a/manager.c
+++ /dev/null
@@ -1,2291 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <sys/signalfd.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <utmpx.h>
-#include <sys/poll.h>
-#include <sys/reboot.h>
-#include <sys/ioctl.h>
-#include <linux/kd.h>
-#include <libcgroup.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "manager.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "util.h"
-#include "ratelimit.h"
-#include "cgroup.h"
-#include "mount-setup.h"
-#include "utmp-wtmp.h"
-#include "unit-name.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "missing.h"
-
-/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
-#define GC_QUEUE_ENTRIES_MAX 16
-
-/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
-#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
-
-static int enable_special_signals(Manager *m) {
-        char fd;
-
-        assert(m);
-
-        /* Enable that we get SIGINT on control-alt-del */
-        if (reboot(RB_DISABLE_CAD) < 0)
-                log_warning("Failed to enable ctrl-alt-del handling: %m");
-
-        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0)
-                log_warning("Failed to open /dev/tty0: %m");
-        else {
-                /* Enable that we get SIGWINCH on kbrequest */
-                if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
-                        log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
-
-                close_nointr_nofail(fd);
-        }
-
-        return 0;
-}
-
-static int manager_setup_signals(Manager *m) {
-        sigset_t mask;
-        struct epoll_event ev;
-        struct sigaction sa;
-
-        assert(m);
-
-        /* We are not interested in SIGSTOP and friends. */
-        zero(sa);
-        sa.sa_handler = SIG_DFL;
-        sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
-        assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
-        assert_se(sigemptyset(&mask) == 0);
-        assert_se(sigaddset(&mask, SIGCHLD) == 0);
-        assert_se(sigaddset(&mask, SIGTERM) == 0);
-        assert_se(sigaddset(&mask, SIGHUP) == 0);
-        assert_se(sigaddset(&mask, SIGUSR1) == 0);
-        assert_se(sigaddset(&mask, SIGUSR2) == 0);
-        assert_se(sigaddset(&mask, SIGINT) == 0);   /* Kernel sends us this on control-alt-del */
-        assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */
-        assert_se(sigaddset(&mask, SIGPWR) == 0);   /* Some kernel drivers and upsd send us this on power failure */
-        assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
-
-        m->signal_watch.type = WATCH_SIGNAL;
-        if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
-                return -errno;
-
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.ptr = &m->signal_watch;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
-                return -errno;
-
-        if (m->running_as == MANAGER_INIT)
-                return enable_special_signals(m);
-
-        return 0;
-}
-
-static char** session_dirs(void) {
-        const char *home, *e;
-        char *config_home = NULL, *data_home = NULL;
-        char **config_dirs = NULL, **data_dirs = NULL;
-        char **r = NULL, **t;
-
-        /* Implement the mechanisms defined in
-         *
-         * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
-         *
-         * We look in both the config and the data dirs because we
-         * want to encourage that distributors ship their unit files
-         * as data, and allow overriding as configuration.
-         */
-
-        home = getenv("HOME");
-
-        if ((e = getenv("XDG_CONFIG_HOME"))) {
-                if (asprintf(&config_home, "%s/systemd/session", e) < 0)
-                        goto fail;
-
-        } else if (home) {
-                if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0)
-                        goto fail;
-        }
-
-        if ((e = getenv("XDG_CONFIG_DIRS")))
-                if (!(config_dirs = strv_split(e, ":")))
-                        goto fail;
-
-        /* We don't treat /etc/xdg/systemd here as the spec
-         * suggests because we assume that that is a link to
-         * /etc/systemd/ anyway. */
-
-        if ((e = getenv("XDG_DATA_HOME"))) {
-                if (asprintf(&data_home, "%s/systemd/session", e) < 0)
-                        goto fail;
-
-        } else if (home) {
-                if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0)
-                        goto fail;
-        }
-
-        if ((e = getenv("XDG_DATA_DIRS")))
-                data_dirs = strv_split(e, ":");
-        else
-                data_dirs = strv_new("/usr/local/share", "/usr/share", NULL);
-
-        if (!data_dirs)
-                goto fail;
-
-        /* Now merge everything we found. */
-        if (config_home) {
-                if (!(t = strv_append(r, config_home)))
-                        goto fail;
-                strv_free(r);
-                r = t;
-        }
-
-        if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session")))
-                goto finish;
-        strv_free(r);
-        r = t;
-
-        if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH)))
-                goto fail;
-        strv_free(r);
-        r = t;
-
-        if (data_home) {
-                if (!(t = strv_append(r, data_home)))
-                        goto fail;
-                strv_free(r);
-                r = t;
-        }
-
-        if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session")))
-                goto fail;
-        strv_free(r);
-        r = t;
-
-        if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH)))
-                goto fail;
-        strv_free(r);
-        r = t;
-
-        if (!strv_path_make_absolute_cwd(r))
-            goto fail;
-
-finish:
-        free(config_home);
-        strv_free(config_dirs);
-        free(data_home);
-        strv_free(data_dirs);
-
-        return r;
-
-fail:
-        strv_free(r);
-        r = NULL;
-        goto finish;
-}
-
-static int manager_find_paths(Manager *m) {
-        const char *e;
-        char *t;
-
-        assert(m);
-
-        /* First priority is whatever has been passed to us via env
-         * vars */
-        if ((e = getenv("SYSTEMD_UNIT_PATH")))
-                if (!(m->unit_path = split_path_and_make_absolute(e)))
-                        return -ENOMEM;
-
-        if (strv_isempty(m->unit_path)) {
-
-                /* Nothing is set, so let's figure something out. */
-                strv_free(m->unit_path);
-
-                if (m->running_as == MANAGER_SESSION) {
-                        if (!(m->unit_path = session_dirs()))
-                                return -ENOMEM;
-                } else
-                        if (!(m->unit_path = strv_new(
-                                              SYSTEM_CONFIG_UNIT_PATH,  /* /etc/systemd/system/ */
-                                              SYSTEM_DATA_UNIT_PATH,    /* /lib/systemd/system/ */
-                                              NULL)))
-                                return -ENOMEM;
-        }
-
-        if (m->running_as == MANAGER_INIT) {
-                /* /etc/init.d/ compatibility does not matter to users */
-
-                if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
-                        if (!(m->sysvinit_path = split_path_and_make_absolute(e)))
-                                return -ENOMEM;
-
-                if (strv_isempty(m->sysvinit_path)) {
-                        strv_free(m->sysvinit_path);
-
-                        if (!(m->sysvinit_path = strv_new(
-                                              SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
-                                              NULL)))
-                                return -ENOMEM;
-                }
-
-                if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
-                        if (!(m->sysvrcnd_path = split_path_and_make_absolute(e)))
-                                return -ENOMEM;
-
-                if (strv_isempty(m->sysvrcnd_path)) {
-                        strv_free(m->sysvrcnd_path);
-
-                        if (!(m->sysvrcnd_path = strv_new(
-                                              SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
-                                              NULL)))
-                                return -ENOMEM;
-                }
-        }
-
-        strv_uniq(m->unit_path);
-        strv_uniq(m->sysvinit_path);
-        strv_uniq(m->sysvrcnd_path);
-
-        assert(!strv_isempty(m->unit_path));
-        if (!(t = strv_join(m->unit_path, "\n\t")))
-                return -ENOMEM;
-        log_debug("Looking for unit files in:\n\t%s", t);
-        free(t);
-
-        if (!strv_isempty(m->sysvinit_path)) {
-
-                if (!(t = strv_join(m->sysvinit_path, "\n\t")))
-                        return -ENOMEM;
-
-                log_debug("Looking for SysV init scripts in:\n\t%s", t);
-                free(t);
-        } else
-                log_debug("Ignoring SysV init scripts.");
-
-        if (!strv_isempty(m->sysvrcnd_path)) {
-
-                if (!(t = strv_join(m->sysvrcnd_path, "\n\t")))
-                        return -ENOMEM;
-
-                log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
-                free(t);
-        } else
-                log_debug("Ignoring SysV rcN.d links.");
-
-        return 0;
-}
-
-int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
-        Manager *m;
-        int r = -ENOMEM;
-
-        assert(_m);
-        assert(running_as >= 0);
-        assert(running_as < _MANAGER_RUNNING_AS_MAX);
-
-        if (!(m = new0(Manager, 1)))
-                return -ENOMEM;
-
-        m->boot_timestamp = now(CLOCK_REALTIME);
-
-        m->running_as = running_as;
-        m->confirm_spawn = confirm_spawn;
-        m->name_data_slot = -1;
-        m->exit_code = _MANAGER_EXIT_CODE_INVALID;
-
-        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
-        m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
-
-        if (!(m->environment = strv_copy(environ)))
-                goto fail;
-
-        if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
-                goto fail;
-
-        if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
-                goto fail;
-
-        if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
-                goto fail;
-
-        if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
-                goto fail;
-
-        if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
-                goto fail;
-
-        if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
-                goto fail;
-
-        if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
-                goto fail;
-
-        if ((r = manager_find_paths(m)) < 0)
-                goto fail;
-
-        if ((r = manager_setup_signals(m)) < 0)
-                goto fail;
-
-        if ((r = manager_setup_cgroup(m)) < 0)
-                goto fail;
-
-        /* Try to connect to the busses, if possible. */
-        if ((r = bus_init_system(m)) < 0 ||
-            (r = bus_init_api(m)) < 0)
-                goto fail;
-
-        *_m = m;
-        return 0;
-
-fail:
-        manager_free(m);
-        return r;
-}
-
-static unsigned manager_dispatch_cleanup_queue(Manager *m) {
-        Meta *meta;
-        unsigned n = 0;
-
-        assert(m);
-
-        while ((meta = m->cleanup_queue)) {
-                assert(meta->in_cleanup_queue);
-
-                unit_free(UNIT(meta));
-                n++;
-        }
-
-        return n;
-}
-
-enum {
-        GC_OFFSET_IN_PATH,  /* This one is on the path we were travelling */
-        GC_OFFSET_UNSURE,   /* No clue */
-        GC_OFFSET_GOOD,     /* We still need this unit */
-        GC_OFFSET_BAD,      /* We don't need this unit anymore */
-        _GC_OFFSET_MAX
-};
-
-static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
-        Iterator i;
-        Unit *other;
-        bool is_bad;
-
-        assert(u);
-
-        if (u->meta.gc_marker == gc_marker + GC_OFFSET_GOOD ||
-            u->meta.gc_marker == gc_marker + GC_OFFSET_BAD ||
-            u->meta.gc_marker == gc_marker + GC_OFFSET_IN_PATH)
-                return;
-
-        if (u->meta.in_cleanup_queue)
-                goto bad;
-
-        if (unit_check_gc(u))
-                goto good;
-
-        u->meta.gc_marker = gc_marker + GC_OFFSET_IN_PATH;
-
-        is_bad = true;
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) {
-                unit_gc_sweep(other, gc_marker);
-
-                if (other->meta.gc_marker == gc_marker + GC_OFFSET_GOOD)
-                        goto good;
-
-                if (other->meta.gc_marker != gc_marker + GC_OFFSET_BAD)
-                        is_bad = false;
-        }
-
-        if (is_bad)
-                goto bad;
-
-        /* We were unable to find anything out about this entry, so
-         * let's investigate it later */
-        u->meta.gc_marker = gc_marker + GC_OFFSET_UNSURE;
-        unit_add_to_gc_queue(u);
-        return;
-
-bad:
-        /* We definitely know that this one is not useful anymore, so
-         * let's mark it for deletion */
-        u->meta.gc_marker = gc_marker + GC_OFFSET_BAD;
-        unit_add_to_cleanup_queue(u);
-        return;
-
-good:
-        u->meta.gc_marker = gc_marker + GC_OFFSET_GOOD;
-}
-
-static unsigned manager_dispatch_gc_queue(Manager *m) {
-        Meta *meta;
-        unsigned n = 0;
-        unsigned gc_marker;
-
-        assert(m);
-
-        if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
-            (m->gc_queue_timestamp <= 0 ||
-             (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
-                return 0;
-
-        log_debug("Running GC...");
-
-        m->gc_marker += _GC_OFFSET_MAX;
-        if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
-                m->gc_marker = 1;
-
-        gc_marker = m->gc_marker;
-
-        while ((meta = m->gc_queue)) {
-                assert(meta->in_gc_queue);
-
-                unit_gc_sweep(UNIT(meta), gc_marker);
-
-                LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta);
-                meta->in_gc_queue = false;
-
-                n++;
-
-                if (meta->gc_marker == gc_marker + GC_OFFSET_BAD ||
-                    meta->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
-                        log_debug("Collecting %s", meta->id);
-                        meta->gc_marker = gc_marker + GC_OFFSET_BAD;
-                        unit_add_to_cleanup_queue(UNIT(meta));
-                }
-        }
-
-        m->n_in_gc_queue = 0;
-        m->gc_queue_timestamp = 0;
-
-        return n;
-}
-
-static void manager_clear_jobs_and_units(Manager *m) {
-        Job *j;
-        Unit *u;
-
-        assert(m);
-
-        while ((j = hashmap_first(m->transaction_jobs)))
-                job_free(j);
-
-        while ((u = hashmap_first(m->units)))
-                unit_free(u);
-}
-
-void manager_free(Manager *m) {
-        UnitType c;
-
-        assert(m);
-
-        manager_dispatch_cleanup_queue(m);
-        manager_clear_jobs_and_units(m);
-
-        for (c = 0; c < _UNIT_TYPE_MAX; c++)
-                if (unit_vtable[c]->shutdown)
-                        unit_vtable[c]->shutdown(m);
-
-        /* If we reexecute ourselves, we keep the root cgroup
-         * around */
-        manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
-
-        bus_done_api(m);
-        bus_done_system(m);
-
-        hashmap_free(m->units);
-        hashmap_free(m->jobs);
-        hashmap_free(m->transaction_jobs);
-        hashmap_free(m->watch_pids);
-        hashmap_free(m->watch_bus);
-
-        if (m->epoll_fd >= 0)
-                close_nointr_nofail(m->epoll_fd);
-        if (m->signal_watch.fd >= 0)
-                close_nointr_nofail(m->signal_watch.fd);
-
-        strv_free(m->unit_path);
-        strv_free(m->sysvinit_path);
-        strv_free(m->sysvrcnd_path);
-        strv_free(m->environment);
-
-        free(m->cgroup_controller);
-        free(m->cgroup_hierarchy);
-
-        hashmap_free(m->cgroup_bondings);
-
-        free(m);
-}
-
-int manager_enumerate(Manager *m) {
-        int r = 0, q;
-        UnitType c;
-
-        assert(m);
-
-        /* Let's ask every type to load all units from disk/kernel
-         * that it might know */
-        for (c = 0; c < _UNIT_TYPE_MAX; c++)
-                if (unit_vtable[c]->enumerate)
-                        if ((q = unit_vtable[c]->enumerate(m)) < 0)
-                                r = q;
-
-        manager_dispatch_load_queue(m);
-        return r;
-}
-
-int manager_coldplug(Manager *m) {
-        int r = 0, q;
-        Iterator i;
-        Unit *u;
-        char *k;
-
-        assert(m);
-
-        /* Then, let's set up their initial state. */
-        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-
-                /* ignore aliases */
-                if (u->meta.id != k)
-                        continue;
-
-                if (UNIT_VTABLE(u)->coldplug)
-                        if ((q = UNIT_VTABLE(u)->coldplug(u)) < 0)
-                                r = q;
-        }
-
-        return r;
-}
-
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
-        int r, q;
-
-        assert(m);
-
-        /* First, enumerate what we can from all config files */
-        r = manager_enumerate(m);
-
-        /* Second, deserialize if there is something to deserialize */
-        if (serialization)
-                if ((q = manager_deserialize(m, serialization, fds)) < 0)
-                        r = q;
-
-        /* Third, fire things up! */
-        if ((q = manager_coldplug(m)) < 0)
-                r = q;
-
-        /* Now that the initial devices are available, let's see if we
-         * can write the utmp file */
-        manager_write_utmp_reboot(m);
-
-        return r;
-}
-
-static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
-        assert(m);
-        assert(j);
-
-        /* Deletes one job from the transaction */
-
-        manager_transaction_unlink_job(m, j, delete_dependencies);
-
-        if (!j->installed)
-                job_free(j);
-}
-
-static void transaction_delete_unit(Manager *m, Unit *u) {
-        Job *j;
-
-        /* Deletes all jobs associated with a certain unit from the
-         * transaction */
-
-        while ((j = hashmap_get(m->transaction_jobs, u)))
-                transaction_delete_job(m, j, true);
-}
-
-static void transaction_clean_dependencies(Manager *m) {
-        Iterator i;
-        Job *j;
-
-        assert(m);
-
-        /* Drops all dependencies of all installed jobs */
-
-        HASHMAP_FOREACH(j, m->jobs, i) {
-                while (j->subject_list)
-                        job_dependency_free(j->subject_list);
-                while (j->object_list)
-                        job_dependency_free(j->object_list);
-        }
-
-        assert(!m->transaction_anchor);
-}
-
-static void transaction_abort(Manager *m) {
-        Job *j;
-
-        assert(m);
-
-        while ((j = hashmap_first(m->transaction_jobs)))
-                if (j->installed)
-                        transaction_delete_job(m, j, true);
-                else
-                        job_free(j);
-
-        assert(hashmap_isempty(m->transaction_jobs));
-
-        transaction_clean_dependencies(m);
-}
-
-static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) {
-        JobDependency *l;
-
-        assert(m);
-
-        /* A recursive sweep through the graph that marks all units
-         * that matter to the anchor job, i.e. are directly or
-         * indirectly a dependency of the anchor job via paths that
-         * are fully marked as mattering. */
-
-        if (j)
-                l = j->subject_list;
-        else
-                l = m->transaction_anchor;
-
-        LIST_FOREACH(subject, l, l) {
-
-                /* This link does not matter */
-                if (!l->matters)
-                        continue;
-
-                /* This unit has already been marked */
-                if (l->object->generation == generation)
-                        continue;
-
-                l->object->matters_to_anchor = true;
-                l->object->generation = generation;
-
-                transaction_find_jobs_that_matter_to_anchor(m, l->object, generation);
-        }
-}
-
-static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
-        JobDependency *l, *last;
-
-        assert(j);
-        assert(other);
-        assert(j->unit == other->unit);
-        assert(!j->installed);
-
-        /* Merges 'other' into 'j' and then deletes j. */
-
-        j->type = t;
-        j->state = JOB_WAITING;
-        j->override = j->override || other->override;
-
-        j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
-
-        /* Patch us in as new owner of the JobDependency objects */
-        last = NULL;
-        LIST_FOREACH(subject, l, other->subject_list) {
-                assert(l->subject == other);
-                l->subject = j;
-                last = l;
-        }
-
-        /* Merge both lists */
-        if (last) {
-                last->subject_next = j->subject_list;
-                if (j->subject_list)
-                        j->subject_list->subject_prev = last;
-                j->subject_list = other->subject_list;
-        }
-
-        /* Patch us in as new owner of the JobDependency objects */
-        last = NULL;
-        LIST_FOREACH(object, l, other->object_list) {
-                assert(l->object == other);
-                l->object = j;
-                last = l;
-        }
-
-        /* Merge both lists */
-        if (last) {
-                last->object_next = j->object_list;
-                if (j->object_list)
-                        j->object_list->object_prev = last;
-                j->object_list = other->object_list;
-        }
-
-        /* Kill the other job */
-        other->subject_list = NULL;
-        other->object_list = NULL;
-        transaction_delete_job(m, other, true);
-}
-
-static int delete_one_unmergeable_job(Manager *m, Job *j) {
-        Job *k;
-
-        assert(j);
-
-        /* Tries to delete one item in the linked list
-         * j->transaction_next->transaction_next->... that conflicts
-         * whith another one, in an attempt to make an inconsistent
-         * transaction work. */
-
-        /* We rely here on the fact that if a merged with b does not
-         * merge with c, either a or b merge with c neither */
-        LIST_FOREACH(transaction, j, j)
-                LIST_FOREACH(transaction, k, j->transaction_next) {
-                        Job *d;
-
-                        /* Is this one mergeable? Then skip it */
-                        if (job_type_is_mergeable(j->type, k->type))
-                                continue;
-
-                        /* Ok, we found two that conflict, let's see if we can
-                         * drop one of them */
-                        if (!j->matters_to_anchor)
-                                d = j;
-                        else if (!k->matters_to_anchor)
-                                d = k;
-                        else
-                                return -ENOEXEC;
-
-                        /* Ok, we can drop one, so let's do so. */
-                        log_debug("Trying to fix job merging by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
-                        transaction_delete_job(m, d, true);
-                        return 0;
-                }
-
-        return -EINVAL;
-}
-
-static int transaction_merge_jobs(Manager *m) {
-        Job *j;
-        Iterator i;
-        int r;
-
-        assert(m);
-
-        /* First step, check whether any of the jobs for one specific
-         * task conflict. If so, try to drop one of them. */
-        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                JobType t;
-                Job *k;
-
-                t = j->type;
-                LIST_FOREACH(transaction, k, j->transaction_next) {
-                        if ((r = job_type_merge(&t, k->type)) >= 0)
-                                continue;
-
-                        /* OK, we could not merge all jobs for this
-                         * action. Let's see if we can get rid of one
-                         * of them */
-
-                        if ((r = delete_one_unmergeable_job(m, j)) >= 0)
-                                /* Ok, we managed to drop one, now
-                                 * let's ask our callers to call us
-                                 * again after garbage collecting */
-                                return -EAGAIN;
-
-                        /* We couldn't merge anything. Failure */
-                        return r;
-                }
-        }
-
-        /* Second step, merge the jobs. */
-        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                JobType t = j->type;
-                Job *k;
-
-                /* Merge all transactions */
-                LIST_FOREACH(transaction, k, j->transaction_next)
-                        assert_se(job_type_merge(&t, k->type) == 0);
-
-                /* If an active job is mergeable, merge it too */
-                if (j->unit->meta.job)
-                        job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */
-
-                while ((k = j->transaction_next)) {
-                        if (j->installed) {
-                                transaction_merge_and_delete_job(m, k, j, t);
-                                j = k;
-                        } else
-                                transaction_merge_and_delete_job(m, j, k, t);
-                }
-
-                assert(!j->transaction_next);
-                assert(!j->transaction_prev);
-        }
-
-        return 0;
-}
-
-static void transaction_drop_redundant(Manager *m) {
-        bool again;
-
-        assert(m);
-
-        /* Goes through the transaction and removes all jobs that are
-         * a noop */
-
-        do {
-                Job *j;
-                Iterator i;
-
-                again = false;
-
-                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                        bool changes_something = false;
-                        Job *k;
-
-                        LIST_FOREACH(transaction, k, j) {
-
-                                if (!job_is_anchor(k) &&
-                                    job_type_is_redundant(k->type, unit_active_state(k->unit)))
-                                        continue;
-
-                                changes_something = true;
-                                break;
-                        }
-
-                        if (changes_something)
-                                continue;
-
-                        log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
-                        transaction_delete_job(m, j, false);
-                        again = true;
-                        break;
-                }
-
-        } while (again);
-}
-
-static bool unit_matters_to_anchor(Unit *u, Job *j) {
-        assert(u);
-        assert(!j->transaction_prev);
-
-        /* Checks whether at least one of the jobs for this unit
-         * matters to the anchor. */
-
-        LIST_FOREACH(transaction, j, j)
-                if (j->matters_to_anchor)
-                        return true;
-
-        return false;
-}
-
-static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation) {
-        Iterator i;
-        Unit *u;
-        int r;
-
-        assert(m);
-        assert(j);
-        assert(!j->transaction_prev);
-
-        /* Does a recursive sweep through the ordering graph, looking
-         * for a cycle. If we find cycle we try to break it. */
-
-        /* Did we find a cycle? */
-        if (j->marker && j->generation == generation) {
-                Job *k;
-
-                /* So, we already have been here. We have a
-                 * cycle. Let's try to break it. We go backwards in
-                 * our path and try to find a suitable job to
-                 * remove. We use the marker to find our way back,
-                 * since smart how we are we stored our way back in
-                 * there. */
-
-                log_debug("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
-
-                for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
-
-                        log_debug("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type));
-
-                        if (!k->installed &&
-                            !unit_matters_to_anchor(k->unit, k)) {
-                                /* Ok, we can drop this one, so let's
-                                 * do so. */
-                                log_debug("Breaking order cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type));
-                                transaction_delete_unit(m, k->unit);
-                                return -EAGAIN;
-                        }
-
-                        /* Check if this in fact was the beginning of
-                         * the cycle */
-                        if (k == j)
-                                break;
-                }
-
-                log_debug("Unable to break cycle");
-
-                return -ENOEXEC;
-        }
-
-        /* Make the marker point to where we come from, so that we can
-         * find our way backwards if we want to break a cycle */
-        j->marker = from;
-        j->generation = generation;
-
-        /* We assume that the the dependencies are bidirectional, and
-         * hence can ignore UNIT_AFTER */
-        SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
-                Job *o;
-
-                /* Is there a job for this unit? */
-                if (!(o = hashmap_get(m->transaction_jobs, u)))
-
-                        /* Ok, there is no job for this in the
-                         * transaction, but maybe there is already one
-                         * running? */
-                        if (!(o = u->meta.job))
-                                continue;
-
-                if ((r = transaction_verify_order_one(m, o, j, generation)) < 0)
-                        return r;
-        }
-
-        /* Ok, let's backtrack, and remember that this entry is not on
-         * our path anymore. */
-        j->marker = NULL;
-
-        return 0;
-}
-
-static int transaction_verify_order(Manager *m, unsigned *generation) {
-        Job *j;
-        int r;
-        Iterator i;
-
-        assert(m);
-        assert(generation);
-
-        /* Check if the ordering graph is cyclic. If it is, try to fix
-         * that up by dropping one of the jobs. */
-
-        HASHMAP_FOREACH(j, m->transaction_jobs, i)
-                if ((r = transaction_verify_order_one(m, j, NULL, (*generation)++)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static void transaction_collect_garbage(Manager *m) {
-        bool again;
-
-        assert(m);
-
-        /* Drop jobs that are not required by any other job */
-
-        do {
-                Iterator i;
-                Job *j;
-
-                again = false;
-
-                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                        if (j->object_list)
-                                continue;
-
-                        log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
-                        transaction_delete_job(m, j, true);
-                        again = true;
-                        break;
-                }
-
-        } while (again);
-}
-
-static int transaction_is_destructive(Manager *m) {
-        Iterator i;
-        Job *j;
-
-        assert(m);
-
-        /* Checks whether applying this transaction means that
-         * existing jobs would be replaced */
-
-        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-
-                /* Assume merged */
-                assert(!j->transaction_prev);
-                assert(!j->transaction_next);
-
-                if (j->unit->meta.job &&
-                    j->unit->meta.job != j &&
-                    !job_type_is_superset(j->type, j->unit->meta.job->type))
-                        return -EEXIST;
-        }
-
-        return 0;
-}
-
-static void transaction_minimize_impact(Manager *m) {
-        bool again;
-        assert(m);
-
-        /* Drops all unnecessary jobs that reverse already active jobs
-         * or that stop a running service. */
-
-        do {
-                Job *j;
-                Iterator i;
-
-                again = false;
-
-                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                        LIST_FOREACH(transaction, j, j) {
-                                bool stops_running_service, changes_existing_job;
-
-                                /* If it matters, we shouldn't drop it */
-                                if (j->matters_to_anchor)
-                                        continue;
-
-                                /* Would this stop a running service?
-                                 * Would this change an existing job?
-                                 * If so, let's drop this entry */
-
-                                stops_running_service =
-                                        j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
-
-                                changes_existing_job =
-                                        j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state);
-
-                                if (!stops_running_service && !changes_existing_job)
-                                        continue;
-
-                                if (stops_running_service)
-                                        log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
-
-                                if (changes_existing_job)
-                                        log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
-
-                                /* Ok, let's get rid of this */
-                                log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
-
-                                transaction_delete_job(m, j, true);
-                                again = true;
-                                break;
-                        }
-
-                        if (again)
-                                break;
-                }
-
-        } while (again);
-}
-
-static int transaction_apply(Manager *m) {
-        Iterator i;
-        Job *j;
-        int r;
-
-        /* Moves the transaction jobs to the set of active jobs */
-
-        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                /* Assume merged */
-                assert(!j->transaction_prev);
-                assert(!j->transaction_next);
-
-                if (j->installed)
-                        continue;
-
-                if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
-                        goto rollback;
-        }
-
-        while ((j = hashmap_steal_first(m->transaction_jobs))) {
-                if (j->installed)
-                        continue;
-
-                if (j->unit->meta.job)
-                        job_free(j->unit->meta.job);
-
-                j->unit->meta.job = j;
-                j->installed = true;
-
-                /* We're fully installed. Now let's free data we don't
-                 * need anymore. */
-
-                assert(!j->transaction_next);
-                assert(!j->transaction_prev);
-
-                job_add_to_run_queue(j);
-                job_add_to_dbus_queue(j);
-        }
-
-        /* As last step, kill all remaining job dependencies. */
-        transaction_clean_dependencies(m);
-
-        return 0;
-
-rollback:
-
-        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                if (j->installed)
-                        continue;
-
-                hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
-        }
-
-        return r;
-}
-
-static int transaction_activate(Manager *m, JobMode mode) {
-        int r;
-        unsigned generation = 1;
-
-        assert(m);
-
-        /* This applies the changes recorded in transaction_jobs to
-         * the actual list of jobs, if possible. */
-
-        /* First step: figure out which jobs matter */
-        transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++);
-
-        /* Second step: Try not to stop any running services if
-         * we don't have to. Don't try to reverse running
-         * jobs if we don't have to. */
-        transaction_minimize_impact(m);
-
-        /* Third step: Drop redundant jobs */
-        transaction_drop_redundant(m);
-
-        for (;;) {
-                /* Fourth step: Let's remove unneeded jobs that might
-                 * be lurking. */
-                transaction_collect_garbage(m);
-
-                /* Fifth step: verify order makes sense and correct
-                 * cycles if necessary and possible */
-                if ((r = transaction_verify_order(m, &generation)) >= 0)
-                        break;
-
-                if (r != -EAGAIN) {
-                        log_debug("Requested transaction contains an unfixable cyclic ordering dependency: %s", strerror(-r));
-                        goto rollback;
-                }
-
-                /* Let's see if the resulting transaction ordering
-                 * graph is still cyclic... */
-        }
-
-        for (;;) {
-                /* Sixth step: let's drop unmergeable entries if
-                 * necessary and possible, merge entries we can
-                 * merge */
-                if ((r = transaction_merge_jobs(m)) >= 0)
-                        break;
-
-                if (r != -EAGAIN) {
-                        log_debug("Requested transaction contains unmergable jobs: %s", strerror(-r));
-                        goto rollback;
-                }
-
-                /* Seventh step: an entry got dropped, let's garbage
-                 * collect its dependencies. */
-                transaction_collect_garbage(m);
-
-                /* Let's see if the resulting transaction still has
-                 * unmergeable entries ... */
-        }
-
-        /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
-        transaction_drop_redundant(m);
-
-        /* Ninth step: check whether we can actually apply this */
-        if (mode == JOB_FAIL)
-                if ((r = transaction_is_destructive(m)) < 0) {
-                        log_debug("Requested transaction contradicts existing jobs: %s", strerror(-r));
-                        goto rollback;
-                }
-
-        /* Tenth step: apply changes */
-        if ((r = transaction_apply(m)) < 0) {
-                log_debug("Failed to apply transaction: %s", strerror(-r));
-                goto rollback;
-        }
-
-        assert(hashmap_isempty(m->transaction_jobs));
-        assert(!m->transaction_anchor);
-
-        return 0;
-
-rollback:
-        transaction_abort(m);
-        return r;
-}
-
-static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) {
-        Job *j, *f;
-        int r;
-
-        assert(m);
-        assert(unit);
-
-        /* Looks for an axisting prospective job and returns that. If
-         * it doesn't exist it is created and added to the prospective
-         * jobs list. */
-
-        f = hashmap_get(m->transaction_jobs, unit);
-
-        LIST_FOREACH(transaction, j, f) {
-                assert(j->unit == unit);
-
-                if (j->type == type) {
-                        if (is_new)
-                                *is_new = false;
-                        return j;
-                }
-        }
-
-        if (unit->meta.job && unit->meta.job->type == type)
-                j = unit->meta.job;
-        else if (!(j = job_new(m, type, unit)))
-                return NULL;
-
-        j->generation = 0;
-        j->marker = NULL;
-        j->matters_to_anchor = false;
-        j->override = override;
-
-        LIST_PREPEND(Job, transaction, f, j);
-
-        if ((r = hashmap_replace(m->transaction_jobs, unit, f)) < 0) {
-                job_free(j);
-                return NULL;
-        }
-
-        if (is_new)
-                *is_new = true;
-
-        log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type));
-
-        return j;
-}
-
-void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) {
-        assert(m);
-        assert(j);
-
-        if (j->transaction_prev)
-                j->transaction_prev->transaction_next = j->transaction_next;
-        else if (j->transaction_next)
-                hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next);
-        else
-                hashmap_remove_value(m->transaction_jobs, j->unit, j);
-
-        if (j->transaction_next)
-                j->transaction_next->transaction_prev = j->transaction_prev;
-
-        j->transaction_prev = j->transaction_next = NULL;
-
-        while (j->subject_list)
-                job_dependency_free(j->subject_list);
-
-        while (j->object_list) {
-                Job *other = j->object_list->matters ? j->object_list->subject : NULL;
-
-                job_dependency_free(j->object_list);
-
-                if (other && delete_dependencies) {
-                        log_debug("Deleting job %s/%s as dependency of job %s/%s",
-                                  other->unit->meta.id, job_type_to_string(other->type),
-                                  j->unit->meta.id, job_type_to_string(j->type));
-                        transaction_delete_job(m, other, delete_dependencies);
-                }
-        }
-}
-
-static int transaction_add_job_and_dependencies(
-                Manager *m,
-                JobType type,
-                Unit *unit,
-                Job *by,
-                bool matters,
-                bool override,
-                Job **_ret) {
-        Job *ret;
-        Iterator i;
-        Unit *dep;
-        int r;
-        bool is_new;
-
-        assert(m);
-        assert(type < _JOB_TYPE_MAX);
-        assert(unit);
-
-        if (unit->meta.load_state != UNIT_LOADED)
-                return -EINVAL;
-
-        if (!unit_job_is_applicable(unit, type))
-                return -EBADR;
-
-        /* First add the job. */
-        if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
-                return -ENOMEM;
-
-        /* Then, add a link to the job. */
-        if (!job_dependency_new(by, ret, matters))
-                return -ENOMEM;
-
-        if (is_new) {
-                /* Finally, recursively add in all dependencies. */
-                if (type == JOB_START || type == JOB_RELOAD_OR_START) {
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
-
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
-
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, NULL)) < 0)
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
-
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
-
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
-
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
-
-                } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
-
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
-                }
-
-                /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
-        }
-
-        if (_ret)
-                *_ret = ret;
-
-        return 0;
-
-fail:
-        return r;
-}
-
-static int transaction_add_isolate_jobs(Manager *m) {
-        Iterator i;
-        Unit *u;
-        char *k;
-        int r;
-
-        assert(m);
-
-        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-
-                /* ignore aliases */
-                if (u->meta.id != k)
-                        continue;
-
-                if (UNIT_VTABLE(u)->no_isolate)
-                        continue;
-
-                /* No need to stop inactive jobs */
-                if (unit_active_state(u) == UNIT_INACTIVE)
-                        continue;
-
-                /* Is there already something listed for this? */
-                if (hashmap_get(m->transaction_jobs, u))
-                        continue;
-
-                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, NULL)) < 0)
-                        log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r));
-        }
-
-        return 0;
-}
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, Job **_ret) {
-        int r;
-        Job *ret;
-
-        assert(m);
-        assert(type < _JOB_TYPE_MAX);
-        assert(unit);
-        assert(mode < _JOB_MODE_MAX);
-
-        if (mode == JOB_ISOLATE && type != JOB_START)
-                return -EINVAL;
-
-        log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type));
-
-        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, &ret)) < 0) {
-                transaction_abort(m);
-                return r;
-        }
-
-        if (mode == JOB_ISOLATE)
-                if ((r = transaction_add_isolate_jobs(m)) < 0) {
-                        transaction_abort(m);
-                        return r;
-                }
-
-        if ((r = transaction_activate(m, mode)) < 0)
-                return r;
-
-        log_debug("Enqueued job %s/%s as %u", unit->meta.id, job_type_to_string(type), (unsigned) ret->id);
-
-        if (_ret)
-                *_ret = ret;
-
-        return 0;
-}
-
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, Job **_ret) {
-        Unit *unit;
-        int r;
-
-        assert(m);
-        assert(type < _JOB_TYPE_MAX);
-        assert(name);
-        assert(mode < _JOB_MODE_MAX);
-
-        if ((r = manager_load_unit(m, name, NULL, &unit)) < 0)
-                return r;
-
-        return manager_add_job(m, type, unit, mode, override, _ret);
-}
-
-Job *manager_get_job(Manager *m, uint32_t id) {
-        assert(m);
-
-        return hashmap_get(m->jobs, UINT32_TO_PTR(id));
-}
-
-Unit *manager_get_unit(Manager *m, const char *name) {
-        assert(m);
-        assert(name);
-
-        return hashmap_get(m->units, name);
-}
-
-unsigned manager_dispatch_load_queue(Manager *m) {
-        Meta *meta;
-        unsigned n = 0;
-
-        assert(m);
-
-        /* Make sure we are not run recursively */
-        if (m->dispatching_load_queue)
-                return 0;
-
-        m->dispatching_load_queue = true;
-
-        /* Dispatches the load queue. Takes a unit from the queue and
-         * tries to load its data until the queue is empty */
-
-        while ((meta = m->load_queue)) {
-                assert(meta->in_load_queue);
-
-                unit_load(UNIT(meta));
-                n++;
-        }
-
-        m->dispatching_load_queue = false;
-        return n;
-}
-
-int manager_load_unit_prepare(Manager *m, const char *name, const char *path, Unit **_ret) {
-        Unit *ret;
-        int r;
-
-        assert(m);
-        assert(name || path);
-
-        /* This will prepare the unit for loading, but not actually
-         * load anything from disk. */
-
-        if (path && !is_path(path))
-                return -EINVAL;
-
-        if (!name)
-                name = file_name_from_path(path);
-
-        if (!unit_name_is_valid(name))
-                return -EINVAL;
-
-        if ((ret = manager_get_unit(m, name))) {
-                *_ret = ret;
-                return 1;
-        }
-
-        if (!(ret = unit_new(m)))
-                return -ENOMEM;
-
-        if (path)
-                if (!(ret->meta.fragment_path = strdup(path))) {
-                        unit_free(ret);
-                        return -ENOMEM;
-                }
-
-        if ((r = unit_add_name(ret, name)) < 0) {
-                unit_free(ret);
-                return r;
-        }
-
-        unit_add_to_load_queue(ret);
-        unit_add_to_dbus_queue(ret);
-        unit_add_to_gc_queue(ret);
-
-        if (_ret)
-                *_ret = ret;
-
-        return 0;
-}
-
-int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret) {
-        int r;
-
-        assert(m);
-
-        /* This will load the service information files, but not actually
-         * start any services or anything. */
-
-        if ((r = manager_load_unit_prepare(m, name, path, _ret)) != 0)
-                return r;
-
-        manager_dispatch_load_queue(m);
-
-        if (_ret)
-                *_ret = unit_follow_merge(*_ret);
-
-        return 0;
-}
-
-void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
-        Iterator i;
-        Job *j;
-
-        assert(s);
-        assert(f);
-
-        HASHMAP_FOREACH(j, s->jobs, i)
-                job_dump(j, f, prefix);
-}
-
-void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
-        Iterator i;
-        Unit *u;
-        const char *t;
-
-        assert(s);
-        assert(f);
-
-        HASHMAP_FOREACH_KEY(u, t, s->units, i)
-                if (u->meta.id == t)
-                        unit_dump(u, f, prefix);
-}
-
-void manager_clear_jobs(Manager *m) {
-        Job *j;
-
-        assert(m);
-
-        transaction_abort(m);
-
-        while ((j = hashmap_first(m->jobs)))
-                job_free(j);
-}
-
-unsigned manager_dispatch_run_queue(Manager *m) {
-        Job *j;
-        unsigned n = 0;
-
-        if (m->dispatching_run_queue)
-                return 0;
-
-        m->dispatching_run_queue = true;
-
-        while ((j = m->run_queue)) {
-                assert(j->installed);
-                assert(j->in_run_queue);
-
-                job_run_and_invalidate(j);
-                n++;
-        }
-
-        m->dispatching_run_queue = false;
-        return n;
-}
-
-unsigned manager_dispatch_dbus_queue(Manager *m) {
-        Job *j;
-        Meta *meta;
-        unsigned n = 0;
-
-        assert(m);
-
-        if (m->dispatching_dbus_queue)
-                return 0;
-
-        m->dispatching_dbus_queue = true;
-
-        while ((meta = m->dbus_unit_queue)) {
-                assert(meta->in_dbus_queue);
-
-                bus_unit_send_change_signal(UNIT(meta));
-                n++;
-        }
-
-        while ((j = m->dbus_job_queue)) {
-                assert(j->in_dbus_queue);
-
-                bus_job_send_change_signal(j);
-                n++;
-        }
-
-        m->dispatching_dbus_queue = false;
-        return n;
-}
-
-static int manager_dispatch_sigchld(Manager *m) {
-        assert(m);
-
-        for (;;) {
-                siginfo_t si;
-                Unit *u;
-
-                zero(si);
-
-                /* First we call waitd() for a PID and do not reap the
-                 * zombie. That way we can still access /proc/$PID for
-                 * it while it is a zombie. */
-                if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
-
-                        if (errno == ECHILD)
-                                break;
-
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-                }
-
-                if (si.si_pid <= 0)
-                        break;
-
-                if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
-                        char *name = NULL;
-
-                        get_process_name(si.si_pid, &name);
-                        log_debug("Got SIGCHLD for process %llu (%s)", (unsigned long long) si.si_pid, strna(name));
-                        free(name);
-                }
-
-                /* And now, we actually reap the zombie. */
-                if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-                }
-
-                if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
-                        continue;
-
-                log_debug("Child %llu died (code=%s, status=%i/%s)",
-                          (long long unsigned) si.si_pid,
-                          sigchld_code_to_string(si.si_code),
-                          si.si_status,
-                          strna(si.si_code == CLD_EXITED ? exit_status_to_string(si.si_status) : strsignal(si.si_status)));
-
-                if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
-                        continue;
-
-                log_debug("Child %llu belongs to %s", (long long unsigned) si.si_pid, u->meta.id);
-
-                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
-        }
-
-        return 0;
-}
-
-static void manager_start_target(Manager *m, const char *name) {
-        int r;
-
-        if ((r = manager_add_job_by_name(m, JOB_START, name, JOB_REPLACE, true, NULL)) < 0)
-                log_error("Failed to enqueue %s job: %s", name, strerror(-r));
-}
-
-static int manager_process_signal_fd(Manager *m) {
-        ssize_t n;
-        struct signalfd_siginfo sfsi;
-        bool sigchld = false;
-
-        assert(m);
-
-        for (;;) {
-                if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
-
-                        if (n >= 0)
-                                return -EIO;
-
-                        if (errno == EAGAIN)
-                                break;
-
-                        return -errno;
-                }
-
-                switch (sfsi.ssi_signo) {
-
-                case SIGCHLD:
-                        sigchld = true;
-                        break;
-
-                case SIGTERM:
-                        if (m->running_as == MANAGER_INIT)
-                                /* This is for compatibility with the
-                                 * original sysvinit */
-                                m->exit_code = MANAGER_REEXECUTE;
-                        else
-                                m->exit_code = MANAGER_EXIT;
-
-                        return 0;
-
-                case SIGINT:
-                        if (m->running_as == MANAGER_INIT) {
-                                manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET);
-                                break;
-                        }
-
-                        m->exit_code = MANAGER_EXIT;
-                        return 0;
-
-                case SIGWINCH:
-                        if (m->running_as == MANAGER_INIT)
-                                manager_start_target(m, SPECIAL_KBREQUEST_TARGET);
-
-                        /* This is a nop on non-init */
-                        break;
-
-                case SIGPWR:
-                        if (m->running_as == MANAGER_INIT)
-                                manager_start_target(m, SPECIAL_SIGPWR_TARGET);
-
-                        /* This is a nop on non-init */
-                        break;
-
-                case SIGUSR1: {
-                        Unit *u;
-
-                        u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
-
-                        if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
-                                log_info("Trying to reconnect to bus...");
-                                bus_init_system(m);
-                                bus_init_api(m);
-                        }
-
-                        if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
-                                log_info("Loading D-Bus service...");
-                                manager_start_target(m, SPECIAL_DBUS_SERVICE);
-                        }
-
-                        break;
-                }
-
-                case SIGUSR2:
-                        manager_dump_units(m, stdout, "\t");
-                        manager_dump_jobs(m, stdout, "\t");
-                        break;
-
-                case SIGHUP:
-                        m->exit_code = MANAGER_RELOAD;
-                        break;
-
-                default:
-                        log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo));
-                }
-        }
-
-        if (sigchld)
-                return manager_dispatch_sigchld(m);
-
-        return 0;
-}
-
-static int process_event(Manager *m, struct epoll_event *ev) {
-        int r;
-        Watch *w;
-
-        assert(m);
-        assert(ev);
-
-        assert(w = ev->data.ptr);
-
-        switch (w->type) {
-
-        case WATCH_SIGNAL:
-
-                /* An incoming signal? */
-                if (ev->events != EPOLLIN)
-                        return -EINVAL;
-
-                if ((r = manager_process_signal_fd(m)) < 0)
-                        return r;
-
-                break;
-
-        case WATCH_FD:
-
-                /* Some fd event, to be dispatched to the units */
-                UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w);
-                break;
-
-        case WATCH_TIMER: {
-                uint64_t v;
-                ssize_t k;
-
-                /* Some timer event, to be dispatched to the units */
-                if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
-
-                        if (k < 0 && (errno == EINTR || errno == EAGAIN))
-                                break;
-
-                        return k < 0 ? -errno : -EIO;
-                }
-
-                UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
-                break;
-        }
-
-        case WATCH_MOUNT:
-                /* Some mount table change, intended for the mount subsystem */
-                mount_fd_event(m, ev->events);
-                break;
-
-        case WATCH_UDEV:
-                /* Some notification from udev, intended for the device subsystem */
-                device_fd_event(m, ev->events);
-                break;
-
-        case WATCH_DBUS_WATCH:
-                bus_watch_event(m, w, ev->events);
-                break;
-
-        case WATCH_DBUS_TIMEOUT:
-                bus_timeout_event(m, w, ev->events);
-                break;
-
-        default:
-                assert_not_reached("Unknown epoll event type.");
-        }
-
-        return 0;
-}
-
-int manager_loop(Manager *m) {
-        int r;
-
-        RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
-
-        assert(m);
-        m->exit_code = MANAGER_RUNNING;
-
-        while (m->exit_code == MANAGER_RUNNING) {
-                struct epoll_event event;
-                int n;
-
-                if (!ratelimit_test(&rl)) {
-                        /* Yay, something is going seriously wrong, pause a little */
-                        log_warning("Looping too fast. Throttling execution a little.");
-                        sleep(1);
-                }
-
-                if (manager_dispatch_load_queue(m) > 0)
-                        continue;
-
-                if (manager_dispatch_run_queue(m) > 0)
-                        continue;
-
-                if (bus_dispatch(m) > 0)
-                        continue;
-
-                if (manager_dispatch_cleanup_queue(m) > 0)
-                        continue;
-
-                if (manager_dispatch_gc_queue(m) > 0)
-                        continue;
-
-                if (manager_dispatch_dbus_queue(m) > 0)
-                        continue;
-
-                if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-                }
-
-                assert(n == 1);
-
-                if ((r = process_event(m, &event)) < 0)
-                        return r;
-        }
-
-        return m->exit_code;
-}
-
-int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) {
-        char *n;
-        Unit *u;
-
-        assert(m);
-        assert(s);
-        assert(_u);
-
-        if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
-                return -EINVAL;
-
-        if (!(n = bus_path_unescape(s+31)))
-                return -ENOMEM;
-
-        u = manager_get_unit(m, n);
-        free(n);
-
-        if (!u)
-                return -ENOENT;
-
-        *_u = u;
-
-        return 0;
-}
-
-int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
-        Job *j;
-        unsigned id;
-        int r;
-
-        assert(m);
-        assert(s);
-        assert(_j);
-
-        if (!startswith(s, "/org/freedesktop/systemd1/job/"))
-                return -EINVAL;
-
-        if ((r = safe_atou(s + 30, &id)) < 0)
-                return r;
-
-        if (!(j = manager_get_job(m, id)))
-                return -ENOENT;
-
-        *_j = j;
-
-        return 0;
-}
-
-static bool manager_utmp_good(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if ((r = mount_path_is_mounted(m, _PATH_UTMPX)) <= 0) {
-
-                if (r < 0)
-                        log_warning("Failed to determine whether " _PATH_UTMPX " is mounted: %s", strerror(-r));
-
-                return false;
-        }
-
-        return true;
-}
-
-void manager_write_utmp_reboot(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if (m->utmp_reboot_written)
-                return;
-
-        if (m->running_as != MANAGER_INIT)
-                return;
-
-        if (!manager_utmp_good(m))
-                return;
-
-        if ((r = utmp_put_reboot(m->boot_timestamp)) < 0) {
-
-                if (r != -ENOENT && r != -EROFS)
-                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-
-                return;
-        }
-
-        m->utmp_reboot_written = true;
-}
-
-void manager_write_utmp_runlevel(Manager *m, Unit *u) {
-        int runlevel, r;
-
-        assert(m);
-        assert(u);
-
-        if (u->meta.type != UNIT_TARGET)
-                return;
-
-        if (m->running_as != MANAGER_INIT)
-                return;
-
-        if (!manager_utmp_good(m))
-                return;
-
-        if ((runlevel = target_get_runlevel(TARGET(u))) <= 0)
-                return;
-
-        if ((r = utmp_put_runlevel(0, runlevel, 0)) < 0) {
-
-                if (r != -ENOENT && r != -EROFS)
-                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-        }
-}
-
-void manager_dispatch_bus_name_owner_changed(
-                Manager *m,
-                const char *name,
-                const char* old_owner,
-                const char *new_owner) {
-
-        Unit *u;
-
-        assert(m);
-        assert(name);
-
-        if (!(u = hashmap_get(m->watch_bus, name)))
-                return;
-
-        UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
-}
-
-void manager_dispatch_bus_query_pid_done(
-                Manager *m,
-                const char *name,
-                pid_t pid) {
-
-        Unit *u;
-
-        assert(m);
-        assert(name);
-        assert(pid >= 1);
-
-        if (!(u = hashmap_get(m->watch_bus, name)))
-                return;
-
-        UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
-}
-
-int manager_open_serialization(FILE **_f) {
-        char *path;
-        mode_t saved_umask;
-        int fd;
-        FILE *f;
-
-        assert(_f);
-
-        if (asprintf(&path, "/dev/shm/systemd-%u.dump-XXXXXX", (unsigned) getpid()) < 0)
-                return -ENOMEM;
-
-        saved_umask = umask(0077);
-        fd = mkostemp(path, O_RDWR|O_CLOEXEC);
-        umask(saved_umask);
-
-        if (fd < 0) {
-                free(path);
-                return -errno;
-        }
-
-        unlink(path);
-
-        log_debug("Serializing state to %s", path);
-        free(path);
-
-        if (!(f = fdopen(fd, "w+")) < 0)
-                return -errno;
-
-        *_f = f;
-
-        return 0;
-}
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
-        Iterator i;
-        Unit *u;
-        const char *t;
-        int r;
-
-        assert(m);
-        assert(f);
-        assert(fds);
-
-        HASHMAP_FOREACH_KEY(u, t, m->units, i) {
-                if (u->meta.id != t)
-                        continue;
-
-                if (!unit_can_serialize(u))
-                        continue;
-
-                /* Start marker */
-                fputs(u->meta.id, f);
-                fputc('\n', f);
-
-                if ((r = unit_serialize(u, f, fds)) < 0)
-                        return r;
-        }
-
-        if (ferror(f))
-                return -EIO;
-
-        return 0;
-}
-
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
-        int r = 0;
-
-        assert(m);
-        assert(f);
-
-        log_debug("Deserializing state...");
-
-        for (;;) {
-                Unit *u;
-                char name[UNIT_NAME_MAX+2];
-
-                /* Start marker */
-                if (!fgets(name, sizeof(name), f)) {
-                        if (feof(f))
-                                break;
-
-                        return -errno;
-                }
-
-                char_array_0(name);
-
-                if ((r = manager_load_unit(m, strstrip(name), NULL, &u)) < 0)
-                        return r;
-
-                if ((r = unit_deserialize(u, f, fds)) < 0)
-                        return r;
-        }
-
-        if (ferror(f))
-                return -EIO;
-
-        return 0;
-}
-
-int manager_reload(Manager *m) {
-        int r, q;
-        FILE *f;
-        FDSet *fds;
-
-        assert(m);
-
-        if ((r = manager_open_serialization(&f)) < 0)
-                return r;
-
-        if (!(fds = fdset_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if ((r = manager_serialize(m, f, fds)) < 0)
-                goto finish;
-
-        if (fseeko(f, 0, SEEK_SET) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        /* From here on there is no way back. */
-        manager_clear_jobs_and_units(m);
-
-        /* First, enumerate what we can from all config files */
-        if ((q = manager_enumerate(m)) < 0)
-                r = q;
-
-        /* Second, deserialize our stored data */
-        if ((q = manager_deserialize(m, f, fds)) < 0)
-                r = q;
-
-        fclose(f);
-        f = NULL;
-
-        /* Third, fire things up! */
-        if ((q = manager_coldplug(m)) < 0)
-                r = q;
-
-finish:
-        if (f)
-                fclose(f);
-
-        if (fds)
-                fdset_free(fds);
-
-        return r;
-}
-
-static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
-        [MANAGER_INIT] = "init",
-        [MANAGER_SYSTEM] = "system",
-        [MANAGER_SESSION] = "session"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);
diff --git a/manager.h b/manager.h
deleted file mode 100644
index a6500ac..0000000
--- a/manager.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foomanagerhfoo
-#define foomanagerhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <dbus/dbus.h>
-
-#include "fdset.h"
-
-/* Enforce upper limit how many names we allow */
-#define MANAGER_MAX_NAMES 2048
-
-typedef struct Manager Manager;
-typedef enum WatchType WatchType;
-typedef struct Watch Watch;
-
-typedef enum ManagerExitCode {
-        MANAGER_RUNNING,
-        MANAGER_EXIT,
-        MANAGER_RELOAD,
-        MANAGER_REEXECUTE,
-        _MANAGER_EXIT_CODE_MAX,
-        _MANAGER_EXIT_CODE_INVALID = -1
-} ManagerExitCode;
-
-typedef enum ManagerRunningAs {
-        MANAGER_INIT,      /* root and pid=1 */
-        MANAGER_SYSTEM,    /* root and pid!=1 */
-        MANAGER_SESSION,   /* non-root, for a session */
-        _MANAGER_RUNNING_AS_MAX,
-        _MANAGER_RUNNING_AS_INVALID = -1
-} ManagerRunningAs;
-
-enum WatchType {
-        WATCH_INVALID,
-        WATCH_SIGNAL,
-        WATCH_FD,
-        WATCH_TIMER,
-        WATCH_MOUNT,
-        WATCH_UDEV,
-        WATCH_DBUS_WATCH,
-        WATCH_DBUS_TIMEOUT
-};
-
-struct Watch {
-        int fd;
-        WatchType type;
-        union {
-                union Unit *unit;
-                DBusWatch *bus_watch;
-                DBusTimeout *bus_timeout;
-        } data;
-        bool fd_is_dupped:1;
-        bool socket_accept:1;
-};
-
-#include "unit.h"
-#include "job.h"
-#include "hashmap.h"
-#include "list.h"
-#include "set.h"
-#include "dbus.h"
-
-#define SPECIAL_DEFAULT_TARGET "default.target"
-
-/* This is not really intended to be started by directly. This is
- * mostly so that other targets (reboot/halt/poweroff) can depend on
- * it to bring all services down that want to be brought down on
- * system shutdown. */
-#define SPECIAL_SHUTDOWN_TARGET "shutdown.target"
-
-#define SPECIAL_LOGGER_SOCKET "systemd-logger.socket"
-
-#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
-#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
-#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
-
-#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"
-#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target"
-#define SPECIAL_SWAP_TARGET "swap.target"
-#define SPECIAL_NETWORK_TARGET "network.target"
-#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target"     /* LSB's $named */
-#define SPECIAL_RPCBIND_TARGET "rpcbind.target"           /* LSB's $portmap */
-#define SPECIAL_SYSLOG_TARGET "syslog.target"             /* Should pull in syslog.socket or syslog.service */
-#define SPECIAL_RTC_SET_TARGET "rtc-set.target"           /* LSB's $time */
-
-#define SPECIAL_BASIC_TARGET "basic.target"
-#define SPECIAL_RESCUE_TARGET "rescue.target"
-
-#ifndef SPECIAL_DBUS_SERVICE
-#define SPECIAL_DBUS_SERVICE "dbus.service"
-#endif
-
-#ifndef SPECIAL_SYSLOG_SERVICE
-#define SPECIAL_SYSLOG_SERVICE "syslog.service"
-#endif
-
-/* For SysV compatibility. Usually an alias for a saner target. On
- * SysV-free systems this doesn't exist. */
-#define SPECIAL_RUNLEVEL0_TARGET "runlevel0.target"
-#define SPECIAL_RUNLEVEL1_TARGET "runlevel1.target"
-#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target"
-#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
-#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
-#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
-#define SPECIAL_RUNLEVEL6_TARGET "runlevel6.target"
-
-struct Manager {
-        uint32_t current_job_id;
-
-        /* Note that the set of units we know of is allowed to be
-         * incosistent. However the subset of it that is loaded may
-         * not, and the list of jobs may neither. */
-
-        /* Active jobs and units */
-        Hashmap *units;  /* name string => Unit object n:1 */
-        Hashmap *jobs;   /* job id => Job object 1:1 */
-
-        /* To make it easy to iterate through the units of a specific
-         * type we maintain a per type linked list */
-        LIST_HEAD(Meta, units_per_type[_UNIT_TYPE_MAX]);
-
-        /* Units that need to be loaded */
-        LIST_HEAD(Meta, load_queue); /* this is actually more a stack than a queue, but uh. */
-
-        /* Jobs that need to be run */
-        LIST_HEAD(Job, run_queue);   /* more a stack than a queue, too */
-
-        /* Units and jobs that have not yet been announced via
-         * D-Bus. When something about a job changes it is added here
-         * if it is not in there yet. This allows easy coalescing of
-         * D-Bus change signals. */
-        LIST_HEAD(Meta, dbus_unit_queue);
-        LIST_HEAD(Job, dbus_job_queue);
-
-        /* Units to remove */
-        LIST_HEAD(Meta, cleanup_queue);
-
-        /* Units to check when doing GC */
-        LIST_HEAD(Meta, gc_queue);
-
-        /* Jobs to be added */
-        Hashmap *transaction_jobs;      /* Unit object => Job object list 1:1 */
-        JobDependency *transaction_anchor;
-
-        Hashmap *watch_pids;  /* pid => Unit object n:1 */
-
-        Watch signal_watch;
-
-        int epoll_fd;
-
-        unsigned n_snapshots;
-
-        char **unit_path;
-        char **sysvinit_path;
-        char **sysvrcnd_path;
-
-        char **environment;
-
-        usec_t boot_timestamp;
-
-        /* Data specific to the device subsystem */
-        struct udev* udev;
-        struct udev_monitor* udev_monitor;
-        Watch udev_watch;
-
-        /* Data specific to the mount subsystem */
-        FILE *proc_self_mountinfo;
-        Watch mount_watch;
-
-        /* Data specific to the swap filesystem */
-        FILE *proc_swaps;
-
-        /* Data specific to the D-Bus subsystem */
-        DBusConnection *api_bus, *system_bus;
-        Set *subscribed;
-        DBusMessage *queued_message; /* This is used during reloading:
-                                      * before the reload we queue the
-                                      * reply message here, and
-                                      * afterwards we send it */
-
-        Hashmap *watch_bus;  /* D-Bus names => Unit object n:1 */
-        int32_t name_data_slot;
-
-        /* Data specific to the Automount subsystem */
-        int dev_autofs_fd;
-
-        /* Data specific to the cgroup subsystem */
-        Hashmap *cgroup_bondings; /* path string => CGroupBonding object 1:n */
-        char *cgroup_controller;
-        char *cgroup_hierarchy;
-
-        usec_t gc_queue_timestamp;
-
-        int gc_marker;
-        unsigned n_in_gc_queue;
-
-        /* Flags */
-        ManagerRunningAs running_as;
-        ManagerExitCode exit_code:4;
-
-        bool dispatching_load_queue:1;
-        bool dispatching_run_queue:1;
-        bool dispatching_dbus_queue:1;
-
-        bool request_api_bus_dispatch:1;
-        bool request_system_bus_dispatch:1;
-
-        bool utmp_reboot_written:1;
-
-        bool confirm_spawn:1;
-};
-
-int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **m);
-void manager_free(Manager *m);
-
-int manager_enumerate(Manager *m);
-int manager_coldplug(Manager *m);
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
-
-Job *manager_get_job(Manager *m, uint32_t id);
-Unit *manager_get_unit(Manager *m, const char *name);
-
-int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u);
-int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
-
-int manager_load_unit_prepare(Manager *m, const char *name, const char *path, Unit **_ret);
-int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret);
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, Job **_ret);
-
-void manager_dump_units(Manager *s, FILE *f, const char *prefix);
-void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
-
-void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies);
-
-void manager_clear_jobs(Manager *m);
-
-unsigned manager_dispatch_load_queue(Manager *m);
-unsigned manager_dispatch_run_queue(Manager *m);
-unsigned manager_dispatch_dbus_queue(Manager *m);
-
-int manager_loop(Manager *m);
-
-void manager_write_utmp_reboot(Manager *m);
-void manager_write_utmp_runlevel(Manager *m, Unit *t);
-
-void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
-void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid);
-
-int manager_open_serialization(FILE **_f);
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds);
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
-
-int manager_reload(Manager *m);
-
-const char *manager_running_as_to_string(ManagerRunningAs i);
-ManagerRunningAs manager_running_as_from_string(const char *s);
-
-#endif
diff --git a/missing.h b/missing.h
deleted file mode 100644
index 7db7d7d..0000000
--- a/missing.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foomissinghfoo
-#define foomissinghfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/* Missing glibc definitions to access certain kernel APIs */
-
-#include <sys/resource.h>
-#include <sys/syscall.h>
-
-#ifndef RLIMIT_RTTIME
-#define RLIMIT_RTTIME 15
-#endif
-
-static inline int pivot_root(const char *new_root, const char *put_old) {
-        return syscall(SYS_pivot_root, new_root, put_old);
-}
-
-#endif
diff --git a/mount-setup.c b/mount-setup.c
deleted file mode 100644
index cb91e18..0000000
--- a/mount-setup.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/mount.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libgen.h>
-#include <assert.h>
-
-#include "mount-setup.h"
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-
-typedef struct MountPoint {
-        const char *what;
-        const char *where;
-        const char *type;
-        const char *options;
-        unsigned long flags;
-        bool fatal;
-} MountPoint;
-
-static const MountPoint mount_table[] = {
-        { "proc",        "/proc",                    "proc",        NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "sysfs",       "/sys",                     "sysfs",       NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "devtmps",     "/dev",                     "devtmpfs",    "mode=755",  MS_NOSUID,                    true },
-        { "tmpfs",       "/dev/shm",                 "tmpfs",       "mode=1777", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "devpts",      "/dev/pts",                 "devpts",      NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-        { "cgroup",      "/cgroup/debug",            "cgroup",      "debug",     MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "debugfs",     "/sys/kernel/debug",        "debugfs",     NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-        { "binfmt_misc", "/proc/sys/fs/binfmt_misc", "binfmt_misc", NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-        { "mqueue",      "/dev/mqueue",              "mqueue",      NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-};
-
-bool mount_point_is_api(const char *path) {
-        unsigned i;
-
-        /* Checks if this mount point is considered "API", and hence
-         * should be ignored */
-
-        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
-                if (path_startswith(path, mount_table[i].where))
-                        return true;
-
-        return path_startswith(path, "/cgroup/");
-}
-
-static int mount_one(const MountPoint *p) {
-        int r;
-
-        assert(p);
-
-        if ((r = path_is_mount_point(p->where)) < 0)
-                return r;
-
-        if (r > 0)
-                return 0;
-
-        /* The access mode here doesn't really matter too much, since
-         * the mounted file system will take precedence anyway. */
-        mkdir_p(p->where, 0755);
-
-        log_debug("Mounting %s to %s of type %s with options %s.",
-                  p->what,
-                  p->where,
-                  p->type,
-                  strna(p->options));
-
-        if (mount(p->what,
-                  p->where,
-                  p->type,
-                  p->flags,
-                  p->options) < 0) {
-                log_error("Failed to mount %s: %s", p->where, strerror(errno));
-                return p->fatal ? -errno : 0;
-        }
-
-        return 0;
-}
-
-static int mount_cgroup_controllers(void) {
-        int r;
-        FILE *f;
-        char buf [256];
-
-        /* Mount all available cgroup controllers. */
-
-        if (!(f = fopen("/proc/cgroups", "re")))
-                return -ENOENT;
-
-        /* Ignore the header line */
-        (void) fgets(buf, sizeof(buf), f);
-
-        for (;;) {
-                MountPoint p;
-                char *controller, *where;
-
-                if (fscanf(f, "%ms %*i %*i %*i", &controller) != 1) {
-
-                        if (feof(f))
-                                break;
-
-                        log_error("Failed to parse /proc/cgroups.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                if (asprintf(&where, "/cgroup/%s", controller) < 0) {
-                        free(controller);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                zero(p);
-                p.what = "cgroup";
-                p.where = where;
-                p.type = "cgroup";
-                p.options = controller;
-                p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
-                p.fatal = false;
-
-                r = mount_one(&p);
-                free(controller);
-                free(where);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        fclose(f);
-
-        return r;
-}
-
-int mount_setup(void) {
-        int r;
-        unsigned i;
-
-        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
-                if ((r = mount_one(mount_table+i)) < 0)
-                        return r;
-
-        return mount_cgroup_controllers();
-}
diff --git a/mount-setup.h b/mount-setup.h
deleted file mode 100644
index bb13e01..0000000
--- a/mount-setup.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foomountsetuphfoo
-#define foomountsetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-int mount_setup(void);
-
-bool mount_point_is_api(const char *path);
-
-#endif
diff --git a/mount.c b/mount.c
deleted file mode 100644
index ec03a52..0000000
--- a/mount.c
+++ /dev/null
@@ -1,1539 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <stdio.h>
-#include <mntent.h>
-#include <sys/epoll.h>
-#include <signal.h>
-
-#include "unit.h"
-#include "mount.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "mount-setup.h"
-#include "unit-name.h"
-#include "mount.h"
-#include "dbus-mount.h"
-
-static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
-        [MOUNT_DEAD] = UNIT_INACTIVE,
-        [MOUNT_MOUNTING] = UNIT_ACTIVATING,
-        [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE,
-        [MOUNT_MOUNTED] = UNIT_ACTIVE,
-        [MOUNT_REMOUNTING] = UNIT_ACTIVE_RELOADING,
-        [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
-        [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
-        [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
-        [MOUNT_REMOUNTING_SIGTERM] = UNIT_ACTIVE_RELOADING,
-        [MOUNT_REMOUNTING_SIGKILL] = UNIT_ACTIVE_RELOADING,
-        [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
-        [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
-        [MOUNT_MAINTAINANCE] = UNIT_INACTIVE,
-};
-
-static void mount_init(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        m->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        exec_context_init(&m->exec_context);
-
-        /* We need to make sure that /bin/mount is always called in
-         * the same process group as us, so that the autofs kernel
-         * side doesn't send us another mount request while we are
-         * already trying to comply its last one. */
-        m->exec_context.no_setsid = true;
-
-        m->timer_watch.type = WATCH_INVALID;
-
-        m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-}
-
-static void mount_unwatch_control_pid(Mount *m) {
-        assert(m);
-
-        if (m->control_pid <= 0)
-                return;
-
-        unit_unwatch_pid(UNIT(m), m->control_pid);
-        m->control_pid = 0;
-}
-
-static void mount_parameters_done(MountParameters *p) {
-        assert(p);
-
-        free(p->what);
-        free(p->options);
-        free(p->fstype);
-
-        p->what = p->options = p->fstype = NULL;
-}
-
-static void mount_done(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        free(m->where);
-        m->where = NULL;
-
-        mount_parameters_done(&m->parameters_etc_fstab);
-        mount_parameters_done(&m->parameters_proc_self_mountinfo);
-        mount_parameters_done(&m->parameters_fragment);
-
-        exec_context_done(&m->exec_context);
-        exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
-        m->control_command = NULL;
-
-        mount_unwatch_control_pid(m);
-
-        unit_unwatch_timer(u, &m->timer_watch);
-}
-
-static int mount_add_mount_links(Mount *m) {
-        Meta *other;
-        int r;
-
-        assert(m);
-
-        /* Adds in links to other mount points that might lie below or
-         * above us in the hierarchy */
-
-        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_MOUNT]) {
-                Mount *n = (Mount*) other;
-
-                if (n == m)
-                        continue;
-
-                if (n->meta.load_state != UNIT_LOADED)
-                        continue;
-
-                if (path_startswith(m->where, n->where)) {
-
-                        if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
-                                return r;
-
-                        if (n->from_etc_fstab || n->from_fragment)
-                                if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
-                                        return r;
-
-                } else if (path_startswith(n->where, m->where)) {
-
-                        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(n), true)) < 0)
-                                return r;
-
-                        if (m->from_etc_fstab || m->from_fragment)
-                                if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
-                                        return r;
-                }
-        }
-
-        return 0;
-}
-
-static int mount_add_swap_links(Mount *m) {
-        Meta *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SWAP])
-                if ((r = swap_add_one_mount_link((Swap*) other, m)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int mount_add_automount_links(Mount *m) {
-        Meta *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_AUTOMOUNT])
-                if ((r = automount_add_one_mount_link((Automount*) other, m)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int mount_add_socket_links(Mount *m) {
-        Meta *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SOCKET])
-                if ((r = socket_add_one_mount_link((Socket*) other, m)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static char* mount_test_option(const char *haystack, const char *needle) {
-        struct mntent me;
-
-        assert(needle);
-
-        /* Like glibc's hasmntopt(), but works on a string, not a
-         * struct mntent */
-
-        if (!haystack)
-                return false;
-
-        zero(me);
-        me.mnt_opts = (char*) haystack;
-
-        return hasmntopt(&me, needle);
-}
-
-static int mount_add_target_links(Mount *m) {
-        const char *target;
-        MountParameters *p;
-        Unit *tu;
-        int r;
-        bool noauto, handle, automount;
-
-        assert(m);
-
-        if (m->from_fragment)
-                p = &m->parameters_fragment;
-        else if (m->from_etc_fstab)
-                p = &m->parameters_etc_fstab;
-        else
-                return 0;
-
-        noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO);
-        handle = !!mount_test_option(p->options, "comment=systemd.mount");
-        automount = !!mount_test_option(p->options, "comment=systemd.automount");
-
-        if (mount_test_option(p->options, "_netdev") ||
-            fstype_is_network(p->fstype))
-                target = SPECIAL_REMOTE_FS_TARGET;
-        else
-                target = SPECIAL_LOCAL_FS_TARGET;
-
-        if ((r = manager_load_unit(UNIT(m)->meta.manager, target, NULL, &tu)) < 0)
-                return r;
-
-        if (automount) {
-                Unit *am;
-
-                if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0)
-                        return r;
-
-                if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(am), true)) < 0)
-                        return r;
-
-                return unit_add_dependency(UNIT(am), UNIT_BEFORE, tu, true);
-
-        } else {
-
-                if (!noauto && handle)
-                        if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0)
-                                return r;
-
-                return unit_add_dependency(UNIT(m), UNIT_BEFORE, tu, true);
-        }
-}
-
-static int mount_verify(Mount *m) {
-        bool b;
-        char *e;
-        assert(m);
-
-        if (UNIT(m)->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (!(e = unit_name_from_path(m->where, ".mount")))
-                return -ENOMEM;
-
-        b = unit_has_name(UNIT(m), e);
-        free(e);
-
-        if (!b) {
-                log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->meta.id);
-                return -EINVAL;
-        }
-
-        if (m->meta.fragment_path && !m->parameters_fragment.what) {
-                log_error("%s's What setting is missing. Refusing.", UNIT(m)->meta.id);
-                return -EBADMSG;
-        }
-
-        return 0;
-}
-
-static int mount_load(Unit *u) {
-        Mount *m = MOUNT(u);
-        int r;
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
-                return r;
-
-        /* This is a new unit? Then let's add in some extras */
-        if (u->meta.load_state == UNIT_LOADED) {
-                const char *what = NULL;
-
-                if (m->meta.fragment_path)
-                        m->from_fragment = true;
-
-                if (!m->where)
-                        if (!(m->where = unit_name_to_path(u->meta.id)))
-                                return -ENOMEM;
-
-                path_kill_slashes(m->where);
-
-                if (!m->meta.description)
-                        if ((r = unit_set_description(u, m->where)) < 0)
-                                return r;
-
-                if (m->from_fragment && m->parameters_fragment.what)
-                        what = m->parameters_fragment.what;
-                else if (m->from_etc_fstab && m->parameters_etc_fstab.what)
-                        what = m->parameters_etc_fstab.what;
-                else if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what)
-                        what = m->parameters_proc_self_mountinfo.what;
-
-                if (what)
-                        if ((r = unit_add_node_link(u, what,
-                                                    (u->meta.manager->running_as == MANAGER_INIT ||
-                                                     u->meta.manager->running_as == MANAGER_SYSTEM))) < 0)
-                                return r;
-
-                if ((r = mount_add_mount_links(m)) < 0)
-                        return r;
-
-                if ((r = mount_add_socket_links(m)) < 0)
-                        return r;
-
-                if ((r = mount_add_swap_links(m)) < 0)
-                        return r;
-
-                if ((r = mount_add_automount_links(m)) < 0)
-                        return r;
-
-                if ((r = mount_add_target_links(m)) < 0)
-                        return r;
-
-                if ((r = unit_add_default_cgroup(u)) < 0)
-                        return r;
-        }
-
-        return mount_verify(m);
-}
-
-static int mount_notify_automount(Mount *m, int status) {
-        Unit *p;
-        int r;
-
-        assert(m);
-
-        if ((r = unit_get_related_unit(UNIT(m), ".automount", &p)) < 0)
-                return r == -ENOENT ? 0 : r;
-
-        return automount_send_ready(AUTOMOUNT(p), status);
-}
-
-static void mount_set_state(Mount *m, MountState state) {
-        MountState old_state;
-        assert(m);
-
-        old_state = m->state;
-        m->state = state;
-
-        if (state != MOUNT_MOUNTING &&
-            state != MOUNT_MOUNTING_DONE &&
-            state != MOUNT_REMOUNTING &&
-            state != MOUNT_UNMOUNTING &&
-            state != MOUNT_MOUNTING_SIGTERM &&
-            state != MOUNT_MOUNTING_SIGKILL &&
-            state != MOUNT_UNMOUNTING_SIGTERM &&
-            state != MOUNT_UNMOUNTING_SIGKILL &&
-            state != MOUNT_REMOUNTING_SIGTERM &&
-            state != MOUNT_REMOUNTING_SIGKILL) {
-                unit_unwatch_timer(UNIT(m), &m->timer_watch);
-                mount_unwatch_control_pid(m);
-                m->control_command = NULL;
-                m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-        }
-
-        if (state == MOUNT_MOUNTED ||
-            state == MOUNT_REMOUNTING)
-                mount_notify_automount(m, 0);
-        else if (state == MOUNT_DEAD ||
-                 state == MOUNT_UNMOUNTING ||
-                 state == MOUNT_MOUNTING_SIGTERM ||
-                 state == MOUNT_MOUNTING_SIGKILL ||
-                 state == MOUNT_REMOUNTING_SIGTERM ||
-                 state == MOUNT_REMOUNTING_SIGKILL ||
-                 state == MOUNT_UNMOUNTING_SIGTERM ||
-                 state == MOUNT_UNMOUNTING_SIGKILL ||
-                 state == MOUNT_MAINTAINANCE)
-                mount_notify_automount(m, -ENODEV);
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(m)->meta.id,
-                          mount_state_to_string(old_state),
-                          mount_state_to_string(state));
-
-        unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int mount_coldplug(Unit *u) {
-        Mount *m = MOUNT(u);
-        MountState new_state = MOUNT_DEAD;
-        int r;
-
-        assert(m);
-        assert(m->state == MOUNT_DEAD);
-
-        if (m->deserialized_state != m->state)
-                new_state = m->deserialized_state;
-        else if (m->from_proc_self_mountinfo)
-                new_state = MOUNT_MOUNTED;
-
-        if (new_state != m->state) {
-
-                if (new_state == MOUNT_MOUNTING ||
-                    new_state == MOUNT_MOUNTING_DONE ||
-                    new_state == MOUNT_REMOUNTING ||
-                    new_state == MOUNT_UNMOUNTING ||
-                    new_state == MOUNT_MOUNTING_SIGTERM ||
-                    new_state == MOUNT_MOUNTING_SIGKILL ||
-                    new_state == MOUNT_UNMOUNTING_SIGTERM ||
-                    new_state == MOUNT_UNMOUNTING_SIGKILL ||
-                    new_state == MOUNT_REMOUNTING_SIGTERM ||
-                    new_state == MOUNT_REMOUNTING_SIGKILL) {
-
-                        if (m->control_pid <= 0)
-                                return -EBADMSG;
-
-                        if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0)
-                                return r;
-
-                        if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
-                                return r;
-                }
-
-                mount_set_state(m, new_state);
-        }
-
-        return 0;
-}
-
-static void mount_dump(Unit *u, FILE *f, const char *prefix) {
-        Mount *m = MOUNT(u);
-        MountParameters *p;
-
-        assert(m);
-        assert(f);
-
-        if (m->from_proc_self_mountinfo)
-                p = &m->parameters_proc_self_mountinfo;
-        else if (m->from_fragment)
-                p = &m->parameters_fragment;
-        else
-                p = &m->parameters_etc_fstab;
-
-        fprintf(f,
-                "%sMount State: %s\n"
-                "%sWhere: %s\n"
-                "%sWhat: %s\n"
-                "%sFile System Type: %s\n"
-                "%sOptions: %s\n"
-                "%sFrom /etc/fstab: %s\n"
-                "%sFrom /proc/self/mountinfo: %s\n"
-                "%sFrom fragment: %s\n"
-                "%sKillMode: %s\n",
-                prefix, mount_state_to_string(m->state),
-                prefix, m->where,
-                prefix, strna(p->what),
-                prefix, strna(p->fstype),
-                prefix, strna(p->options),
-                prefix, yes_no(m->from_etc_fstab),
-                prefix, yes_no(m->from_proc_self_mountinfo),
-                prefix, yes_no(m->from_fragment),
-                prefix, kill_mode_to_string(m->kill_mode));
-
-        if (m->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %llu\n",
-                        prefix, (unsigned long long) m->control_pid);
-
-        exec_context_dump(&m->exec_context, f, prefix);
-}
-
-static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
-        pid_t pid;
-        int r;
-
-        assert(m);
-        assert(c);
-        assert(_pid);
-
-        if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
-                goto fail;
-
-        if ((r = exec_spawn(c,
-                            NULL,
-                            &m->exec_context,
-                            NULL, 0,
-                            m->meta.manager->environment,
-                            true,
-                            true,
-                            UNIT(m)->meta.manager->confirm_spawn,
-                            UNIT(m)->meta.cgroup_bondings,
-                            &pid)) < 0)
-                goto fail;
-
-        if ((r = unit_watch_pid(UNIT(m), pid)) < 0)
-                /* FIXME: we need to do something here */
-                goto fail;
-
-        *_pid = pid;
-
-        return 0;
-
-fail:
-        unit_unwatch_timer(UNIT(m), &m->timer_watch);
-
-        return r;
-}
-
-static void mount_enter_dead(Mount *m, bool success) {
-        assert(m);
-
-        if (!success)
-                m->failure = true;
-
-        mount_set_state(m, m->failure ? MOUNT_MAINTAINANCE : MOUNT_DEAD);
-}
-
-static void mount_enter_mounted(Mount *m, bool success) {
-        assert(m);
-
-        if (!success)
-                m->failure = true;
-
-        mount_set_state(m, MOUNT_MOUNTED);
-}
-
-static void mount_enter_signal(Mount *m, MountState state, bool success) {
-        int r;
-        bool sent = false;
-
-        assert(m);
-
-        if (!success)
-                m->failure = true;
-
-        if (m->kill_mode != KILL_NONE) {
-                int sig = (state == MOUNT_MOUNTING_SIGTERM ||
-                           state == MOUNT_UNMOUNTING_SIGTERM ||
-                           state == MOUNT_REMOUNTING_SIGTERM) ? SIGTERM : SIGKILL;
-
-                if (m->kill_mode == KILL_CONTROL_GROUP) {
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(m)->meta.cgroup_bondings, sig)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH)
-                                        goto fail;
-                        } else
-                                sent = true;
-                }
-
-                if (!sent && m->control_pid > 0)
-                        if (kill(m->kill_mode == KILL_PROCESS ? m->control_pid : -m->control_pid, sig) < 0 && errno != ESRCH) {
-                                r = -errno;
-                                goto fail;
-                        }
-        }
-
-        if (sent) {
-                if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
-                        goto fail;
-
-                mount_set_state(m, state);
-        } else if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
-                mount_enter_mounted(m, true);
-        else
-                mount_enter_dead(m, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", UNIT(m)->meta.id, strerror(-r));
-
-        if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
-                mount_enter_mounted(m, false);
-        else
-                mount_enter_dead(m, false);
-}
-
-static void mount_enter_unmounting(Mount *m, bool success) {
-        int r;
-
-        assert(m);
-
-        if (!success)
-                m->failure = true;
-
-        m->control_command_id = MOUNT_EXEC_UNMOUNT;
-        m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
-
-        if ((r = exec_command_set(
-                             m->control_command,
-                             "/bin/umount",
-                             m->where,
-                             NULL)) < 0)
-                goto fail;
-
-        mount_unwatch_control_pid(m);
-
-        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
-                goto fail;
-
-        mount_set_state(m, MOUNT_UNMOUNTING);
-
-        return;
-
-fail:
-        log_warning("%s failed to run umount exectuable: %s", UNIT(m)->meta.id, strerror(-r));
-        mount_enter_mounted(m, false);
-}
-
-static void mount_enter_mounting(Mount *m) {
-        int r;
-
-        assert(m);
-
-        m->control_command_id = MOUNT_EXEC_MOUNT;
-        m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
-
-        if (m->from_fragment)
-                r = exec_command_set(
-                                m->control_command,
-                                "/bin/mount",
-                                m->parameters_fragment.what,
-                                m->where,
-                                "-t", m->parameters_fragment.fstype,
-                                m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options,
-                                NULL);
-        else if (m->from_etc_fstab)
-                r = exec_command_set(
-                                m->control_command,
-                                "/bin/mount",
-                                m->where,
-                                NULL);
-        else
-                r = -ENOENT;
-
-        if (r < 0)
-                goto fail;
-
-        mount_unwatch_control_pid(m);
-
-        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
-                goto fail;
-
-        mount_set_state(m, MOUNT_MOUNTING);
-
-        return;
-
-fail:
-        log_warning("%s failed to run mount exectuable: %s", UNIT(m)->meta.id, strerror(-r));
-        mount_enter_dead(m, false);
-}
-
-static void mount_enter_mounting_done(Mount *m) {
-        assert(m);
-
-        mount_set_state(m, MOUNT_MOUNTING_DONE);
-}
-
-static void mount_enter_remounting(Mount *m, bool success) {
-        int r;
-
-        assert(m);
-
-        if (!success)
-                m->failure = true;
-
-        m->control_command_id = MOUNT_EXEC_REMOUNT;
-        m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
-
-        if (m->from_fragment) {
-                char *buf = NULL;
-                const char *o;
-
-                if (m->parameters_fragment.options) {
-                        if (!(buf = strappend("remount,", m->parameters_fragment.options))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        o = buf;
-                } else
-                        o = "remount";
-
-                r = exec_command_set(
-                                m->control_command,
-                                "/bin/mount",
-                                m->parameters_fragment.what,
-                                m->where,
-                                "-t", m->parameters_fragment.fstype,
-                                "-o", o,
-                                NULL);
-
-                free(buf);
-        } else if (m->from_etc_fstab)
-                r = exec_command_set(
-                                m->control_command,
-                                "/bin/mount",
-                                m->where,
-                                "-o", "remount",
-                                NULL);
-        else
-                r = -ENOENT;
-
-        if (r < 0) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        mount_unwatch_control_pid(m);
-
-        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
-                goto fail;
-
-        mount_set_state(m, MOUNT_REMOUNTING);
-
-        return;
-
-fail:
-        mount_enter_mounted(m, false);
-}
-
-static int mount_start(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        /* We cannot fulfill this request right now, try again later
-         * please! */
-        if (m->state == MOUNT_UNMOUNTING ||
-            m->state == MOUNT_UNMOUNTING_SIGTERM ||
-            m->state == MOUNT_UNMOUNTING_SIGKILL)
-                return -EAGAIN;
-
-        /* Already on it! */
-        if (m->state == MOUNT_MOUNTING ||
-            m->state == MOUNT_MOUNTING_SIGTERM ||
-            m->state == MOUNT_MOUNTING_SIGKILL)
-                return 0;
-
-        assert(m->state == MOUNT_DEAD || m->state == MOUNT_MAINTAINANCE);
-
-        m->failure = false;
-        mount_enter_mounting(m);
-        return 0;
-}
-
-static int mount_stop(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        /* Cann't do this right now. */
-        if (m->state == MOUNT_MOUNTING ||
-            m->state == MOUNT_MOUNTING_DONE ||
-            m->state == MOUNT_MOUNTING_SIGTERM ||
-            m->state == MOUNT_MOUNTING_SIGKILL ||
-            m->state == MOUNT_REMOUNTING ||
-            m->state == MOUNT_REMOUNTING_SIGTERM ||
-            m->state == MOUNT_REMOUNTING_SIGKILL)
-                return -EAGAIN;
-
-        /* Already on it */
-        if (m->state == MOUNT_UNMOUNTING ||
-            m->state == MOUNT_UNMOUNTING_SIGKILL ||
-            m->state == MOUNT_UNMOUNTING_SIGTERM)
-                return 0;
-
-        assert(m->state == MOUNT_MOUNTED);
-
-        mount_enter_unmounting(m, true);
-        return 0;
-}
-
-static int mount_reload(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        if (m->state == MOUNT_MOUNTING_DONE)
-                return -EAGAIN;
-
-        assert(m->state == MOUNT_MOUNTED);
-
-        mount_enter_remounting(m, true);
-        return 0;
-}
-
-static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", mount_state_to_string(m->state));
-        unit_serialize_item(u, f, "failure", yes_no(m->failure));
-
-        if (m->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) m->control_pid);
-
-        if (m->control_command_id >= 0)
-                unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id));
-
-        return 0;
-}
-
-static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Mount *m = MOUNT(u);
-        int r;
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                MountState state;
-
-                if ((state = mount_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        m->deserialized_state = state;
-        } else if (streq(key, "failure")) {
-                int b;
-
-                if ((b = parse_boolean(value)) < 0)
-                        log_debug("Failed to parse failure value %s", value);
-                else
-                        m->failure = b || m->failure;
-
-        } else if (streq(key, "control-pid")) {
-                unsigned pid;
-
-                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        m->control_pid = (pid_t) pid;
-        } else if (streq(key, "control-command")) {
-                MountExecCommand id;
-
-                if ((id = mount_exec_command_from_string(value)) < 0)
-                        log_debug("Failed to parse exec-command value %s", value);
-                else {
-                        m->control_command_id = id;
-                        m->control_command = m->exec_command + id;
-                }
-
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState mount_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[MOUNT(u)->state];
-}
-
-static const char *mount_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return mount_state_to_string(MOUNT(u)->state);
-}
-
-static bool mount_check_gc(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        return m->from_etc_fstab || m->from_proc_self_mountinfo;
-}
-
-static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-        Mount *m = MOUNT(u);
-        bool success;
-
-        assert(m);
-        assert(pid >= 0);
-
-        success = is_clean_exit(code, status);
-        m->failure = m->failure || !success;
-
-        assert(m->control_pid == pid);
-        m->control_pid = 0;
-
-        if (m->control_command) {
-                exec_status_fill(&m->control_command->exec_status, pid, code, status);
-                m->control_command = NULL;
-                m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-        }
-
-        log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
-
-        /* Note that mount(8) returning and the kernel sending us a
-         * mount table change event might happen out-of-order. If an
-         * operation succeed we assume the kernel will follow soon too
-         * and already change into the resulting state.  If it fails
-         * we check if the kernel still knows about the mount. and
-         * change state accordingly. */
-
-        switch (m->state) {
-
-        case MOUNT_MOUNTING:
-        case MOUNT_MOUNTING_DONE:
-        case MOUNT_MOUNTING_SIGKILL:
-        case MOUNT_MOUNTING_SIGTERM:
-        case MOUNT_REMOUNTING:
-        case MOUNT_REMOUNTING_SIGKILL:
-        case MOUNT_REMOUNTING_SIGTERM:
-
-                if (success && m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, true);
-                else if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, false);
-                else
-                        mount_enter_dead(m, false);
-                break;
-
-        case MOUNT_UNMOUNTING:
-        case MOUNT_UNMOUNTING_SIGKILL:
-        case MOUNT_UNMOUNTING_SIGTERM:
-
-                if (success)
-                        mount_enter_dead(m, true);
-                else if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, false);
-                else
-                        mount_enter_dead(m, false);
-                break;
-
-        default:
-                assert_not_reached("Uh, control process died at wrong time.");
-        }
-}
-
-static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-        assert(elapsed == 1);
-        assert(w == &m->timer_watch);
-
-        switch (m->state) {
-
-        case MOUNT_MOUNTING:
-        case MOUNT_MOUNTING_DONE:
-                log_warning("%s mounting timed out. Stopping.", u->meta.id);
-                mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, false);
-                break;
-
-        case MOUNT_REMOUNTING:
-                log_warning("%s remounting timed out. Stopping.", u->meta.id);
-                mount_enter_signal(m, MOUNT_REMOUNTING_SIGTERM, false);
-                break;
-
-        case MOUNT_UNMOUNTING:
-                log_warning("%s unmounting timed out. Stopping.", u->meta.id);
-                mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, false);
-                break;
-
-        case MOUNT_MOUNTING_SIGTERM:
-                log_warning("%s mounting timed out. Killing.", u->meta.id);
-                mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, false);
-                break;
-
-        case MOUNT_REMOUNTING_SIGTERM:
-                log_warning("%s remounting timed out. Killing.", u->meta.id);
-                mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, false);
-                break;
-
-        case MOUNT_UNMOUNTING_SIGTERM:
-                log_warning("%s unmounting timed out. Killing.", u->meta.id);
-                mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, false);
-                break;
-
-        case MOUNT_MOUNTING_SIGKILL:
-        case MOUNT_REMOUNTING_SIGKILL:
-        case MOUNT_UNMOUNTING_SIGKILL:
-                log_warning("%s mount process still around after SIGKILL. Ignoring.", u->meta.id);
-
-                if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, false);
-                else
-                        mount_enter_dead(m, false);
-                break;
-
-        default:
-                assert_not_reached("Timeout at wrong time.");
-        }
-}
-
-static int mount_add_one(
-                Manager *m,
-                const char *what,
-                const char *where,
-                const char *options,
-                const char *fstype,
-                bool from_proc_self_mountinfo,
-                bool set_flags) {
-        int r;
-        Unit *u;
-        bool delete;
-        char *e, *w = NULL, *o = NULL, *f = NULL;
-        MountParameters *p;
-
-        assert(m);
-        assert(what);
-        assert(where);
-        assert(options);
-        assert(fstype);
-
-        assert(!set_flags || from_proc_self_mountinfo);
-
-        /* Ignore API mount points. They should never be referenced in
-         * dependencies ever. */
-        if (mount_point_is_api(where))
-                return 0;
-
-        if (streq(fstype, "autofs"))
-                return 0;
-
-        /* probably some kind of swap, ignore */
-        if (!is_path(where))
-                return 0;
-
-        if (!(e = unit_name_from_path(where, ".mount")))
-                return -ENOMEM;
-
-        if (!(u = manager_get_unit(m, e))) {
-                delete = true;
-
-                if (!(u = unit_new(m))) {
-                        free(e);
-                        return -ENOMEM;
-                }
-
-                r = unit_add_name(u, e);
-                free(e);
-
-                if (r < 0)
-                        goto fail;
-
-                if (!(MOUNT(u)->where = strdup(where))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                unit_add_to_load_queue(u);
-        } else {
-                delete = false;
-                free(e);
-        }
-
-        if (!(w = strdup(what)) ||
-            !(o = strdup(options)) ||
-            !(f = strdup(fstype))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (from_proc_self_mountinfo) {
-                p = &MOUNT(u)->parameters_proc_self_mountinfo;
-
-                if (set_flags) {
-                        MOUNT(u)->is_mounted = true;
-                        MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
-                        MOUNT(u)->just_changed = !streq_ptr(p->options, o);
-                }
-
-                MOUNT(u)->from_proc_self_mountinfo = true;
-        } else {
-                p = &MOUNT(u)->parameters_etc_fstab;
-                MOUNT(u)->from_etc_fstab = true;
-        }
-
-        free(p->what);
-        p->what = w;
-
-        free(p->options);
-        p->options = o;
-
-        free(p->fstype);
-        p->fstype = f;
-
-        unit_add_to_dbus_queue(u);
-
-        return 0;
-
-fail:
-        free(w);
-        free(o);
-        free(f);
-
-        if (delete && u)
-                unit_free(u);
-
-        return r;
-}
-
-static char *fstab_node_to_udev_node(char *p) {
-        char *dn, *t;
-        int r;
-
-        /* FIXME: to follow udev's logic 100% we need to leave valid
-         * UTF8 chars unescaped */
-
-        if (startswith(p, "LABEL=")) {
-
-                if (!(t = xescape(p+6, "/ ")))
-                        return NULL;
-
-                r = asprintf(&dn, "/dev/disk/by-label/%s", t);
-                free(t);
-
-                if (r < 0)
-                        return NULL;
-
-                return dn;
-        }
-
-        if (startswith(p, "UUID=")) {
-
-                if (!(t = xescape(p+5, "/ ")))
-                        return NULL;
-
-                r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t));
-                free(t);
-
-                if (r < 0)
-                        return NULL;
-
-                return dn;
-        }
-
-        return strdup(p);
-}
-
-static int mount_find_pri(char *options) {
-        char *end, *pri;
-        unsigned long r;
-
-        if (!(pri = mount_test_option(options, "pri=")))
-                return 0;
-
-        pri += 4;
-
-        errno = 0;
-        r = strtoul(pri, &end, 10);
-
-        if (errno != 0)
-                return -errno;
-
-        if (end == pri || (*end != ',' && *end != 0))
-                return -EINVAL;
-
-        return (int) r;
-}
-
-static int mount_load_etc_fstab(Manager *m) {
-        FILE *f;
-        int r;
-        struct mntent* me;
-
-        assert(m);
-
-        errno = 0;
-        if (!(f = setmntent("/etc/fstab", "r")))
-                return -errno;
-
-        while ((me = getmntent(f))) {
-                char *where, *what;
-
-                if (!(what = fstab_node_to_udev_node(me->mnt_fsname))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(where = strdup(me->mnt_dir))) {
-                        free(what);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (what[0] == '/')
-                        path_kill_slashes(what);
-
-                if (where[0] == '/')
-                        path_kill_slashes(where);
-
-                if (streq(me->mnt_type, "swap")) {
-                        int pri;
-
-                        if ((pri = mount_find_pri(me->mnt_opts)) < 0)
-                                r = pri;
-                        else
-                                r = swap_add_one(m,
-                                                 what,
-                                                 pri,
-                                                 !!mount_test_option(me->mnt_opts, MNTOPT_NOAUTO),
-                                                 !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"),
-                                                 false);
-                } else
-                        r = mount_add_one(m, what, where, me->mnt_opts, me->mnt_type, false, false);
-
-                free(what);
-                free(where);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = 0;
-finish:
-
-        endmntent(f);
-        return r;
-}
-
-static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
-        int r;
-        char *device, *path, *options, *fstype, *d, *p;
-
-        assert(m);
-
-        rewind(m->proc_self_mountinfo);
-
-        for (;;) {
-                int k;
-
-                device = path = options = fstype = d = p = NULL;
-
-                if ((k = fscanf(m->proc_self_mountinfo,
-                                "%*s "       /* (1) mount id */
-                                "%*s "       /* (2) parent id */
-                                "%*s "       /* (3) major:minor */
-                                "%*s "       /* (4) root */
-                                "%ms "       /* (5) mount point */
-                                "%ms"        /* (6) mount options */
-                                "%*[^-]"     /* (7) optional fields */
-                                "- "         /* (8) seperator */
-                                "%ms "       /* (9) file system type */
-                                "%ms"        /* (10) mount source */
-                                "%*[^\n]",   /* some rubbish at the end */
-                                &path,
-                                &options,
-                                &fstype,
-                                &device)) != 4) {
-
-                        if (k == EOF)
-                                break;
-
-                        r = -EBADMSG;
-                        goto finish;
-                }
-
-                if (!(d = cunescape(device)) ||
-                    !(p = cunescape(path))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if ((r = mount_add_one(m, d, p, options, fstype, true, set_flags)) < 0)
-                        goto finish;
-
-                free(device);
-                free(path);
-                free(options);
-                free(fstype);
-                free(d);
-                free(p);
-        }
-
-        r = 0;
-
-finish:
-        free(device);
-        free(path);
-        free(options);
-        free(fstype);
-        free(d);
-        free(p);
-
-        return r;
-}
-
-static void mount_shutdown(Manager *m) {
-        assert(m);
-
-        if (m->proc_self_mountinfo) {
-                fclose(m->proc_self_mountinfo);
-                m->proc_self_mountinfo = NULL;
-        }
-}
-
-static int mount_enumerate(Manager *m) {
-        int r;
-        struct epoll_event ev;
-        assert(m);
-
-        if (!m->proc_self_mountinfo) {
-                if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
-                        return -errno;
-
-                m->mount_watch.type = WATCH_MOUNT;
-                m->mount_watch.fd = fileno(m->proc_self_mountinfo);
-
-                zero(ev);
-                ev.events = EPOLLERR;
-                ev.data.ptr = &m->mount_watch;
-
-                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0)
-                        return -errno;
-        }
-
-        if ((r = mount_load_etc_fstab(m)) < 0)
-                goto fail;
-
-        if ((r = mount_load_proc_self_mountinfo(m, false)) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        mount_shutdown(m);
-        return r;
-}
-
-void mount_fd_event(Manager *m, int events) {
-        Meta *meta;
-        int r;
-
-        assert(m);
-        assert(events == EPOLLERR);
-
-        /* The manager calls this for every fd event happening on the
-         * /proc/self/mountinfo file, which informs us about mounting
-         * table changes */
-
-        if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) {
-                log_error("Failed to reread /proc/self/mountinfo: %s", strerror(errno));
-
-                /* Reset flags, just in case, for later calls */
-                LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) {
-                        Mount *mount = (Mount*) meta;
-
-                        mount->is_mounted = mount->just_mounted = mount->just_changed = false;
-                }
-
-                return;
-        }
-
-        manager_dispatch_load_queue(m);
-
-        LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) {
-                Mount *mount = (Mount*) meta;
-
-                if (!mount->is_mounted) {
-                        /* This has just been unmounted. */
-
-                        mount->from_proc_self_mountinfo = false;
-
-                        switch (mount->state) {
-
-                        case MOUNT_MOUNTED:
-                                mount_enter_dead(mount, true);
-                                break;
-
-                        default:
-                                mount_set_state(mount, mount->state);
-                                break;
-
-                        }
-
-                } else if (mount->just_mounted || mount->just_changed) {
-
-                        /* New or changed entrymount */
-
-                        switch (mount->state) {
-
-                        case MOUNT_DEAD:
-                        case MOUNT_MAINTAINANCE:
-                                mount_enter_mounted(mount, true);
-                                break;
-
-                        case MOUNT_MOUNTING:
-                                mount_enter_mounting_done(mount);
-                                break;
-
-                        default:
-                                /* Nothing really changed, but let's
-                                 * issue an notification call
-                                 * nonetheless, in case somebody is
-                                 * waiting for this. (e.g. file system
-                                 * ro/rw remounts.) */
-                                mount_set_state(mount, mount->state);
-                                break;
-                        }
-                }
-
-                /* Reset the flags for later calls */
-                mount->is_mounted = mount->just_mounted = mount->just_changed = false;
-        }
-}
-
-int mount_path_is_mounted(Manager *m, const char* path) {
-        char *t;
-        int r;
-
-        assert(m);
-        assert(path);
-
-        if (path[0] != '/')
-                return 1;
-
-        if (!(t = strdup(path)))
-                return -ENOMEM;
-
-        path_kill_slashes(t);
-
-        for (;;) {
-                char *e, *slash;
-                Unit *u;
-
-                if (!(e = unit_name_from_path(t, ".mount"))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                u = manager_get_unit(m, e);
-                free(e);
-
-                if (u &&
-                    (MOUNT(u)->from_etc_fstab || MOUNT(u)->from_fragment) &&
-                    MOUNT(u)->state != MOUNT_MOUNTED) {
-                        r = 0;
-                        goto finish;
-                }
-
-                assert_se(slash = strrchr(t, '/'));
-
-                if (slash == t) {
-                        r = 1;
-                        goto finish;
-                }
-
-                *slash = 0;
-        }
-
-        r = 1;
-
-finish:
-        free(t);
-        return r;
-}
-
-static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
-        [MOUNT_DEAD] = "dead",
-        [MOUNT_MOUNTING] = "mounting",
-        [MOUNT_MOUNTING_DONE] = "mounting-done",
-        [MOUNT_MOUNTED] = "mounted",
-        [MOUNT_REMOUNTING] = "remounting",
-        [MOUNT_UNMOUNTING] = "unmounting",
-        [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
-        [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
-        [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
-        [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
-        [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
-        [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
-        [MOUNT_MAINTAINANCE] = "maintainance"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
-
-static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
-        [MOUNT_EXEC_MOUNT] = "ExecMount",
-        [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
-        [MOUNT_EXEC_REMOUNT] = "ExecRemount",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
-
-const UnitVTable mount_vtable = {
-        .suffix = ".mount",
-
-        .no_alias = true,
-        .no_instances = true,
-        .no_isolate = true,
-
-        .init = mount_init,
-        .load = mount_load,
-        .done = mount_done,
-
-        .coldplug = mount_coldplug,
-
-        .dump = mount_dump,
-
-        .start = mount_start,
-        .stop = mount_stop,
-        .reload = mount_reload,
-
-        .serialize = mount_serialize,
-        .deserialize_item = mount_deserialize_item,
-
-        .active_state = mount_active_state,
-        .sub_state_to_string = mount_sub_state_to_string,
-
-        .check_gc = mount_check_gc,
-
-        .sigchld_event = mount_sigchld_event,
-        .timer_event = mount_timer_event,
-
-        .bus_message_handler = bus_mount_message_handler,
-
-        .enumerate = mount_enumerate,
-        .shutdown = mount_shutdown
-};
diff --git a/mount.h b/mount.h
deleted file mode 100644
index 3b28e89..0000000
--- a/mount.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foomounthfoo
-#define foomounthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Mount Mount;
-
-#include "unit.h"
-
-typedef enum MountState {
-        MOUNT_DEAD,
-        MOUNT_MOUNTING,               /* /bin/mount is running, but the mount is not done yet. */
-        MOUNT_MOUNTING_DONE,          /* /bin/mount is running, and the mount is done. */
-        MOUNT_MOUNTED,
-        MOUNT_REMOUNTING,
-        MOUNT_UNMOUNTING,
-        MOUNT_MOUNTING_SIGTERM,
-        MOUNT_MOUNTING_SIGKILL,
-        MOUNT_REMOUNTING_SIGTERM,
-        MOUNT_REMOUNTING_SIGKILL,
-        MOUNT_UNMOUNTING_SIGTERM,
-        MOUNT_UNMOUNTING_SIGKILL,
-        MOUNT_MAINTAINANCE,
-        _MOUNT_STATE_MAX,
-        _MOUNT_STATE_INVALID = -1
-} MountState;
-
-typedef enum MountExecCommand {
-        MOUNT_EXEC_MOUNT,
-        MOUNT_EXEC_UNMOUNT,
-        MOUNT_EXEC_REMOUNT,
-        _MOUNT_EXEC_COMMAND_MAX,
-        _MOUNT_EXEC_COMMAND_INVALID = -1
-} MountExecCommand;
-
-typedef struct MountParameters {
-        char *what;
-        char *options;
-        char *fstype;
-} MountParameters;
-
-struct Mount {
-        Meta meta;
-
-        char *where;
-
-        MountParameters parameters_etc_fstab;
-        MountParameters parameters_proc_self_mountinfo;
-        MountParameters parameters_fragment;
-
-        bool from_etc_fstab:1;
-        bool from_proc_self_mountinfo:1;
-        bool from_fragment:1;
-
-        /* Used while looking for mount points that vanished or got
-         * added from/to /proc/self/mountinfo */
-        bool is_mounted:1;
-        bool just_mounted:1;
-        bool just_changed:1;
-
-        bool failure:1;
-
-        usec_t timeout_usec;
-
-        ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        MountState state, deserialized_state;
-
-        KillMode kill_mode;
-
-        ExecCommand* control_command;
-        MountExecCommand control_command_id;
-        pid_t control_pid;
-
-        Watch timer_watch;
-};
-
-extern const UnitVTable mount_vtable;
-
-void mount_fd_event(Manager *m, int events);
-
-int mount_path_is_mounted(Manager *m, const char* path);
-
-const char* mount_state_to_string(MountState i);
-MountState mount_state_from_string(const char *s);
-
-const char* mount_exec_command_to_string(MountExecCommand i);
-MountExecCommand mount_exec_command_from_string(const char *s);
-
-#endif
diff --git a/namespace.c b/namespace.c
deleted file mode 100644
index 09bcaff..0000000
--- a/namespace.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/mount.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sched.h>
-#include <sys/syscall.h>
-#include <limits.h>
-#include <linux/fs.h>
-
-#include "strv.h"
-#include "util.h"
-#include "namespace.h"
-#include "missing.h"
-
-typedef enum PathMode {
-        /* This is ordered by priority! */
-        INACCESSIBLE,
-        READONLY,
-        PRIVATE,
-        READWRITE
-} PathMode;
-
-typedef struct Path {
-        const char *path;
-        PathMode mode;
-} Path;
-
-static int append_paths(Path **p, char **strv, PathMode mode) {
-        char **i;
-
-        STRV_FOREACH(i, strv) {
-
-                if (!path_is_absolute(*i))
-                        return -EINVAL;
-
-                (*p)->path = *i;
-                (*p)->mode = mode;
-                (*p)++;
-        }
-
-        return 0;
-}
-
-static int path_compare(const void *a, const void *b) {
-        const Path *p = a, *q = b;
-
-        if (path_equal(p->path, q->path)) {
-
-                /* If the paths are equal, check the mode */
-                if (p->mode < q->mode)
-                        return -1;
-
-                if (p->mode > q->mode)
-                        return 1;
-
-                return 0;
-        }
-
-        /* If the paths are not equal, then order prefixes first */
-        if (path_startswith(p->path, q->path))
-                return 1;
-
-        if (path_startswith(q->path, p->path))
-                return -1;
-
-        return 0;
-}
-
-static void drop_duplicates(Path *p, unsigned *n, bool *need_inaccessible, bool *need_private) {
-        Path *f, *t, *previous;
-
-        assert(p);
-        assert(n);
-        assert(need_inaccessible);
-        assert(need_private);
-
-        for (f = p, t = p, previous = NULL; f < p+*n; f++) {
-
-                if (previous && path_equal(f->path, previous->path))
-                        continue;
-
-                t->path = f->path;
-                t->mode = f->mode;
-
-                if (t->mode == PRIVATE)
-                        *need_private = true;
-
-                if (t->mode == INACCESSIBLE)
-                        *need_inaccessible = true;
-
-                previous = t;
-
-                t++;
-        }
-
-        *n = t - p;
-}
-
-static int apply_mount(Path *p, const char *root_dir, const char *inaccessible_dir, const char *private_dir, unsigned long flags) {
-        const char *what;
-        char *where;
-        int r;
-
-        assert(p);
-        assert(root_dir);
-        assert(inaccessible_dir);
-        assert(private_dir);
-
-        if (!(where = strappend(root_dir, p->path)))
-                return -ENOMEM;
-
-        switch (p->mode) {
-
-        case INACCESSIBLE:
-                what = inaccessible_dir;
-                flags |= MS_RDONLY;
-                break;
-
-        case READONLY:
-                flags |= MS_RDONLY;
-                /* Fall through */
-
-        case READWRITE:
-                what = p->path;
-                break;
-
-        case PRIVATE:
-                what = private_dir;
-                break;
-        }
-
-        if ((r = mount(what, where, NULL, MS_BIND|MS_REC, NULL)) >= 0) {
-                log_debug("Successfully mounted %s to %s", what, where);
-
-                /* The bind mount will always inherit the original
-                 * flags. If we want to set any flag we need
-                 * to do so in a second indepdant step. */
-                if (flags)
-                        r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_REC|flags, NULL);
-
-                /* Avoid expontial growth of trees */
-                if (r >= 0 && path_equal(p->path, "/"))
-                        r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_UNBINDABLE|flags, NULL);
-
-                if (r < 0) {
-                        r = -errno;
-                        umount2(where, MNT_DETACH);
-                }
-        }
-
-        free(where);
-        return r;
-}
-
-int setup_namespace(
-                char **writable,
-                char **readable,
-                char **inaccessible,
-                bool private_tmp,
-                unsigned long flags) {
-
-        char
-                tmp_dir[] = "/tmp/systemd-namespace-XXXXXX",
-                root_dir[] = "/tmp/systemd-namespace-XXXXXX/root",
-                old_root_dir[] = "/tmp/systemd-namespace-XXXXXX/root/tmp/old-root-XXXXXX",
-                inaccessible_dir[] = "/tmp/systemd-namespace-XXXXXX/inaccessible",
-                private_dir[] = "/tmp/systemd-namespace-XXXXXX/private";
-
-        Path *paths, *p;
-        unsigned n;
-        bool need_private = false, need_inaccessible = false;
-        bool remove_tmp = false, remove_root = false, remove_old_root = false, remove_inaccessible = false, remove_private = false;
-        int r;
-        const char *t;
-
-        n =
-                strv_length(writable) +
-                strv_length(readable) +
-                strv_length(inaccessible) +
-                (private_tmp ? 2 : 1);
-
-        if (!(paths = new(Path, n)))
-                return -ENOMEM;
-
-        p = paths;
-        if ((r = append_paths(&p, writable, READWRITE)) < 0 ||
-            (r = append_paths(&p, readable, READONLY)) < 0 ||
-            (r = append_paths(&p, inaccessible, INACCESSIBLE)) < 0)
-                goto fail;
-
-        if (private_tmp) {
-                p->path = "/tmp";
-                p->mode = PRIVATE;
-                p++;
-        }
-
-        p->path = "/";
-        p->mode = READWRITE;
-        p++;
-
-        assert(paths + n == p);
-
-        qsort(paths, n, sizeof(Path), path_compare);
-        drop_duplicates(paths, &n, &need_inaccessible, &need_private);
-
-        if (!mkdtemp(tmp_dir)) {
-                r = -errno;
-                goto fail;
-        }
-        remove_tmp = true;
-
-        memcpy(root_dir, tmp_dir, sizeof(tmp_dir)-1);
-        if (mkdir(root_dir, 0777) < 0) {
-                r = -errno;
-                goto fail;
-        }
-        remove_root = true;
-
-        if (need_inaccessible) {
-                memcpy(inaccessible_dir, tmp_dir, sizeof(tmp_dir)-1);
-                if (mkdir(inaccessible_dir, 0) < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-                remove_inaccessible = true;
-        }
-
-        if (need_private) {
-                memcpy(private_dir, tmp_dir, sizeof(tmp_dir)-1);
-                if (mkdir(private_dir, 0777 + S_ISVTX) < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-                remove_private = true;
-        }
-
-        if (unshare(CLONE_NEWNS) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* We assume that by default mount events from us won't be
-         * propagated to the root namespace. */
-
-        for (p = paths; p < paths + n; p++)
-                if ((r = apply_mount(p, root_dir, inaccessible_dir, private_dir, flags)) < 0)
-                        goto undo_mounts;
-
-        memcpy(old_root_dir, tmp_dir, sizeof(tmp_dir)-1);
-        if (!mkdtemp(old_root_dir)) {
-                r = -errno;
-                goto undo_mounts;
-        }
-        remove_old_root = true;
-
-        if (chdir(root_dir) < 0) {
-                r = -errno;
-                goto undo_mounts;
-        }
-
-        if (pivot_root(root_dir, old_root_dir) < 0) {
-                r = -errno;
-                goto undo_mounts;
-        }
-
-        t = old_root_dir + sizeof(root_dir) - 1;
-        if (umount2(t, MNT_DETACH) < 0)
-                /* At this point it's too late to turn anything back,
-                 * since we are already in the new root. */
-                return -errno;
-
-        if (rmdir(t) < 0)
-                return -errno;
-
-        return 0;
-
-undo_mounts:
-
-        for (p--; p >= paths; p--) {
-                char full_path[PATH_MAX];
-
-                snprintf(full_path, sizeof(full_path), "%s%s", root_dir, p->path);
-                char_array_0(full_path);
-
-                umount2(full_path, MNT_DETACH);
-        }
-
-fail:
-        if (remove_old_root)
-                rmdir(old_root_dir);
-
-        if (remove_inaccessible)
-                rmdir(inaccessible_dir);
-
-        if (remove_private)
-                rmdir(private_dir);
-
-        if (remove_root)
-                rmdir(root_dir);
-
-        if (remove_tmp)
-                rmdir(tmp_dir);
-
-             free(paths);
-
-        return r;
-}
diff --git a/namespace.h b/namespace.h
deleted file mode 100644
index 6128646..0000000
--- a/namespace.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foonamespacehfoo
-#define foonamespacehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-int setup_namespace(
-                char **writable,
-                char **readable,
-                char **inaccessible,
-                bool private_tmp,
-                unsigned long flags);
-
-#endif
diff --git a/ratelimit.c b/ratelimit.c
deleted file mode 100644
index 1e5ed03..0000000
--- a/ratelimit.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-
-#include "ratelimit.h"
-#include "log.h"
-
-/* Modelled after Linux' lib/ratelimit.c by Dave Young
- * <hidave.darkstar at gmail.com>, which is licensed GPLv2. */
-
-bool ratelimit_test(RateLimit *r) {
-        usec_t timestamp;
-
-        timestamp = now(CLOCK_MONOTONIC);
-
-        assert(r);
-        assert(r->interval > 0);
-        assert(r->burst > 0);
-
-        if (r->begin <= 0 ||
-            r->begin + r->interval < timestamp) {
-
-                if (r->n_missed > 0)
-                        log_warning("%u events suppressed", r->n_missed);
-
-                r->begin = timestamp;
-
-                /* Reset counters */
-                r->n_printed = 0;
-                r->n_missed = 0;
-                goto good;
-        }
-
-        if (r->n_printed <= r->burst)
-                goto good;
-
-        r->n_missed++;
-        return false;
-
-good:
-        r->n_printed++;
-        return true;
-}
diff --git a/ratelimit.h b/ratelimit.h
deleted file mode 100644
index e7dffb8..0000000
--- a/ratelimit.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooratelimithfoo
-#define fooratelimithfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-
-typedef struct RateLimit {
-        usec_t interval;
-        usec_t begin;
-        unsigned burst;
-        unsigned n_printed, n_missed;
-} RateLimit;
-
-#define RATELIMIT_DEFINE(_name, _interval, _burst)       \
-        RateLimit _name = {                              \
-                .interval = (_interval),                 \
-                .burst = (_burst),                       \
-                .n_printed = 0,                          \
-                .n_missed = 0,                           \
-                .begin = 0                               \
-        }
-
-#define RATELIMIT_INIT(v, _interval, _burst)             \
-        do {                                             \
-                RateLimit *_r = &(v);                    \
-                _r->interval = (_interval);              \
-                _r->burst = (_burst);                    \
-                _r->n_printed = 0;                       \
-                _r->n_missed = 0;                        \
-                _r->begin = 0;                           \
-        } while (false);
-
-bool ratelimit_test(RateLimit *r);
-
-#endif
diff --git a/sd-daemon.c b/sd-daemon.c
deleted file mode 100644
index cc972da..0000000
--- a/sd-daemon.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  Copyright 2010 Lennart Poettering
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation files
-  (the "Software"), to deal in the Software without restriction,
-  including without limitation the rights to use, copy, modify, merge,
-  publish, distribute, sublicense, and/or sell copies of the Software,
-  and to permit persons to whom the Software is furnished to do so,
-  subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-  SOFTWARE.
-***/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "sd-daemon.h"
-
-int sd_listen_fds(int unset_environment) {
-
-#ifdef DISABLE_SYSTEMD
-        return 0;
-#else
-        int r;
-        const char *e;
-        char *p = NULL;
-        unsigned long l;
-
-        if (!(e = getenv("LISTEN_PID"))) {
-                r = 0;
-                goto finish;
-        }
-
-        errno = 0;
-        l = strtoul(e, &p, 10);
-
-        if (errno != 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (!p || *p || l <= 0) {
-                r = -EINVAL;
-                goto finish;
-        }
-
-        /* Is this for us? */
-        if (getpid() != (pid_t) l) {
-                r = 0;
-                goto finish;
-        }
-
-        if (!(e = getenv("LISTEN_FDS"))) {
-                r = 0;
-                goto finish;
-        }
-
-        errno = 0;
-        l = strtoul(e, &p, 10);
-
-        if (errno != 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (!p || *p) {
-                r = -EINVAL;
-                goto finish;
-        }
-
-        r = (int) l;
-
-finish:
-        if (unset_environment) {
-                unsetenv("LISTEN_PID");
-                unsetenv("LISTEN_FDS");
-        }
-
-        return r;
-#endif
-}
diff --git a/sd-daemon.h b/sd-daemon.h
deleted file mode 100644
index c7f5c1d..0000000
--- a/sd-daemon.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foosddaemonhfoo
-#define foosddaemonhfoo
-
-/***
-  Copyright 2010 Lennart Poettering
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation files
-  (the "Software"), to deal in the Software without restriction,
-  including without limitation the rights to use, copy, modify, merge,
-  publish, distribute, sublicense, and/or sell copies of the Software,
-  and to permit persons to whom the Software is furnished to do so,
-  subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-  SOFTWARE.
-***/
-
-/* Reference implementation of a few systemd related interfaces for
- * writing daemons. These interfaces are trivial to implement, however
- * to simplify porting we provide this reference
- * implementation. Applications are free to reimplement the algorithms
- * described here. */
-
-/*
-  Log levels for usage on stderr:
-
-          fprintf(stderr, SD_NOTICE "Hello World!");
-
-  This is similar to printk() usage in the kernel.
-*/
-
-#define SD_EMERG   "<0>"  /* system is unusable */
-#define SD_ALERT   "<1>"  /* action must be taken immediately */
-#define SD_CRIT    "<2>"  /* critical conditions */
-#define SD_ERR     "<3>"  /* error conditions */
-#define SD_WARNING "<4>"  /* warning conditions */
-#define SD_NOTICE  "<5>"  /* normal but significant condition */
-#define SD_INFO    "<6>"  /* informational */
-#define SD_DEBUG   "<7>"  /* debug-level messages */
-
-/* The first passed file descriptor is fd 3 */
-#define SD_LISTEN_FDS_START 3
-
-/* Returns how many file descriptors have been passed, or a negative
- * errno code on failure. Optionally removes the $LISTEN_FDS and
- * $LISTEN_PID file descriptors from the environment (recommended). */
-int sd_listen_fds(int unset_environment);
-
-#endif
diff --git a/securebits.h b/securebits.h
deleted file mode 100644
index a5b99a3..0000000
--- a/securebits.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _LINUX_SECUREBITS_H
-#define _LINUX_SECUREBITS_H 1
-
-/* This is minimal version of Linux' linux/securebits.h header file,
- * which is licensed GPL2 */
-
-#define SECUREBITS_DEFAULT 0x00000000
-
-/* When set UID 0 has no special privileges. When unset, we support
-   inheritance of root-permissions and suid-root executable under
-   compatibility mode. We raise the effective and inheritable bitmasks
-   *of the executable file* if the effective uid of the new process is
-   0. If the real uid is 0, we raise the effective (legacy) bit of the
-   executable file. */
-#define SECURE_NOROOT			0
-#define SECURE_NOROOT_LOCKED		1  /* make bit-0 immutable */
-
-/* When set, setuid to/from uid 0 does not trigger capability-"fixup".
-   When unset, to provide compatiblility with old programs relying on
-   set*uid to gain/lose privilege, transitions to/from uid 0 cause
-   capabilities to be gained/lost. */
-#define SECURE_NO_SETUID_FIXUP		2
-#define SECURE_NO_SETUID_FIXUP_LOCKED	3  /* make bit-2 immutable */
-
-/* When set, a process can retain its capabilities even after
-   transitioning to a non-root user (the set-uid fixup suppressed by
-   bit 2). Bit-4 is cleared when a process calls exec(); setting both
-   bit 4 and 5 will create a barrier through exec that no exec()'d
-   child can use this feature again. */
-#define SECURE_KEEP_CAPS		4
-#define SECURE_KEEP_CAPS_LOCKED		5  /* make bit-4 immutable */
-
-/* Each securesetting is implemented using two bits. One bit specifies
-   whether the setting is on or off. The other bit specify whether the
-   setting is locked or not. A setting which is locked cannot be
-   changed from user-level. */
-#define issecure_mask(X)	(1 << (X))
-#define issecure(X)		(issecure_mask(X) & current_cred_xxx(securebits))
-
-#define SECURE_ALL_BITS		(issecure_mask(SECURE_NOROOT) | \
-				 issecure_mask(SECURE_NO_SETUID_FIXUP) | \
-				 issecure_mask(SECURE_KEEP_CAPS))
-#define SECURE_ALL_LOCKS	(SECURE_ALL_BITS << 1)
-
-#endif /* !_LINUX_SECUREBITS_H */
diff --git a/service.c b/service.c
deleted file mode 100644
index bf91561..0000000
--- a/service.c
+++ /dev/null
@@ -1,2463 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <signal.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "dbus-service.h"
-
-#define COMMENTS "#;\n"
-#define NEWLINES "\n\r"
-#define LINE_MAX 4096
-
-typedef enum RunlevelType {
-        RUNLEVEL_UP,
-        RUNLEVEL_DOWN,
-        RUNLEVEL_BASIC
-} RunlevelType;
-
-static const struct {
-        const char *path;
-        const char *target;
-        const RunlevelType type;
-} rcnd_table[] = {
-        /* Standard SysV runlevels */
-        { "rc0.d",  SPECIAL_RUNLEVEL0_TARGET, RUNLEVEL_DOWN },
-        { "rc1.d",  SPECIAL_RUNLEVEL1_TARGET, RUNLEVEL_UP },
-        { "rc2.d",  SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
-        { "rc3.d",  SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
-        { "rc4.d",  SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
-        { "rc5.d",  SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
-        { "rc6.d",  SPECIAL_RUNLEVEL6_TARGET, RUNLEVEL_DOWN },
-
-        /* SuSE style boot.d */
-        { "boot.d", SPECIAL_BASIC_TARGET,     RUNLEVEL_BASIC },
-
-        /* Debian style rcS.d */
-        { "rcS.d",  SPECIAL_BASIC_TARGET,     RUNLEVEL_BASIC },
-};
-
-#define RUNLEVELS_UP "12345"
-/* #define RUNLEVELS_DOWN "06" */
-/* #define RUNLEVELS_BOOT "bBsS" */
-
-static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
-        [SERVICE_DEAD] = UNIT_INACTIVE,
-        [SERVICE_START_PRE] = UNIT_ACTIVATING,
-        [SERVICE_START] = UNIT_ACTIVATING,
-        [SERVICE_START_POST] = UNIT_ACTIVATING,
-        [SERVICE_RUNNING] = UNIT_ACTIVE,
-        [SERVICE_EXITED] = UNIT_ACTIVE,
-        [SERVICE_RELOAD] = UNIT_ACTIVE_RELOADING,
-        [SERVICE_STOP] = UNIT_DEACTIVATING,
-        [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
-        [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
-        [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
-        [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
-        [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
-        [SERVICE_MAINTAINANCE] = UNIT_INACTIVE,
-        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
-};
-
-static void service_init(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        s->restart_usec = DEFAULT_RESTART_USEC;
-        s->timer_watch.type = WATCH_INVALID;
-        s->sysv_start_priority = -1;
-        s->socket_fd = -1;
-
-        exec_context_init(&s->exec_context);
-
-        RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
-
-        s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-}
-
-static void service_unwatch_control_pid(Service *s) {
-        assert(s);
-
-        if (s->control_pid <= 0)
-                return;
-
-        unit_unwatch_pid(UNIT(s), s->control_pid);
-        s->control_pid = 0;
-}
-
-static void service_unwatch_main_pid(Service *s) {
-        assert(s);
-
-        if (s->main_pid <= 0)
-                return;
-
-        unit_unwatch_pid(UNIT(s), s->main_pid);
-        s->main_pid = 0;
-}
-
-static void service_close_socket_fd(Service *s) {
-        assert(s);
-
-        if (s->socket_fd < 0)
-                return;
-
-        close_nointr_nofail(s->socket_fd);
-        s->socket_fd = -1;
-}
-
-static void service_done(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        free(s->pid_file);
-        s->pid_file = NULL;
-
-        free(s->sysv_path);
-        s->sysv_path = NULL;
-
-        free(s->sysv_runlevels);
-        s->sysv_runlevels = NULL;
-
-        exec_context_done(&s->exec_context);
-        exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
-        s->control_command = NULL;
-
-        /* This will leak a process, but at least no memory or any of
-         * our resources */
-        service_unwatch_main_pid(s);
-        service_unwatch_control_pid(s);
-
-        if (s->bus_name)  {
-                unit_unwatch_bus_name(UNIT(u), s->bus_name);
-                free(s->bus_name);
-                s->bus_name = NULL;
-        }
-
-        service_close_socket_fd(s);
-
-        unit_unwatch_timer(u, &s->timer_watch);
-}
-
-static int sysv_translate_name(const char *name, char **_r) {
-
-        static const char * const table[] = {
-                "$local_fs",  SPECIAL_LOCAL_FS_TARGET,
-                "$network",   SPECIAL_NETWORK_TARGET,
-                "$named",     SPECIAL_NSS_LOOKUP_TARGET,
-                "$portmap",   SPECIAL_RPCBIND_TARGET,
-                "$remote_fs", SPECIAL_REMOTE_FS_TARGET,
-                "$syslog",    SPECIAL_SYSLOG_TARGET,
-                "$time",      SPECIAL_RTC_SET_TARGET
-        };
-
-        unsigned i;
-        char *r;
-
-        for (i = 0; i < ELEMENTSOF(table); i += 2)
-                if (streq(table[i], name)) {
-                        if (!(r = strdup(table[i+1])))
-                                return -ENOMEM;
-
-                        goto finish;
-                }
-
-        if (*name == '$')
-                return 0;
-
-        if (asprintf(&r, "%s.service", name) < 0)
-                return -ENOMEM;
-
-finish:
-
-        if (_r)
-                *_r = r;
-
-        return 1;
-}
-
-static int sysv_chkconfig_order(Service *s) {
-        Meta *other;
-        int r;
-
-        assert(s);
-
-        if (s->sysv_start_priority < 0)
-                return 0;
-
-        /* For each pair of services where at least one lacks a LSB
-         * header, we use the start priority value to order things. */
-
-        LIST_FOREACH(units_per_type, other, UNIT(s)->meta.manager->units_per_type[UNIT_SERVICE]) {
-                Service *t;
-                UnitDependency d;
-
-                t = (Service*) other;
-
-                if (s == t)
-                        continue;
-
-                if (t->sysv_start_priority < 0)
-                        continue;
-
-                /* If both units have modern headers we don't care
-                 * about the priorities */
-                if ((!s->sysv_path || s->sysv_has_lsb) &&
-                    (!t->sysv_path || t->sysv_has_lsb))
-                        continue;
-
-                if (t->sysv_start_priority < s->sysv_start_priority)
-                        d = UNIT_AFTER;
-                else if (t->sysv_start_priority > s->sysv_start_priority)
-                        d = UNIT_BEFORE;
-                else
-                        continue;
-
-                /* FIXME: Maybe we should compare the name here lexicographically? */
-
-                if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static ExecCommand *exec_command_new(const char *path, const char *arg1) {
-        ExecCommand *c;
-
-        if (!(c = new0(ExecCommand, 1)))
-                return NULL;
-
-        if (!(c->path = strdup(path))) {
-                free(c);
-                return NULL;
-        }
-
-        if (!(c->argv = strv_new(path, arg1, NULL))) {
-                free(c->path);
-                free(c);
-                return NULL;
-        }
-
-        return c;
-}
-
-static int sysv_exec_commands(Service *s) {
-        ExecCommand *c;
-
-        assert(s);
-        assert(s->sysv_path);
-
-        if (!(c = exec_command_new(s->sysv_path, "start")))
-                return -ENOMEM;
-        exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c);
-
-        if (!(c = exec_command_new(s->sysv_path, "stop")))
-                return -ENOMEM;
-        exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c);
-
-        if (!(c = exec_command_new(s->sysv_path, "reload")))
-                return -ENOMEM;
-        exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c);
-
-        return 0;
-}
-
-static int service_load_sysv_path(Service *s, const char *path) {
-        FILE *f;
-        Unit *u;
-        unsigned line = 0;
-        int r;
-        enum {
-                NORMAL,
-                DESCRIPTION,
-                LSB,
-                LSB_DESCRIPTION
-        } state = NORMAL;
-
-        assert(s);
-        assert(path);
-
-        u = UNIT(s);
-
-        if (!(f = fopen(path, "re"))) {
-                r = errno == ENOENT ? 0 : -errno;
-                goto finish;
-        }
-
-        s->type = SERVICE_FORKING;
-        s->restart = SERVICE_ONCE;
-
-        free(s->sysv_path);
-        if (!(s->sysv_path = strdup(path))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        while (!feof(f)) {
-                char l[LINE_MAX], *t;
-
-                if (!fgets(l, sizeof(l), f)) {
-                        if (feof(f))
-                                break;
-
-                        r = -errno;
-                        log_error("Failed to read configuration file '%s': %s", path, strerror(-r));
-                        goto finish;
-                }
-
-                line++;
-
-                t = strstrip(l);
-                if (*t != '#')
-                        continue;
-
-                if (state == NORMAL && streq(t, "### BEGIN INIT INFO")) {
-                        state = LSB;
-                        s->sysv_has_lsb = true;
-                        continue;
-                }
-
-                if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) {
-                        state = NORMAL;
-                        continue;
-                }
-
-                t++;
-                t += strspn(t, WHITESPACE);
-
-                if (state == NORMAL) {
-
-                        /* Try to parse Red Hat style chkconfig headers */
-
-                        if (startswith(t, "chkconfig:")) {
-                                int start_priority;
-                                char runlevels[16], *k;
-
-                                state = NORMAL;
-
-                                if (sscanf(t+10, "%15s %i %*i",
-                                           runlevels,
-                                           &start_priority) != 2) {
-
-                                        log_warning("[%s:%u] Failed to parse chkconfig line. Ignoring.", path, line);
-                                        continue;
-                                }
-
-                                /* A start priority gathered from the
-                                 * symlink farms is preferred over the
-                                 * data from the LSB header. */
-                                if (start_priority < 0 || start_priority > 99)
-                                        log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line);
-                                else if (s->sysv_start_priority < 0)
-                                        s->sysv_start_priority = start_priority;
-
-                                char_array_0(runlevels);
-                                k = delete_chars(runlevels, WHITESPACE "-");
-
-                                if (k[0]) {
-                                        char *d;
-
-                                        if (!(d = strdup(k))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        free(s->sysv_runlevels);
-                                        s->sysv_runlevels = d;
-                                }
-
-                        } else if (startswith(t, "description:")) {
-
-                                size_t k = strlen(t);
-                                char *d;
-
-                                if (t[k-1] == '\\') {
-                                        state = DESCRIPTION;
-                                        t[k-1] = 0;
-                                }
-
-                                if (!(d = strdup(strstrip(t+12)))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                free(u->meta.description);
-                                u->meta.description = d;
-
-                        } else if (startswith(t, "pidfile:")) {
-
-                                char *fn;
-
-                                state = NORMAL;
-
-                                fn = strstrip(t+8);
-                                if (!path_is_absolute(fn)) {
-                                        log_warning("[%s:%u] PID file not absolute. Ignoring.", path, line);
-                                        continue;
-                                }
-
-                                if (!(fn = strdup(fn))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                free(s->pid_file);
-                                s->pid_file = fn;
-                        }
-
-                } else if (state == DESCRIPTION) {
-
-                        /* Try to parse Red Hat style description
-                         * continuation */
-
-                        size_t k = strlen(t);
-                        char *d;
-
-                        if (t[k-1] == '\\')
-                                t[k-1] = 0;
-                        else
-                                state = NORMAL;
-
-                        assert(u->meta.description);
-                        if (asprintf(&d, "%s %s", u->meta.description, strstrip(t)) < 0) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        free(u->meta.description);
-                        u->meta.description = d;
-
-                } else if (state == LSB || state == LSB_DESCRIPTION) {
-
-                        if (startswith(t, "Provides:")) {
-                                char *i, *w;
-                                size_t z;
-
-                                state = LSB;
-
-                                FOREACH_WORD(w, z, t+9, i) {
-                                        char *n, *m;
-
-                                        if (!(n = strndup(w, z))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        r = sysv_translate_name(n, &m);
-                                        free(n);
-
-                                        if (r < 0)
-                                                goto finish;
-
-                                        if (r == 0)
-                                                continue;
-
-                                        if (unit_name_to_type(m) == UNIT_SERVICE)
-                                                r = unit_add_name(u, m);
-                                        else {
-                                                if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m, NULL, true)) >= 0)
-                                                        r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true);
-                                        }
-
-                                        free(m);
-
-                                        if (r < 0)
-                                                goto finish;
-                                }
-
-                        } else if (startswith(t, "Required-Start:") ||
-                                   startswith(t, "Should-Start:")) {
-                                char *i, *w;
-                                size_t z;
-
-                                state = LSB;
-
-                                FOREACH_WORD(w, z, strchr(t, ':')+1, i) {
-                                        char *n, *m;
-
-                                        if (!(n = strndup(w, z))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        r = sysv_translate_name(n, &m);
-                                        free(n);
-
-                                        if (r < 0)
-                                                goto finish;
-
-                                        if (r == 0)
-                                                continue;
-
-                                        r = unit_add_dependency_by_name(u, UNIT_AFTER, m, NULL, true);
-                                        free(m);
-
-                                        if (r < 0)
-                                                goto finish;
-                                }
-                        } else if (startswith(t, "Default-Start:")) {
-                                char *k, *d;
-
-                                state = LSB;
-
-                                k = delete_chars(t+14, WHITESPACE "-");
-
-                                if (k[0] != 0) {
-                                        if (!(d = strdup(k))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        free(s->sysv_runlevels);
-                                        s->sysv_runlevels = d;
-                                }
-
-                        } else if (startswith(t, "Description:")) {
-                                char *d;
-
-                                state = LSB_DESCRIPTION;
-
-                                if (!(d = strdup(strstrip(t+12)))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                free(u->meta.description);
-                                u->meta.description = d;
-
-                        } else if (startswith(t, "Short-Description:") &&
-                                   !u->meta.description) {
-                                char *d;
-
-                                /* We use the short description only
-                                 * if no long description is set. */
-
-                                state = LSB;
-
-                                if (!(d = strdup(strstrip(t+18)))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                u->meta.description = d;
-
-                        } else if (state == LSB_DESCRIPTION) {
-
-                                if (startswith(l, "#\t") || startswith(l, "#  ")) {
-                                        char *d;
-
-                                        assert(u->meta.description);
-                                        if (asprintf(&d, "%s %s", u->meta.description, t) < 0) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        free(u->meta.description);
-                                        u->meta.description = d;
-                                } else
-                                        state = LSB;
-                        }
-                }
-        }
-
-        if ((r = sysv_exec_commands(s)) < 0)
-                goto finish;
-
-        if (!s->sysv_runlevels || chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
-                /* If there a runlevels configured for this service
-                 * but none of the standard ones, then we assume this
-                 * is some special kind of service (which might be
-                 * needed for early boot) and don't create any links
-                 * to it. */
-
-                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0 ||
-                    (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
-                        goto finish;
-
-        } else
-                /* Don't timeout special services during boot (like fsck) */
-                s->timeout_usec = 0;
-
-        /* Special setting for all SysV services */
-        s->valid_no_process = true;
-        s->kill_mode = KILL_PROCESS_GROUP;
-
-        u->meta.load_state = UNIT_LOADED;
-        r = 0;
-
-finish:
-
-        if (f)
-                fclose(f);
-
-        return r;
-}
-
-static int service_load_sysv_name(Service *s, const char *name) {
-        char **p;
-
-        assert(s);
-        assert(name);
-
-        STRV_FOREACH(p, UNIT(s)->meta.manager->sysvinit_path) {
-                char *path;
-                int r;
-
-                if (asprintf(&path, "%s/%s", *p, name) < 0)
-                        return -ENOMEM;
-
-                assert(endswith(path, ".service"));
-                path[strlen(path)-8] = 0;
-
-                r = service_load_sysv_path(s, path);
-
-                if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
-                        /* Try Debian style .sh source'able init scripts */
-                        strcat(path, ".sh");
-                        r = service_load_sysv_path(s, path);
-                }
-
-                free(path);
-
-                if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
-                        /* Try Suse style boot.xxxx init scripts */
-
-                        if (asprintf(&path, "%s/boot.%s", *p, name) < 0)
-                                return -ENOMEM;
-
-                        path[strlen(path)-8] = 0;
-                        r = service_load_sysv_path(s, path);
-                        free(path);
-                }
-
-                if (r < 0)
-                        return r;
-
-                if ((UNIT(s)->meta.load_state != UNIT_STUB))
-                        break;
-        }
-
-        return 0;
-}
-
-static int service_load_sysv(Service *s) {
-        const char *t;
-        Iterator i;
-        int r;
-
-        assert(s);
-
-        /* Load service data from SysV init scripts, preferably with
-         * LSB headers ... */
-
-        if (strv_isempty(UNIT(s)->meta.manager->sysvinit_path))
-                return 0;
-
-        if ((t = UNIT(s)->meta.id))
-                if ((r = service_load_sysv_name(s, t)) < 0)
-                        return r;
-
-        if (UNIT(s)->meta.load_state == UNIT_STUB)
-                SET_FOREACH(t, UNIT(s)->meta.names, i) {
-                        if (t == UNIT(s)->meta.id)
-                                continue;
-
-                        if ((r == service_load_sysv_name(s, t)) < 0)
-                                return r;
-
-                        if (UNIT(s)->meta.load_state != UNIT_STUB)
-                                break;
-                }
-
-        return 0;
-}
-
-static int service_add_bus_name(Service *s) {
-        char *n;
-        int r;
-
-        assert(s);
-        assert(s->bus_name);
-
-        if (asprintf(&n, "dbus-%s.service", s->bus_name) < 0)
-                return 0;
-
-        r = unit_merge_by_name(UNIT(s), n);
-        free(n);
-
-        return r;
-}
-
-static int service_verify(Service *s) {
-        assert(s);
-
-        if (UNIT(s)->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (!s->exec_command[SERVICE_EXEC_START]) {
-                log_error("%s lacks ExecStart setting. Refusing.", UNIT(s)->meta.id);
-                return -EINVAL;
-        }
-
-        if (s->type == SERVICE_DBUS && !s->bus_name) {
-                log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->meta.id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int service_load(Unit *u) {
-        int r;
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        /* Load a .service file */
-        if ((r = unit_load_fragment(u)) < 0)
-                return r;
-
-        /* Load a classic init script as a fallback, if we couldn't find anything */
-        if (u->meta.load_state == UNIT_STUB)
-                if ((r = service_load_sysv(s)) < 0)
-                        return r;
-
-        /* Still nothing found? Then let's give up */
-        if (u->meta.load_state == UNIT_STUB)
-                return -ENOENT;
-
-        /* We were able to load something, then let's add in the
-         * dropin directories. */
-        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
-                return r;
-
-        /* This is a new unit? Then let's add in some extras */
-        if (u->meta.load_state == UNIT_LOADED) {
-                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
-                        return r;
-
-                if ((r = unit_add_default_cgroup(u)) < 0)
-                        return r;
-
-                if ((r = sysv_chkconfig_order(s)) < 0)
-                        return r;
-
-                if (s->bus_name) {
-                        if ((r = service_add_bus_name(s)) < 0)
-                                return r;
-
-                        if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
-                            return r;
-                }
-        }
-
-        return service_verify(s);
-}
-
-static void service_dump(Unit *u, FILE *f, const char *prefix) {
-
-        ServiceExecCommand c;
-        Service *s = SERVICE(u);
-        const char *prefix2;
-        char *p2;
-
-        assert(s);
-
-        p2 = strappend(prefix, "\t");
-        prefix2 = p2 ? p2 : prefix;
-
-        fprintf(f,
-                "%sService State: %s\n"
-                "%sPermissionsStartOnly: %s\n"
-                "%sRootDirectoryStartOnly: %s\n"
-                "%sValidNoProcess: %s\n"
-                "%sKillMode: %s\n"
-                "%sType: %s\n",
-                prefix, service_state_to_string(s->state),
-                prefix, yes_no(s->permissions_start_only),
-                prefix, yes_no(s->root_directory_start_only),
-                prefix, yes_no(s->valid_no_process),
-                prefix, kill_mode_to_string(s->kill_mode),
-                prefix, service_type_to_string(s->type));
-
-        if (s->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %llu\n",
-                        prefix, (unsigned long long) s->control_pid);
-
-        if (s->main_pid > 0)
-                fprintf(f,
-                        "%sMain PID: %llu\n",
-                        prefix, (unsigned long long) s->main_pid);
-
-        if (s->pid_file)
-                fprintf(f,
-                        "%sPIDFile: %s\n",
-                        prefix, s->pid_file);
-
-        if (s->bus_name)
-                fprintf(f,
-                        "%sBusName: %s\n"
-                        "%sBus Name Good: %s\n",
-                        prefix, s->bus_name,
-                        prefix, yes_no(s->bus_name_good));
-
-        exec_context_dump(&s->exec_context, f, prefix);
-
-        for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) {
-
-                if (!s->exec_command[c])
-                        continue;
-
-                fprintf(f, "%s-> %s:\n",
-                        prefix, service_exec_command_to_string(c));
-
-                exec_command_dump_list(s->exec_command[c], f, prefix2);
-        }
-
-        if (s->sysv_path)
-                fprintf(f,
-                        "%sSysV Init Script Path: %s\n"
-                        "%sSysV Init Script has LSB Header: %s\n",
-                        prefix, s->sysv_path,
-                        prefix, yes_no(s->sysv_has_lsb));
-
-        if (s->sysv_start_priority >= 0)
-                fprintf(f,
-                        "%sSysVStartPriority: %i\n",
-                        prefix, s->sysv_start_priority);
-
-        if (s->sysv_runlevels)
-                fprintf(f, "%sSysVRunLevels: %s\n",
-                        prefix, s->sysv_runlevels);
-
-        free(p2);
-}
-
-static int service_load_pid_file(Service *s) {
-        char *k;
-        unsigned long p;
-        int r;
-
-        assert(s);
-
-        if (s->main_pid_known)
-                return 0;
-
-        assert(s->main_pid <= 0);
-
-        if (!s->pid_file)
-                return -ENOENT;
-
-        if ((r = read_one_line_file(s->pid_file, &k)) < 0)
-                return r;
-
-        if ((r = safe_atolu(k, &p)) < 0) {
-                free(k);
-                return r;
-        }
-
-        if ((unsigned long) (pid_t) p != p)
-                return -ERANGE;
-
-        if (kill((pid_t) p, 0) < 0 && errno != EPERM) {
-                log_warning("PID %llu read from file %s does not exist. Your service or init script might be broken.",
-                            (unsigned long long) p, s->pid_file);
-                return -ESRCH;
-        }
-
-        if ((r = unit_watch_pid(UNIT(s), (pid_t) p)) < 0)
-                /* FIXME: we need to do something here */
-                return r;
-
-        s->main_pid = (pid_t) p;
-        s->main_pid_known = true;
-
-        return 0;
-}
-
-static int service_get_sockets(Service *s, Set **_set) {
-        Set *set;
-        Iterator i;
-        char *t;
-        int r;
-
-        assert(s);
-        assert(_set);
-
-        /* Collects all Socket objects that belong to this
-         * service. Note that a service might have multiple sockets
-         * via multiple names. */
-
-        if (!(set = set_new(NULL, NULL)))
-                return -ENOMEM;
-
-        SET_FOREACH(t, UNIT(s)->meta.names, i) {
-                char *k;
-                Unit *p;
-
-                /* Look for all socket objects that go by any of our
-                 * units and collect their fds */
-
-                if (!(k = unit_name_change_suffix(t, ".socket"))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                p = manager_get_unit(UNIT(s)->meta.manager, k);
-                free(k);
-
-                if (!p)
-                        continue;
-
-                if ((r = set_put(set, p)) < 0)
-                        goto fail;
-        }
-
-        *_set = set;
-        return 0;
-
-fail:
-        set_free(set);
-        return r;
-}
-
-static int service_notify_sockets_dead(Service *s) {
-        Iterator i;
-        Set *set;
-        Socket *sock;
-        int r;
-
-        assert(s);
-
-        /* Notifies all our sockets when we die */
-        if ((r = service_get_sockets(s, &set)) < 0)
-                return r;
-
-        SET_FOREACH(sock, set, i)
-                socket_notify_service_dead(sock);
-
-        set_free(set);
-
-        return 0;
-}
-
-static void service_set_state(Service *s, ServiceState state) {
-        ServiceState old_state;
-        assert(s);
-
-        old_state = s->state;
-        s->state = state;
-
-        if (state != SERVICE_START_PRE &&
-            state != SERVICE_START &&
-            state != SERVICE_START_POST &&
-            state != SERVICE_RELOAD &&
-            state != SERVICE_STOP &&
-            state != SERVICE_STOP_SIGTERM &&
-            state != SERVICE_STOP_SIGKILL &&
-            state != SERVICE_STOP_POST &&
-            state != SERVICE_FINAL_SIGTERM &&
-            state != SERVICE_FINAL_SIGKILL &&
-            state != SERVICE_AUTO_RESTART)
-                unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
-        if (state != SERVICE_START &&
-            state != SERVICE_START_POST &&
-            state != SERVICE_RUNNING &&
-            state != SERVICE_RELOAD &&
-            state != SERVICE_STOP &&
-            state != SERVICE_STOP_SIGTERM &&
-            state != SERVICE_STOP_SIGKILL)
-                service_unwatch_main_pid(s);
-
-        if (state != SERVICE_START_PRE &&
-            state != SERVICE_START &&
-            state != SERVICE_START_POST &&
-            state != SERVICE_RELOAD &&
-            state != SERVICE_STOP &&
-            state != SERVICE_STOP_SIGTERM &&
-            state != SERVICE_STOP_SIGKILL &&
-            state != SERVICE_STOP_POST &&
-            state != SERVICE_FINAL_SIGTERM &&
-            state != SERVICE_FINAL_SIGKILL) {
-                service_unwatch_control_pid(s);
-                s->control_command = NULL;
-                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-        }
-
-        if (state == SERVICE_DEAD ||
-            state == SERVICE_STOP ||
-            state == SERVICE_STOP_SIGTERM ||
-            state == SERVICE_STOP_SIGKILL ||
-            state == SERVICE_STOP_POST ||
-            state == SERVICE_FINAL_SIGTERM ||
-            state == SERVICE_FINAL_SIGKILL ||
-            state == SERVICE_MAINTAINANCE ||
-            state == SERVICE_AUTO_RESTART)
-                service_notify_sockets_dead(s);
-
-        if (state != SERVICE_START_PRE &&
-            state != SERVICE_START &&
-            !(state == SERVICE_DEAD && UNIT(s)->meta.job))
-                service_close_socket_fd(s);
-
-        if (old_state != state)
-                log_debug("%s changed %s -> %s", UNIT(s)->meta.id, service_state_to_string(old_state), service_state_to_string(state));
-
-        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int service_coldplug(Unit *u) {
-        Service *s = SERVICE(u);
-        int r;
-
-        assert(s);
-        assert(s->state == SERVICE_DEAD);
-
-        if (s->deserialized_state != s->state) {
-
-                if (s->deserialized_state == SERVICE_START_PRE ||
-                    s->deserialized_state == SERVICE_START ||
-                    s->deserialized_state == SERVICE_START_POST ||
-                    s->deserialized_state == SERVICE_RELOAD ||
-                    s->deserialized_state == SERVICE_STOP ||
-                    s->deserialized_state == SERVICE_STOP_SIGTERM ||
-                    s->deserialized_state == SERVICE_STOP_SIGKILL ||
-                    s->deserialized_state == SERVICE_STOP_POST ||
-                    s->deserialized_state == SERVICE_FINAL_SIGTERM ||
-                    s->deserialized_state == SERVICE_FINAL_SIGKILL ||
-                    s->deserialized_state == SERVICE_AUTO_RESTART) {
-
-                        if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) {
-                                usec_t k;
-
-                                k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec;
-
-                                if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0)
-                                        return r;
-                        }
-                }
-
-                if ((s->deserialized_state == SERVICE_START &&
-                     (s->type == SERVICE_FORKING ||
-                      s->type == SERVICE_DBUS)) ||
-                    s->deserialized_state == SERVICE_START_POST ||
-                    s->deserialized_state == SERVICE_RUNNING ||
-                    s->deserialized_state == SERVICE_RELOAD ||
-                    s->deserialized_state == SERVICE_STOP ||
-                    s->deserialized_state == SERVICE_STOP_SIGTERM ||
-                    s->deserialized_state == SERVICE_STOP_SIGKILL)
-                        if (s->main_pid > 0)
-                                if ((r = unit_watch_pid(UNIT(s), s->main_pid)) < 0)
-                                        return r;
-
-                if (s->deserialized_state == SERVICE_START_PRE ||
-                    s->deserialized_state == SERVICE_START ||
-                    s->deserialized_state == SERVICE_START_POST ||
-                    s->deserialized_state == SERVICE_RELOAD ||
-                    s->deserialized_state == SERVICE_STOP ||
-                    s->deserialized_state == SERVICE_STOP_SIGTERM ||
-                    s->deserialized_state == SERVICE_STOP_SIGKILL ||
-                    s->deserialized_state == SERVICE_STOP_POST ||
-                    s->deserialized_state == SERVICE_FINAL_SIGTERM ||
-                    s->deserialized_state == SERVICE_FINAL_SIGKILL)
-                        if (s->control_pid > 0)
-                                if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
-                                        return r;
-
-                service_set_state(s, s->deserialized_state);
-        }
-
-        return 0;
-}
-
-static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
-        Iterator i;
-        int r;
-        int *rfds = NULL;
-        unsigned rn_fds = 0;
-        Set *set;
-        Socket *sock;
-
-        assert(s);
-        assert(fds);
-        assert(n_fds);
-
-        if ((r = service_get_sockets(s, &set)) < 0)
-                return r;
-
-        SET_FOREACH(sock, set, i) {
-                int *cfds;
-                unsigned cn_fds;
-
-                if ((r = socket_collect_fds(sock, &cfds, &cn_fds)) < 0)
-                        goto fail;
-
-                if (!cfds)
-                        continue;
-
-                if (!rfds) {
-                        rfds = cfds;
-                        rn_fds = cn_fds;
-                } else {
-                        int *t;
-
-                        if (!(t = new(int, rn_fds+cn_fds))) {
-                                free(cfds);
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        memcpy(t, rfds, rn_fds);
-                        memcpy(t+rn_fds, cfds, cn_fds);
-                        free(rfds);
-                        free(cfds);
-
-                        rfds = t;
-                        rn_fds = rn_fds+cn_fds;
-                }
-        }
-
-        *fds = rfds;
-        *n_fds = rn_fds;
-
-        set_free(set);
-
-        return 0;
-
-fail:
-        set_free(set);
-        free(rfds);
-
-        return r;
-}
-
-static int service_spawn(
-                Service *s,
-                ExecCommand *c,
-                bool timeout,
-                bool pass_fds,
-                bool apply_permissions,
-                bool apply_chroot,
-                pid_t *_pid) {
-
-        pid_t pid;
-        int r;
-        int *fds = NULL;
-        unsigned n_fds = 0;
-        char **argv;
-
-        assert(s);
-        assert(c);
-        assert(_pid);
-
-        if (pass_fds) {
-                if (s->socket_fd >= 0) {
-                        fds = &s->socket_fd;
-                        n_fds = 1;
-                } else if ((r = service_collect_fds(s, &fds, &n_fds)) < 0)
-                        goto fail;
-        }
-
-        if (timeout && s->timeout_usec) {
-                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                        goto fail;
-        } else
-                unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
-        if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        r = exec_spawn(c,
-                       argv,
-                       &s->exec_context,
-                       fds, n_fds,
-                       s->meta.manager->environment,
-                       apply_permissions,
-                       apply_chroot,
-                       UNIT(s)->meta.manager->confirm_spawn,
-                       UNIT(s)->meta.cgroup_bondings,
-                       &pid);
-
-        strv_free(argv);
-        if (r < 0)
-                goto fail;
-
-        if (fds) {
-                if (s->socket_fd >= 0)
-                        service_close_socket_fd(s);
-                else
-                        free(fds);
-        }
-
-        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
-                /* FIXME: we need to do something here */
-                goto fail;
-
-        *_pid = pid;
-
-        return 0;
-
-fail:
-        free(fds);
-
-        if (timeout)
-                unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
-        return r;
-}
-
-static int main_pid_good(Service *s) {
-        assert(s);
-
-        /* Returns 0 if the pid is dead, 1 if it is good, -1 if we
-         * don't know */
-
-        /* If we know the pid file, then lets just check if it is
-         * still valid */
-        if (s->main_pid_known)
-                return s->main_pid > 0;
-
-        /* We don't know the pid */
-        return -EAGAIN;
-}
-
-static int control_pid_good(Service *s) {
-        assert(s);
-
-        return s->control_pid > 0;
-}
-
-static int cgroup_good(Service *s) {
-        int r;
-
-        assert(s);
-
-        if (s->valid_no_process)
-                return -EAGAIN;
-
-        if ((r = cgroup_bonding_is_empty_list(UNIT(s)->meta.cgroup_bondings)) < 0)
-                return r;
-
-        return !r;
-}
-
-static void service_enter_dead(Service *s, bool success, bool allow_restart) {
-        int r;
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        if (allow_restart &&
-            s->allow_restart &&
-            (s->restart == SERVICE_RESTART_ALWAYS ||
-             (s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure))) {
-
-                if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_AUTO_RESTART);
-        } else
-                service_set_state(s, s->failure ? SERVICE_MAINTAINANCE : SERVICE_DEAD);
-
-        return;
-
-fail:
-        log_warning("%s failed to run install restart timer: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_dead(s, false, false);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, bool success);
-
-static void service_enter_stop_post(Service *s, bool success) {
-        int r;
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        service_unwatch_control_pid(s);
-
-        s->control_command_id = SERVICE_EXEC_STOP_POST;
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-
-                service_set_state(s, SERVICE_STOP_POST);
-        } else
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to run stop-post executable: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, bool success) {
-        int r;
-        bool sent = false;
-
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        if (s->kill_mode != KILL_NONE) {
-                int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
-
-                if (s->kill_mode == KILL_CONTROL_GROUP) {
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH)
-                                        goto fail;
-                        } else
-                                sent = true;
-                }
-
-                if (!sent) {
-                        r = 0;
-
-                        if (s->main_pid > 0) {
-                                if (kill(s->kill_mode == KILL_PROCESS ? s->main_pid : -s->main_pid, sig) < 0 && errno != ESRCH)
-                                        r = -errno;
-                                else
-                                        sent = true;
-                        }
-
-                        if (s->control_pid > 0) {
-                                if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH)
-                                        r = -errno;
-                                else
-                                        sent = true;
-                        }
-
-                        if (r < 0)
-                                goto fail;
-                }
-        }
-
-        if (sent && (s->main_pid > 0 || s->control_pid > 0)) {
-                if (s->timeout_usec > 0)
-                        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                                goto fail;
-
-                service_set_state(s, state);
-        } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
-                service_enter_stop_post(s, true);
-        else
-                service_enter_dead(s, true, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", UNIT(s)->meta.id, strerror(-r));
-
-        if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
-                service_enter_stop_post(s, false);
-        else
-                service_enter_dead(s, false, true);
-}
-
-static void service_enter_stop(Service *s, bool success) {
-        int r;
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        service_unwatch_control_pid(s);
-
-        s->control_command_id = SERVICE_EXEC_STOP;
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_STOP);
-        } else
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to run stop executable: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
-}
-
-static void service_enter_running(Service *s, bool success) {
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        if (main_pid_good(s) != 0 &&
-            cgroup_good(s) != 0 &&
-            (s->bus_name_good || s->type != SERVICE_DBUS))
-                service_set_state(s, SERVICE_RUNNING);
-        else if (s->valid_no_process)
-                service_set_state(s, SERVICE_EXITED);
-        else
-                service_enter_stop(s, true);
-}
-
-static void service_enter_start_post(Service *s) {
-        int r;
-        assert(s);
-
-        service_unwatch_control_pid(s);
-
-        s->control_command_id = SERVICE_EXEC_START_POST;
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-
-                service_set_state(s, SERVICE_START_POST);
-        } else
-                service_enter_running(s, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to run start-post executable: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_stop(s, false);
-}
-
-static void service_enter_start(Service *s) {
-        pid_t pid;
-        int r;
-
-        assert(s);
-
-        assert(s->exec_command[SERVICE_EXEC_START]);
-        assert(!s->exec_command[SERVICE_EXEC_START]->command_next);
-
-        if (s->type == SERVICE_FORKING)
-                service_unwatch_control_pid(s);
-        else
-                service_unwatch_main_pid(s);
-
-        if ((r = service_spawn(s,
-                               s->exec_command[SERVICE_EXEC_START],
-                               s->type == SERVICE_FORKING || s->type == SERVICE_DBUS,
-                               true,
-                               true,
-                               true,
-                               &pid)) < 0)
-                goto fail;
-
-        if (s->type == SERVICE_SIMPLE) {
-                /* For simple services we immediately start
-                 * the START_POST binaries. */
-
-                s->main_pid = pid;
-                s->main_pid_known = true;
-
-                service_enter_start_post(s);
-
-        } else  if (s->type == SERVICE_FORKING) {
-
-                /* For forking services we wait until the start
-                 * process exited. */
-
-                s->control_pid = pid;
-
-                s->control_command_id = SERVICE_EXEC_START;
-                s->control_command = s->exec_command[SERVICE_EXEC_START];
-                service_set_state(s, SERVICE_START);
-
-        } else if (s->type == SERVICE_FINISH ||
-                   s->type == SERVICE_DBUS) {
-
-                /* For finishing services we wait until the start
-                 * process exited, too, but it is our main process. */
-
-                /* For D-Bus services we know the main pid right away,
-                 * but wait for the bus name to appear on the bus. */
-
-                s->main_pid = pid;
-                s->main_pid_known = true;
-
-                service_set_state(s, SERVICE_START);
-        } else
-                assert_not_reached("Unknown service type");
-
-        return;
-
-fail:
-        log_warning("%s failed to run start exectuable: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-}
-
-static void service_enter_start_pre(Service *s) {
-        int r;
-
-        assert(s);
-
-        service_unwatch_control_pid(s);
-
-        s->control_command_id = SERVICE_EXEC_START_PRE;
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_START_PRE);
-        } else
-                service_enter_start(s);
-
-        return;
-
-fail:
-        log_warning("%s failed to run start-pre executable: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_dead(s, false, true);
-}
-
-static void service_enter_restart(Service *s) {
-        int r;
-        assert(s);
-
-        service_enter_dead(s, true, false);
-
-        if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s), JOB_FAIL, false, NULL)) < 0)
-                goto fail;
-
-        log_debug("%s scheduled restart job.", UNIT(s)->meta.id);
-        return;
-
-fail:
-
-        log_warning("%s failed to schedule restart job: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_dead(s, false, false);
-}
-
-static void service_enter_reload(Service *s) {
-        int r;
-
-        assert(s);
-
-        service_unwatch_control_pid(s);
-
-        s->control_command_id = SERVICE_EXEC_RELOAD;
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_RELOAD);
-        } else
-                service_enter_running(s, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to run reload executable: %s", UNIT(s)->meta.id, strerror(-r));
-        service_enter_stop(s, false);
-}
-
-static void service_run_next(Service *s, bool success) {
-        int r;
-
-        assert(s);
-        assert(s->control_command);
-        assert(s->control_command->command_next);
-
-        if (!success)
-                s->failure = true;
-
-        s->control_command = s->control_command->command_next;
-
-        service_unwatch_control_pid(s);
-
-        if ((r = service_spawn(s,
-                               s->control_command,
-                               true,
-                               false,
-                               !s->permissions_start_only,
-                               !s->root_directory_start_only,
-                               &s->control_pid)) < 0)
-                goto fail;
-
-        return;
-
-fail:
-        log_warning("%s failed to run spawn next executable: %s", UNIT(s)->meta.id, strerror(-r));
-
-        if (s->state == SERVICE_START_PRE)
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-        else if (s->state == SERVICE_STOP)
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
-        else if (s->state == SERVICE_STOP_POST)
-                service_enter_dead(s, false, true);
-        else
-                service_enter_stop(s, false);
-}
-
-static int service_start(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        /* We cannot fulfill this request right now, try again later
-         * please! */
-        if (s->state == SERVICE_STOP ||
-            s->state == SERVICE_STOP_SIGTERM ||
-            s->state == SERVICE_STOP_SIGKILL ||
-            s->state == SERVICE_STOP_POST ||
-            s->state == SERVICE_FINAL_SIGTERM ||
-            s->state == SERVICE_FINAL_SIGKILL)
-                return -EAGAIN;
-
-        /* Already on it! */
-        if (s->state == SERVICE_START_PRE ||
-            s->state == SERVICE_START ||
-            s->state == SERVICE_START_POST)
-                return 0;
-
-        assert(s->state == SERVICE_DEAD || s->state == SERVICE_MAINTAINANCE || s->state == SERVICE_AUTO_RESTART);
-
-        /* Make sure we don't enter a busy loop of some kind. */
-        if (!ratelimit_test(&s->ratelimit)) {
-                log_warning("%s start request repeated too quickly, refusing to start.", u->meta.id);
-                return -EAGAIN;
-        }
-
-        s->failure = false;
-        s->main_pid_known = false;
-        s->allow_restart = true;
-
-        service_enter_start_pre(s);
-        return 0;
-}
-
-static int service_stop(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        /* Cannot do this now */
-        if (s->state == SERVICE_START_PRE ||
-            s->state == SERVICE_START ||
-            s->state == SERVICE_START_POST ||
-            s->state == SERVICE_RELOAD)
-                return -EAGAIN;
-
-        /* Already on it */
-        if (s->state == SERVICE_STOP ||
-            s->state == SERVICE_STOP_SIGTERM ||
-            s->state == SERVICE_STOP_SIGKILL ||
-            s->state == SERVICE_STOP_POST ||
-            s->state == SERVICE_FINAL_SIGTERM ||
-            s->state == SERVICE_FINAL_SIGKILL)
-                return 0;
-
-        if (s->state == SERVICE_AUTO_RESTART) {
-                service_set_state(s, SERVICE_DEAD);
-                return 0;
-        }
-
-        assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
-
-        /* This is a user request, so don't do restarts on this
-         * shutdown. */
-        s->allow_restart = false;
-
-        service_enter_stop(s, true);
-        return 0;
-}
-
-static int service_reload(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
-
-        service_enter_reload(s);
-        return 0;
-}
-
-static bool service_can_reload(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return !!s->exec_command[SERVICE_EXEC_RELOAD];
-}
-
-static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Service *s = SERVICE(u);
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", service_state_to_string(s->state));
-        unit_serialize_item(u, f, "failure", yes_no(s->failure));
-
-        if (s->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) (s->control_pid));
-
-        if (s->main_pid > 0)
-                unit_serialize_item_format(u, f, "main-pid", "%u", (unsigned) (s->main_pid));
-
-        unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
-
-        /* There's a minor uncleanliness here: if there are multiple
-         * commands attached here, we will start from the first one
-         * again */
-        if (s->control_command_id >= 0)
-                unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
-
-        if (s->socket_fd >= 0) {
-                int copy;
-
-                if ((copy = fdset_put_dup(fds, s->socket_fd)) < 0)
-                        return copy;
-
-                unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
-        }
-
-        return 0;
-}
-
-static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Service *s = SERVICE(u);
-        int r;
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                ServiceState state;
-
-                if ((state = service_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        s->deserialized_state = state;
-        } else if (streq(key, "failure")) {
-                int b;
-
-                if ((b = parse_boolean(value)) < 0)
-                        log_debug("Failed to parse failure value %s", value);
-                else
-                        s->failure = b || s->failure;
-        } else if (streq(key, "control-pid")) {
-                unsigned pid;
-
-                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        s->control_pid = (pid_t) pid;
-        } else if (streq(key, "main-pid")) {
-                unsigned pid;
-
-                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
-                        log_debug("Failed to parse main-pid value %s", value);
-                else
-                        s->main_pid = (pid_t) pid;
-        } else if (streq(key, "main-pid-known")) {
-                int b;
-
-                if ((b = parse_boolean(value)) < 0)
-                        log_debug("Failed to parse main-pid-known value %s", value);
-                else
-                        s->main_pid_known = b;
-        } else if (streq(key, "control-command")) {
-                ServiceExecCommand id;
-
-                if ((id = service_exec_command_from_string(value)) < 0)
-                        log_debug("Failed to parse exec-command value %s", value);
-                else {
-                        s->control_command_id = id;
-                        s->control_command = s->exec_command[id];
-                }
-        } else if (streq(key, "socket-fd")) {
-                int fd;
-
-                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
-                        log_debug("Failed to parse socket-fd value %s", value);
-                else {
-
-                        if (s->socket_fd >= 0)
-                                close_nointr_nofail(s->socket_fd);
-                        s->socket_fd = fdset_remove(fds, fd);
-                }
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState service_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[SERVICE(u)->state];
-}
-
-static const char *service_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return service_state_to_string(SERVICE(u)->state);
-}
-
-static bool service_check_gc(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return !!s->sysv_path;
-}
-
-static bool service_check_snapshot(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return !s->got_socket_fd;
-}
-
-static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-        Service *s = SERVICE(u);
-        bool success;
-
-        assert(s);
-        assert(pid >= 0);
-
-        success = is_clean_exit(code, status);
-        s->failure = s->failure || !success;
-
-        if (s->main_pid == pid) {
-
-                exec_status_fill(&s->main_exec_status, pid, code, status);
-                s->main_pid = 0;
-
-                if (s->type == SERVICE_SIMPLE || s->type == SERVICE_FINISH) {
-                        assert(s->exec_command[SERVICE_EXEC_START]);
-                        s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status;
-                }
-
-                log_debug("%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
-
-                /* The service exited, so the service is officially
-                 * gone. */
-
-                switch (s->state) {
-
-                case SERVICE_START_POST:
-                case SERVICE_RELOAD:
-                case SERVICE_STOP:
-                        /* Need to wait until the operation is
-                         * done */
-                        break;
-
-                case SERVICE_START:
-                        assert(s->type == SERVICE_FINISH);
-
-                        /* This was our main goal, so let's go on */
-                        if (success)
-                                service_enter_start_post(s);
-                        else
-                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-                        break;
-
-                case SERVICE_RUNNING:
-                        service_enter_running(s, success);
-                        break;
-
-                case SERVICE_STOP_SIGTERM:
-                case SERVICE_STOP_SIGKILL:
-
-                        if (!control_pid_good(s))
-                                service_enter_stop_post(s, success);
-
-                        /* If there is still a control process, wait for that first */
-                        break;
-
-                default:
-                        assert_not_reached("Uh, main process died at wrong time.");
-                }
-
-        } else if (s->control_pid == pid) {
-
-                if (s->control_command)
-                        exec_status_fill(&s->control_command->exec_status, pid, code, status);
-
-                s->control_pid = 0;
-
-                log_debug("%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
-
-                /* If we are shutting things down anyway we
-                 * don't care about failing commands. */
-
-                if (s->control_command && s->control_command->command_next && success) {
-
-                        /* There is another command to *
-                         * execute, so let's do that. */
-
-                        log_debug("%s running next command for state %s", u->meta.id, service_state_to_string(s->state));
-                        service_run_next(s, success);
-
-                } else {
-                        /* No further commands for this step, so let's
-                         * figure out what to do next */
-
-                        s->control_command = NULL;
-                        s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-
-                        log_debug("%s got final SIGCHLD for state %s", u->meta.id, service_state_to_string(s->state));
-
-                        switch (s->state) {
-
-                        case SERVICE_START_PRE:
-                                if (success)
-                                        service_enter_start(s);
-                                else
-                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-                                break;
-
-                        case SERVICE_START:
-                                assert(s->type == SERVICE_FORKING);
-
-                                /* Let's try to load the pid
-                                 * file here if we can. We
-                                 * ignore the return value,
-                                 * since the PID file might
-                                 * actually be created by a
-                                 * START_POST script */
-
-                                if (success) {
-                                        if (s->pid_file)
-                                                service_load_pid_file(s);
-
-                                        service_enter_start_post(s);
-                                } else
-                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-
-                                break;
-
-                        case SERVICE_START_POST:
-                                if (success && s->pid_file && !s->main_pid_known) {
-                                        int r;
-
-                                        /* Hmm, let's see if we can
-                                         * load the pid now after the
-                                         * start-post scripts got
-                                         * executed. */
-
-                                        if ((r = service_load_pid_file(s)) < 0)
-                                                log_warning("%s: failed to load PID file %s: %s", UNIT(s)->meta.id, s->pid_file, strerror(-r));
-                                }
-
-                                /* Fall through */
-
-                        case SERVICE_RELOAD:
-                                if (success)
-                                        service_enter_running(s, true);
-                                else
-                                        service_enter_stop(s, false);
-
-                                break;
-
-                        case SERVICE_STOP:
-                                service_enter_signal(s, SERVICE_STOP_SIGTERM, success);
-                                break;
-
-                        case SERVICE_STOP_SIGTERM:
-                        case SERVICE_STOP_SIGKILL:
-                                if (main_pid_good(s) <= 0)
-                                        service_enter_stop_post(s, success);
-
-                                /* If there is still a service
-                                 * process around, wait until
-                                 * that one quit, too */
-                                break;
-
-                        case SERVICE_STOP_POST:
-                        case SERVICE_FINAL_SIGTERM:
-                        case SERVICE_FINAL_SIGKILL:
-                                service_enter_dead(s, success, true);
-                                break;
-
-                        default:
-                                assert_not_reached("Uh, control process died at wrong time.");
-                        }
-                }
-        } else
-                assert_not_reached("Got SIGCHLD for unkown PID");
-}
-
-static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-        assert(elapsed == 1);
-
-        assert(w == &s->timer_watch);
-
-        switch (s->state) {
-
-        case SERVICE_START_PRE:
-        case SERVICE_START:
-                log_warning("%s operation timed out. Terminating.", u->meta.id);
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-                break;
-
-        case SERVICE_START_POST:
-        case SERVICE_RELOAD:
-                log_warning("%s operation timed out. Stopping.", u->meta.id);
-                service_enter_stop(s, false);
-                break;
-
-        case SERVICE_STOP:
-                log_warning("%s stopping timed out. Terminating.", u->meta.id);
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
-                break;
-
-        case SERVICE_STOP_SIGTERM:
-                log_warning("%s stopping timed out. Killing.", u->meta.id);
-                service_enter_signal(s, SERVICE_STOP_SIGKILL, false);
-                break;
-
-        case SERVICE_STOP_SIGKILL:
-                /* Uh, wie sent a SIGKILL and it is still not gone?
-                 * Must be something we cannot kill, so let's just be
-                 * weirded out and continue */
-
-                log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id);
-                service_enter_stop_post(s, false);
-                break;
-
-        case SERVICE_STOP_POST:
-                log_warning("%s stopping timed out (2). Terminating.", u->meta.id);
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
-                break;
-
-        case SERVICE_FINAL_SIGTERM:
-                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
-                service_enter_signal(s, SERVICE_FINAL_SIGKILL, false);
-                break;
-
-        case SERVICE_FINAL_SIGKILL:
-                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", u->meta.id);
-                service_enter_dead(s, false, true);
-                break;
-
-        case SERVICE_AUTO_RESTART:
-                log_debug("%s holdoff time over, scheduling restart.", u->meta.id);
-                service_enter_restart(s);
-                break;
-
-        default:
-                assert_not_reached("Timeout at wrong time.");
-        }
-}
-
-static void service_cgroup_notify_event(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(u);
-
-        log_debug("%s: cgroup is empty", u->meta.id);
-
-        switch (s->state) {
-
-                /* Waiting for SIGCHLD is usually more interesting,
-                 * because it includes return codes/signals. Which is
-                 * why we ignore the cgroup events for most cases,
-                 * except when we don't know pid which to expect the
-                 * SIGCHLD for. */
-
-        case SERVICE_RUNNING:
-                service_enter_running(s, true);
-                break;
-
-        default:
-                ;
-        }
-}
-
-static int service_enumerate(Manager *m) {
-        char **p;
-        unsigned i;
-        DIR *d = NULL;
-        char *path = NULL, *fpath = NULL, *name = NULL;
-        int r;
-
-        assert(m);
-
-        STRV_FOREACH(p, m->sysvrcnd_path)
-                for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
-                        struct dirent *de;
-
-                        free(path);
-                        path = NULL;
-                        if (asprintf(&path, "%s/%s", *p, rcnd_table[i].path) < 0) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (d)
-                                closedir(d);
-
-                        if (!(d = opendir(path))) {
-                                if (errno != ENOENT)
-                                        log_warning("opendir() failed on %s: %s", path, strerror(errno));
-
-                                continue;
-                        }
-
-                        while ((de = readdir(d))) {
-                                Unit *service;
-                                int a, b;
-
-                                if (ignore_file(de->d_name))
-                                        continue;
-
-                                if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
-                                        continue;
-
-                                if (strlen(de->d_name) < 4)
-                                        continue;
-
-                                a = undecchar(de->d_name[1]);
-                                b = undecchar(de->d_name[2]);
-
-                                if (a < 0 || b < 0)
-                                        continue;
-
-                                free(fpath);
-                                fpath = NULL;
-                                if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i].path, de->d_name) < 0) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                if (access(fpath, X_OK) < 0) {
-
-                                        if (errno != ENOENT)
-                                                log_warning("access() failed on %s: %s", fpath, strerror(errno));
-
-                                        continue;
-                                }
-
-                                free(name);
-                                if (!(name = new(char, strlen(de->d_name) - 3 + 8 + 1))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                if (startswith(de->d_name+3, "boot."))
-                                        /* Drop SuSE-style boot. prefix */
-                                        strcpy(stpcpy(name, de->d_name + 3 + 5), ".service");
-                                else if (endswith(de->d_name+3, ".sh"))
-                                        /* Drop Debian-style .sh suffix */
-                                        strcpy(stpcpy(name, de->d_name + 3) - 3, ".service");
-                                else
-                                        /* Normal init scripts */
-                                        strcpy(stpcpy(name, de->d_name + 3), ".service");
-
-                                if ((r = manager_load_unit_prepare(m, name, NULL, &service)) < 0) {
-                                        log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
-                                        continue;
-                                }
-
-                                if (de->d_name[0] == 'S' &&
-                                    (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_BASIC))
-                                        SERVICE(service)->sysv_start_priority =
-                                                MAX(a*10 + b, SERVICE(service)->sysv_start_priority);
-
-                                manager_dispatch_load_queue(m);
-                                service = unit_follow_merge(service);
-
-                                if (de->d_name[0] == 'S') {
-                                        Unit *runlevel_target;
-
-                                        if ((r = manager_load_unit(m, rcnd_table[i].target, NULL, &runlevel_target)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(runlevel_target, UNIT_WANTS, service, true)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(service, UNIT_BEFORE, runlevel_target, true)) < 0)
-                                                goto finish;
-
-                                } else if (de->d_name[0] == 'K' && rcnd_table[i].type == RUNLEVEL_DOWN) {
-                                        Unit *shutdown_target;
-
-                                        /* We honour K links only for
-                                         * halt/reboot. For the normal
-                                         * runlevels we assume the
-                                         * stop jobs will be
-                                         * implicitly added by the
-                                         * core logic. Also, we don't
-                                         * really distuingish here
-                                         * between the runlevels 0 and
-                                         * 6 and just add them to the
-                                         * special shutdown target. */
-
-                                        if ((r = manager_load_unit(m, SPECIAL_SHUTDOWN_TARGET, NULL, &shutdown_target)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(service, UNIT_CONFLICTS, shutdown_target, true)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(service, UNIT_BEFORE, shutdown_target, true)) < 0)
-                                                goto finish;
-                                }
-                        }
-                }
-
-        r = 0;
-
-finish:
-        free(path);
-        free(fpath);
-        free(name);
-
-        if (d)
-                closedir(d);
-
-        return r;
-}
-
-static void service_bus_name_owner_change(
-                Unit *u,
-                const char *name,
-                const char *old_owner,
-                const char *new_owner) {
-
-        Service *s = SERVICE(u);
-
-        assert(s);
-        assert(name);
-
-        assert(streq(s->bus_name, name));
-        assert(old_owner || new_owner);
-
-        if (old_owner && new_owner)
-                log_debug("%s's D-Bus name %s changed owner from %s to %s", u->meta.id, name, old_owner, new_owner);
-        else if (old_owner)
-                log_debug("%s's D-Bus name %s no longer registered by %s", u->meta.id, name, old_owner);
-        else
-                log_debug("%s's D-Bus name %s now registered by %s", u->meta.id, name, new_owner);
-
-        s->bus_name_good = !!new_owner;
-
-        if (s->type == SERVICE_DBUS) {
-
-                /* service_enter_running() will figure out what to
-                 * do */
-                if (s->state == SERVICE_RUNNING)
-                        service_enter_running(s, true);
-                else if (s->state == SERVICE_START && new_owner)
-                        service_enter_start_post(s);
-
-        } else if (new_owner &&
-                   s->main_pid <= 0 &&
-                   (s->state == SERVICE_START ||
-                    s->state == SERVICE_START_POST ||
-                    s->state == SERVICE_RUNNING ||
-                    s->state == SERVICE_RELOAD)) {
-
-                /* Try to acquire PID from bus service */
-                log_debug("Trying to acquire PID from D-Bus name...");
-
-                bus_query_pid(u->meta.manager, name);
-        }
-}
-
-static void service_bus_query_pid_done(
-                Unit *u,
-                const char *name,
-                pid_t pid) {
-
-        Service *s = SERVICE(u);
-
-        assert(s);
-        assert(name);
-
-        log_debug("%s's D-Bus name %s is now owned by process %u", u->meta.id, name, (unsigned) pid);
-
-        if (s->main_pid <= 0 &&
-            (s->state == SERVICE_START ||
-             s->state == SERVICE_START_POST ||
-             s->state == SERVICE_RUNNING ||
-             s->state == SERVICE_RELOAD))
-                s->main_pid = pid;
-}
-
-int service_set_socket_fd(Service *s, int fd) {
-        assert(s);
-        assert(fd >= 0);
-
-        /* This is called by the socket code when instantiating a new
-         * service for a stream socket and the socket needs to be
-         * configured. */
-
-        if (UNIT(s)->meta.load_state != UNIT_LOADED)
-                return -EINVAL;
-
-        if (s->socket_fd >= 0)
-                return -EBUSY;
-
-        if (s->state != SERVICE_DEAD)
-                return -EAGAIN;
-
-        s->socket_fd = fd;
-        s->got_socket_fd = true;
-        return 0;
-}
-
-static const char* const service_state_table[_SERVICE_STATE_MAX] = {
-        [SERVICE_DEAD] = "dead",
-        [SERVICE_START_PRE] = "start-pre",
-        [SERVICE_START] = "start",
-        [SERVICE_START_POST] = "start-post",
-        [SERVICE_RUNNING] = "running",
-        [SERVICE_EXITED] = "exited",
-        [SERVICE_RELOAD] = "reload",
-        [SERVICE_STOP] = "stop",
-        [SERVICE_STOP_SIGTERM] = "stop-sigterm",
-        [SERVICE_STOP_SIGKILL] = "stop-sigkill",
-        [SERVICE_STOP_POST] = "stop-post",
-        [SERVICE_FINAL_SIGTERM] = "final-sigterm",
-        [SERVICE_FINAL_SIGKILL] = "final-sigkill",
-        [SERVICE_MAINTAINANCE] = "maintainance",
-        [SERVICE_AUTO_RESTART] = "auto-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
-
-static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
-        [SERVICE_ONCE] = "once",
-        [SERVICE_RESTART_ON_SUCCESS] = "restart-on-success",
-        [SERVICE_RESTART_ALWAYS] = "restart-always",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
-
-static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
-        [SERVICE_FORKING] = "forking",
-        [SERVICE_SIMPLE] = "simple",
-        [SERVICE_FINISH] = "finish",
-        [SERVICE_DBUS] = "dbus"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
-
-static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
-        [SERVICE_EXEC_START_PRE] = "ExecStartPre",
-        [SERVICE_EXEC_START] = "ExecStart",
-        [SERVICE_EXEC_START_POST] = "ExecStartPost",
-        [SERVICE_EXEC_RELOAD] = "ExecReload",
-        [SERVICE_EXEC_STOP] = "ExecStop",
-        [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
-
-const UnitVTable service_vtable = {
-        .suffix = ".service",
-
-        .init = service_init,
-        .done = service_done,
-        .load = service_load,
-
-        .coldplug = service_coldplug,
-
-        .dump = service_dump,
-
-        .start = service_start,
-        .stop = service_stop,
-        .reload = service_reload,
-
-        .can_reload = service_can_reload,
-
-        .serialize = service_serialize,
-        .deserialize_item = service_deserialize_item,
-
-        .active_state = service_active_state,
-        .sub_state_to_string = service_sub_state_to_string,
-
-        .check_gc = service_check_gc,
-        .check_snapshot = service_check_snapshot,
-
-        .sigchld_event = service_sigchld_event,
-        .timer_event = service_timer_event,
-
-        .cgroup_notify_empty = service_cgroup_notify_event,
-
-        .bus_name_owner_change = service_bus_name_owner_change,
-        .bus_query_pid_done = service_bus_query_pid_done,
-
-        .bus_message_handler = bus_service_message_handler,
-
-        .enumerate = service_enumerate
-};
diff --git a/service.h b/service.h
deleted file mode 100644
index 40bd57e..0000000
--- a/service.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooservicehfoo
-#define fooservicehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Service Service;
-
-#include "unit.h"
-#include "ratelimit.h"
-
-typedef enum ServiceState {
-        SERVICE_DEAD,
-        SERVICE_START_PRE,
-        SERVICE_START,
-        SERVICE_START_POST,
-        SERVICE_RUNNING,
-        SERVICE_EXITED,            /* Nothing is running anymore, but ValidNoProcess is true, ehnce this is OK */
-        SERVICE_RELOAD,
-        SERVICE_STOP,              /* No STOP_PRE state, instead just register multiple STOP executables */
-        SERVICE_STOP_SIGTERM,
-        SERVICE_STOP_SIGKILL,
-        SERVICE_STOP_POST,
-        SERVICE_FINAL_SIGTERM,     /* In case the STOP_POST executable hangs, we shoot that down, too */
-        SERVICE_FINAL_SIGKILL,
-        SERVICE_MAINTAINANCE,
-        SERVICE_AUTO_RESTART,
-        _SERVICE_STATE_MAX,
-        _SERVICE_STATE_INVALID = -1
-} ServiceState;
-
-typedef enum ServiceRestart {
-        SERVICE_ONCE,
-        SERVICE_RESTART_ON_SUCCESS,
-        SERVICE_RESTART_ALWAYS,
-        _SERVICE_RESTART_MAX,
-        _SERVICE_RESTART_INVALID = -1
-} ServiceRestart;
-
-typedef enum ServiceType {
-        SERVICE_FORKING,  /* forks by itself (i.e. traditional daemons) */
-        SERVICE_SIMPLE,   /* we fork and go on right-away (i.e. modern socket activated daemons) */
-        SERVICE_FINISH,   /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
-        SERVICE_DBUS,     /* we fork and wait until a specific D-Bus name appears on the bus */
-        _SERVICE_TYPE_MAX,
-        _SERVICE_TYPE_INVALID = -1
-} ServiceType;
-
-typedef enum ServiceExecCommand {
-        SERVICE_EXEC_START_PRE,
-        SERVICE_EXEC_START,
-        SERVICE_EXEC_START_POST,
-        SERVICE_EXEC_RELOAD,
-        SERVICE_EXEC_STOP,
-        SERVICE_EXEC_STOP_POST,
-        _SERVICE_EXEC_COMMAND_MAX,
-        _SERVICE_EXEC_COMMAND_INVALID = -1
-} ServiceExecCommand;
-
-struct Service {
-        Meta meta;
-
-        ServiceType type;
-        ServiceRestart restart;
-
-        /* If set we'll read the main daemon PID from this file */
-        char *pid_file;
-
-        usec_t restart_usec;
-        usec_t timeout_usec;
-
-        ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        bool permissions_start_only;
-        bool root_directory_start_only;
-        bool valid_no_process;
-
-        ServiceState state, deserialized_state;
-
-        KillMode kill_mode;
-
-        ExecStatus main_exec_status;
-
-        ExecCommand *control_command;
-        ServiceExecCommand control_command_id;
-        pid_t main_pid, control_pid;
-        bool main_pid_known:1;
-
-        /* If we shut down, remember why */
-        bool failure:1;
-
-        bool bus_name_good:1;
-
-        bool allow_restart:1;
-
-        bool got_socket_fd:1;
-
-        bool sysv_has_lsb:1;
-        char *sysv_path;
-        int sysv_start_priority;
-        char *sysv_runlevels;
-
-        char *bus_name;
-
-        RateLimit ratelimit;
-
-        int socket_fd;
-
-        Watch timer_watch;
-};
-
-extern const UnitVTable service_vtable;
-
-int service_set_socket_fd(Service *s, int fd);
-
-const char* service_state_to_string(ServiceState i);
-ServiceState service_state_from_string(const char *s);
-
-const char* service_restart_to_string(ServiceRestart i);
-ServiceRestart service_restart_from_string(const char *s);
-
-const char* service_type_to_string(ServiceType i);
-ServiceType service_type_from_string(const char *s);
-
-const char* service_exec_command_to_string(ServiceExecCommand i);
-ServiceExecCommand service_exec_command_from_string(const char *s);
-
-#endif
diff --git a/set.c b/set.c
deleted file mode 100644
index efd20db..0000000
--- a/set.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-
-#include "set.h"
-#include "hashmap.h"
-
-#define MAKE_SET(h) ((Set*) (h))
-#define MAKE_HASHMAP(s) ((Hashmap*) (s))
-
-/* For now this is not much more than a wrapper around a hashmap */
-
-Set *set_new(hash_func_t hash_func, compare_func_t compare_func) {
-        return MAKE_SET(hashmap_new(hash_func, compare_func));
-}
-
-void set_free(Set* s) {
-        hashmap_free(MAKE_HASHMAP(s));
-}
-
-int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) {
-        return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func);
-}
-
-int set_put(Set *s, void *value) {
-        return hashmap_put(MAKE_HASHMAP(s), value, value);
-}
-
-int set_replace(Set *s, void *value) {
-        return hashmap_replace(MAKE_HASHMAP(s), value, value);
-}
-
-void *set_get(Set *s, void *value) {
-        return hashmap_get(MAKE_HASHMAP(s), value);
-}
-
-void *set_remove(Set *s, void *value) {
-        return hashmap_remove(MAKE_HASHMAP(s), value);
-}
-
-int set_remove_and_put(Set *s, void *old_value, void *new_value) {
-        return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value);
-}
-
-unsigned set_size(Set *s) {
-        return hashmap_size(MAKE_HASHMAP(s));
-}
-
-bool set_isempty(Set *s) {
-        return hashmap_isempty(MAKE_HASHMAP(s));
-}
-
-void *set_iterate(Set *s, Iterator *i) {
-        return hashmap_iterate(MAKE_HASHMAP(s), i, NULL);
-}
-
-void *set_iterate_backwards(Set *s, Iterator *i) {
-        return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL);
-}
-
-void *set_iterate_skip(Set *s, void *value, Iterator *i) {
-        return hashmap_iterate_skip(MAKE_HASHMAP(s), value, i);
-}
-
-void *set_steal_first(Set *s) {
-        return hashmap_steal_first(MAKE_HASHMAP(s));
-}
-
-void* set_first(Set *s) {
-        return hashmap_first(MAKE_HASHMAP(s));
-}
-
-void* set_last(Set *s) {
-        return hashmap_last(MAKE_HASHMAP(s));
-}
-
-int set_merge(Set *s, Set *other) {
-        return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
-}
-
-void set_move(Set *s, Set *other) {
-        return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
-}
-
-int set_move_one(Set *s, Set *other, void *value) {
-        return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value);
-}
-
-Set* set_copy(Set *s) {
-        return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s)));
-}
-
-void set_clear(Set *s) {
-        hashmap_clear(MAKE_HASHMAP(s));
-}
diff --git a/set.h b/set.h
deleted file mode 100644
index dd2e91d..0000000
--- a/set.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foosethfoo
-#define foosethfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/* Pretty straightforward set implementation. Internally based on the
- * hashmap. That means that as a minor optimization a NULL set
- * object will be treated as empty set for all read
- * operations. That way it is not necessary to instantiate an object
- * for each set use. */
-
-#include "hashmap.h"
-
-typedef struct Set Set;
-
-Set *set_new(hash_func_t hash_func, compare_func_t compare_func);
-void set_free(Set* s);
-Set* set_copy(Set *s);
-int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func);
-
-int set_put(Set *s, void *value);
-int set_replace(Set *s, void *value);
-void *set_get(Set *s, void *value);
-void *set_remove(Set *s, void *value);
-int set_remove_and_put(Set *s, void *old_value, void *new_value);
-
-int set_merge(Set *s, Set *other);
-void set_move(Set *s, Set *other);
-int set_move_one(Set *s, Set *other, void *value);
-
-unsigned set_size(Set *s);
-bool set_isempty(Set *s);
-
-void *set_iterate(Set *s, Iterator *i);
-void *set_iterate_backwards(Set *s, Iterator *i);
-void *set_iterate_skip(Set *s, void *value, Iterator *i);
-
-void set_clear(Set *s);
-void *set_steal_first(Set *s);
-void* set_first(Set *s);
-void* set_last(Set *s);
-
-#define SET_FOREACH(e, s, i) \
-        for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i)))
-
-#define SET_FOREACH_BACKWARDS(e, s, i) \
-        for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i)))
-
-#endif
diff --git a/snapshot.c b/snapshot.c
deleted file mode 100644
index 513bf66..0000000
--- a/snapshot.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "unit.h"
-#include "snapshot.h"
-#include "unit-name.h"
-#include "dbus-snapshot.h"
-
-static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
-        [SNAPSHOT_DEAD] = UNIT_INACTIVE,
-        [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
-};
-
-static void snapshot_set_state(Snapshot *s, SnapshotState state) {
-        SnapshotState old_state;
-        assert(s);
-
-        old_state = s->state;
-        s->state = state;
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(s)->meta.id,
-                          snapshot_state_to_string(old_state),
-                          snapshot_state_to_string(state));
-
-        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int snapshot_coldplug(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(s->state == SNAPSHOT_DEAD);
-
-        if (s->deserialized_state != s->state)
-                snapshot_set_state(s, s->deserialized_state);
-
-        return 0;
-}
-
-static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(f);
-
-        fprintf(f,
-                "%sSnapshot State: %s\n"
-                "%sClean Up: %s\n",
-                prefix, snapshot_state_to_string(s->state),
-                prefix, yes_no(s->cleanup));
-}
-
-static int snapshot_start(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(s->state == SNAPSHOT_DEAD);
-
-        snapshot_set_state(s, SNAPSHOT_ACTIVE);
-
-        if (s->cleanup)
-                unit_add_to_cleanup_queue(u);
-
-        return 0;
-}
-
-static int snapshot_stop(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(s->state == SNAPSHOT_ACTIVE);
-
-        snapshot_set_state(s, SNAPSHOT_DEAD);
-        return 0;
-}
-
-static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Snapshot *s = SNAPSHOT(u);
-        Unit *other;
-        Iterator i;
-
-        assert(s);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
-        unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
-                unit_serialize_item(u, f, "requires", other->meta.id);
-
-        return 0;
-}
-
-static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Snapshot *s = SNAPSHOT(u);
-        int r;
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                SnapshotState state;
-
-                if ((state = snapshot_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        s->deserialized_state = state;
-
-        } else if (streq(key, "cleanup")) {
-
-                if ((r = parse_boolean(value)) < 0)
-                        log_debug("Failed to parse cleanup value %s", value);
-                else
-                        s->cleanup = r;
-
-        } else if (streq(key, "requires")) {
-
-                if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, value, NULL, true)) < 0)
-                        return r;
-
-                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, value, NULL, true)) < 0)
-                        return r;
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState snapshot_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[SNAPSHOT(u)->state];
-}
-
-static const char *snapshot_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return snapshot_state_to_string(SNAPSHOT(u)->state);
-}
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **_s) {
-        Iterator i;
-        Unit *other, *u = NULL;
-        char *n = NULL;
-        int r;
-        const char *k;
-
-        assert(m);
-        assert(_s);
-
-        if (name) {
-                if (!unit_name_is_valid(name))
-                        return -EINVAL;
-
-                if (unit_name_to_type(name) != UNIT_SNAPSHOT)
-                        return -EINVAL;
-
-                if (manager_get_unit(m, name))
-                        return -EEXIST;
-
-        } else {
-
-                for (;;) {
-                        if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
-                                return -ENOMEM;
-
-                        if (!manager_get_unit(m, n))
-                                break;
-
-                        free(n);
-                }
-
-                name = n;
-        }
-
-        r = manager_load_unit(m, name, NULL, &u);
-        free(n);
-
-        if (r < 0)
-                goto fail;
-
-        HASHMAP_FOREACH_KEY(other, k, m->units, i) {
-
-                if (UNIT_VTABLE(other)->no_snapshots)
-                        continue;
-
-                if (k != other->meta.id)
-                        continue;
-
-                if (UNIT_VTABLE(other)->check_snapshot)
-                        if (!UNIT_VTABLE(other)->check_snapshot(other))
-                            continue;
-
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        continue;
-
-                if ((r = unit_add_dependency(u, UNIT_REQUIRES, other, true)) < 0)
-                        goto fail;
-
-                if ((r = unit_add_dependency(u, UNIT_AFTER, other, true)) < 0)
-                        goto fail;
-        }
-
-        SNAPSHOT(u)->cleanup = cleanup;
-        *_s = SNAPSHOT(u);
-
-        return 0;
-
-fail:
-        if (u)
-                unit_add_to_cleanup_queue(u);
-
-        return r;
-}
-
-void snapshot_remove(Snapshot *s) {
-        assert(s);
-
-        unit_add_to_cleanup_queue(UNIT(s));
-}
-
-static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
-        [SNAPSHOT_DEAD] = "dead",
-        [SNAPSHOT_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
-
-const UnitVTable snapshot_vtable = {
-        .suffix = ".snapshot",
-
-        .no_alias = true,
-        .no_instances = true,
-        .no_snapshots = true,
-        .no_gc = true,
-
-        .load = unit_load_nop,
-        .coldplug = snapshot_coldplug,
-
-        .dump = snapshot_dump,
-
-        .start = snapshot_start,
-        .stop = snapshot_stop,
-
-        .serialize = snapshot_serialize,
-        .deserialize_item = snapshot_deserialize_item,
-
-        .active_state = snapshot_active_state,
-        .sub_state_to_string = snapshot_sub_state_to_string,
-
-        .bus_message_handler = bus_snapshot_message_handler
-};
diff --git a/snapshot.h b/snapshot.h
deleted file mode 100644
index 959a509..0000000
--- a/snapshot.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foosnapshothfoo
-#define foosnapshothfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Snapshot Snapshot;
-
-#include "unit.h"
-
-typedef enum SnapshotState {
-        SNAPSHOT_DEAD,
-        SNAPSHOT_ACTIVE,
-        _SNAPSHOT_STATE_MAX,
-        _SNAPSHOT_STATE_INVALID = -1
-} SnapshotState;
-
-struct Snapshot {
-        Meta meta;
-
-        SnapshotState state, deserialized_state;
-
-        bool cleanup;
-};
-
-extern const UnitVTable snapshot_vtable;
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **s);
-void snapshot_remove(Snapshot *s);
-
-const char* snapshot_state_to_string(SnapshotState i);
-SnapshotState snapshot_state_from_string(const char *s);
-
-#endif
diff --git a/socket-util.c b/socket-util.c
deleted file mode 100644
index 32f6bcb..0000000
--- a/socket-util.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <net/if.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "macro.h"
-#include "util.h"
-#include "socket-util.h"
-
-int socket_address_parse(SocketAddress *a, const char *s) {
-        int r;
-        char *e, *n;
-        unsigned u;
-
-        assert(a);
-        assert(s);
-
-        zero(*a);
-        a->type = SOCK_STREAM;
-
-        if (*s == '[') {
-                /* IPv6 in [x:.....:z]:p notation */
-
-                if (!(e = strchr(s+1, ']')))
-                        return -EINVAL;
-
-                if (!(n = strndup(s+1, e-s-1)))
-                        return -ENOMEM;
-
-                errno = 0;
-                if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
-                        free(n);
-                        return errno != 0 ? -errno : -EINVAL;
-                }
-
-                free(n);
-
-                e++;
-                if (*e != ':')
-                        return -EINVAL;
-
-                e++;
-                if ((r = safe_atou(e, &u)) < 0)
-                        return r;
-
-                if (u <= 0 || u > 0xFFFF)
-                        return -EINVAL;
-
-                a->sockaddr.in6.sin6_family = AF_INET6;
-                a->sockaddr.in6.sin6_port = htons((uint16_t) u);
-                a->size = sizeof(struct sockaddr_in6);
-
-        } else if (*s == '/') {
-                /* AF_UNIX socket */
-
-                size_t l;
-
-                l = strlen(s);
-                if (l >= sizeof(a->sockaddr.un.sun_path))
-                        return -EINVAL;
-
-                a->sockaddr.un.sun_family = AF_UNIX;
-                memcpy(a->sockaddr.un.sun_path, s, l);
-                a->size = sizeof(sa_family_t) + l + 1;
-
-        } else if (*s == '@') {
-                /* Abstract AF_UNIX socket */
-                size_t l;
-
-                l = strlen(s+1);
-                if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
-                        return -EINVAL;
-
-                a->sockaddr.un.sun_family = AF_UNIX;
-                memcpy(a->sockaddr.un.sun_path+1, s+1, l);
-                a->size = sizeof(struct sockaddr_un);
-
-        } else {
-
-                if ((e = strchr(s, ':'))) {
-
-                        if ((r = safe_atou(e+1, &u)) < 0)
-                                return r;
-
-                        if (u <= 0 || u > 0xFFFF)
-                                return -EINVAL;
-
-                        if (!(n = strndup(s, e-s)))
-                                return -ENOMEM;
-
-                        /* IPv4 in w.x.y.z:p notation? */
-                        if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
-                                free(n);
-                                return -errno;
-                        }
-
-                        if (r > 0) {
-                                /* Gotcha, it's a traditional IPv4 address */
-                                free(n);
-
-                                a->sockaddr.in4.sin_family = AF_INET;
-                                a->sockaddr.in4.sin_port = htons((uint16_t) u);
-                                a->size = sizeof(struct sockaddr_in);
-                        } else {
-                                unsigned idx;
-
-                                if (strlen(n) > IF_NAMESIZE-1) {
-                                        free(n);
-                                        return -EINVAL;
-                                }
-
-                                /* Uh, our last resort, an interface name */
-                                idx = if_nametoindex(n);
-                                free(n);
-
-                                if (idx == 0)
-                                        return -EINVAL;
-
-                                a->sockaddr.in6.sin6_family = AF_INET6;
-                                a->sockaddr.in6.sin6_port = htons((uint16_t) u);
-                                a->sockaddr.in6.sin6_scope_id = idx;
-                                a->sockaddr.in6.sin6_addr = in6addr_any;
-                                a->size = sizeof(struct sockaddr_in6);
-
-                        }
-                } else {
-
-                        /* Just a port */
-                        if ((r = safe_atou(s, &u)) < 0)
-                                return r;
-
-                        if (u <= 0 || u > 0xFFFF)
-                                return -EINVAL;
-
-                        a->sockaddr.in6.sin6_family = AF_INET6;
-                        a->sockaddr.in6.sin6_port = htons((uint16_t) u);
-                        a->sockaddr.in6.sin6_addr = in6addr_any;
-                        a->size = sizeof(struct sockaddr_in6);
-                }
-        }
-
-        return 0;
-}
-
-int socket_address_verify(const SocketAddress *a) {
-        assert(a);
-
-        switch (socket_address_family(a)) {
-                case AF_INET:
-                        if (a->size != sizeof(struct sockaddr_in))
-                                return -EINVAL;
-
-                        if (a->sockaddr.in4.sin_port == 0)
-                                return -EINVAL;
-
-                        return 0;
-
-                case AF_INET6:
-                        if (a->size != sizeof(struct sockaddr_in6))
-                                return -EINVAL;
-
-                        if (a->sockaddr.in6.sin6_port == 0)
-                                return -EINVAL;
-
-                        return 0;
-
-                case AF_UNIX:
-                        if (a->size < sizeof(sa_family_t))
-                                return -EINVAL;
-
-                        if (a->size > sizeof(sa_family_t)) {
-
-                                if (a->sockaddr.un.sun_path[0] == 0) {
-                                        /* abstract */
-                                        if (a->size != sizeof(struct sockaddr_un))
-                                                return -EINVAL;
-                                } else {
-                                        char *e;
-
-                                        /* path */
-                                        if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
-                                                return -EINVAL;
-
-                                        if (a->size != sizeof(sa_family_t) + (e - a->sockaddr.un.sun_path) + 1)
-                                                return -EINVAL;
-                                }
-                        }
-
-                        return 0;
-
-                default:
-                        return -EAFNOSUPPORT;
-        }
-}
-
-int socket_address_print(const SocketAddress *a, char **p) {
-        int r;
-        assert(a);
-        assert(p);
-
-        if ((r = socket_address_verify(a)) < 0)
-                return r;
-
-        switch (socket_address_family(a)) {
-                case AF_INET: {
-                        char *ret;
-
-                        if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
-                                return -ENOMEM;
-
-                        if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
-                                free(ret);
-                                return -errno;
-                        }
-
-                        sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
-                        *p = ret;
-                        return 0;
-                }
-
-                case AF_INET6: {
-                        char *ret;
-
-                        if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
-                                return -ENOMEM;
-
-                        ret[0] = '[';
-                        if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
-                                free(ret);
-                                return -errno;
-                        }
-
-                        sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
-                        *p = ret;
-                        return 0;
-                }
-
-                case AF_UNIX: {
-                        char *ret;
-
-                        if (a->size <= sizeof(sa_family_t)) {
-
-                                if (!(ret = strdup("<unamed>")))
-                                        return -ENOMEM;
-
-                        } else if (a->sockaddr.un.sun_path[0] == 0) {
-                                /* abstract */
-
-                                /* FIXME: We assume we can print the
-                                 * socket path here and that it hasn't
-                                 * more than one NUL byte. That is
-                                 * actually an invalid assumption */
-
-                                if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
-                                        return -ENOMEM;
-
-                                ret[0] = '@';
-                                memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
-                                ret[sizeof(a->sockaddr.un.sun_path)] = 0;
-
-                        } else {
-
-                                if (!(ret = strdup(a->sockaddr.un.sun_path)))
-                                        return -ENOMEM;
-                        }
-
-                        *p = ret;
-                        return 0;
-                }
-
-                default:
-                        return -EINVAL;
-        }
-}
-
-int socket_address_listen(
-                const SocketAddress *a,
-                int backlog,
-                SocketAddressBindIPv6Only only,
-                const char *bind_to_device,
-                mode_t directory_mode,
-                mode_t socket_mode,
-                int *ret) {
-
-        int r, fd, one;
-        assert(a);
-        assert(ret);
-
-        if ((r = socket_address_verify(a)) < 0)
-                return r;
-
-        if ((fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)) < 0)
-                return -errno;
-
-        if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
-                int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
-
-                if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
-                        goto fail;
-        }
-
-        if (bind_to_device)
-                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
-                        goto fail;
-
-        one = 1;
-        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
-                goto fail;
-
-        if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
-                mode_t old_mask;
-
-                /* Create parents */
-                mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
-
-                /* Enforce the right access mode for the socket*/
-                old_mask = umask(~ socket_mode);
-
-                /* Include the original umask in our mask */
-                umask(~socket_mode | old_mask);
-
-                r = bind(fd, &a->sockaddr.sa, a->size);
-
-                if (r < 0 && errno == EADDRINUSE) {
-                        /* Unlink and try again */
-                        unlink(a->sockaddr.un.sun_path);
-                        r = bind(fd, &a->sockaddr.sa, a->size);
-                }
-
-                umask(old_mask);
-        } else
-                r = bind(fd, &a->sockaddr.sa, a->size);
-
-        if (r < 0)
-                goto fail;
-
-        if (a->type == SOCK_STREAM)
-                if (listen(fd, backlog) < 0)
-                        goto fail;
-
-        *ret = fd;
-        return 0;
-
-fail:
-        r = -errno;
-        close_nointr_nofail(fd);
-        return r;
-}
-
-bool socket_address_can_accept(const SocketAddress *a) {
-        assert(a);
-
-        return
-                a->type == SOCK_STREAM ||
-                a->type == SOCK_SEQPACKET;
-}
-
-bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
-        assert(a);
-        assert(b);
-
-        /* Invalid addresses are unequal to all */
-        if (socket_address_verify(a) < 0 ||
-            socket_address_verify(b) < 0)
-                return false;
-
-        if (a->type != b->type)
-                return false;
-
-        if (a->size != b->size)
-                return false;
-
-        if (socket_address_family(a) != socket_address_family(b))
-                return false;
-
-        switch (socket_address_family(a)) {
-
-        case AF_INET:
-                if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
-                        return false;
-
-                if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
-                        return false;
-
-                break;
-
-        case AF_INET6:
-                if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
-                        return false;
-
-                if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
-                        return false;
-
-                break;
-
-        case AF_UNIX:
-
-                if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
-                        return false;
-
-                if (a->sockaddr.un.sun_path[0]) {
-                        if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
-                                return false;
-                } else {
-                        if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
-                                return false;
-                }
-
-                break;
-
-        default:
-                /* Cannot compare, so we assume the addresses are different */
-                return false;
-        }
-
-        return true;
-}
-
-bool socket_address_is(const SocketAddress *a, const char *s) {
-        struct SocketAddress b;
-
-        assert(a);
-        assert(s);
-
-        if (socket_address_parse(&b, s) < 0)
-                return false;
-
-        return socket_address_equal(a, &b);
-}
-
-bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
-        assert(a);
-
-        if (socket_address_family(a) != AF_UNIX)
-                return false;
-
-        if (a->sockaddr.un.sun_path[0] == 0)
-                return false;
-
-        return path_startswith(a->sockaddr.un.sun_path, prefix);
-}
diff --git a/socket-util.h b/socket-util.h
deleted file mode 100644
index 1419216..0000000
--- a/socket-util.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foosocketutilhfoo
-#define foosocketutilhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/un.h>
-#include <net/if.h>
-
-#include "macro.h"
-#include "util.h"
-
-typedef struct SocketAddress {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_in in4;
-                struct sockaddr_in6 in6;
-                struct sockaddr_un un;
-                struct sockaddr_storage storage;
-        } sockaddr;
-
-        /* We store the size here explicitly due to the weird
-         * sockaddr_un semantics for abstract sockets */
-        socklen_t size;
-
-        /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */
-        int type;
-} SocketAddress;
-
-typedef enum SocketAddressBindIPv6Only {
-        SOCKET_ADDRESS_DEFAULT,
-        SOCKET_ADDRESS_BOTH,
-        SOCKET_ADDRESS_IPV6_ONLY
-} SocketAddressBindIPv6Only;
-
-#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
-
-int socket_address_parse(SocketAddress *a, const char *s);
-int socket_address_print(const SocketAddress *a, char **p);
-int socket_address_verify(const SocketAddress *a);
-
-bool socket_address_can_accept(const SocketAddress *a);
-
-int socket_address_listen(
-                const SocketAddress *a,
-                int backlog,
-                SocketAddressBindIPv6Only only,
-                const char *bind_to_device,
-                mode_t directory_mode,
-                mode_t socket_mode,
-                int *ret);
-
-bool socket_address_is(const SocketAddress *a, const char *s);
-
-bool socket_address_equal(const SocketAddress *a, const SocketAddress *b);
-
-bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);
-
-#endif
diff --git a/socket.c b/socket.c
deleted file mode 100644
index 259f273..0000000
--- a/socket.c
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <arpa/inet.h>
-
-#include "unit.h"
-#include "socket.h"
-#include "log.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "dbus-socket.h"
-
-static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
-        [SOCKET_DEAD] = UNIT_INACTIVE,
-        [SOCKET_START_PRE] = UNIT_ACTIVATING,
-        [SOCKET_START_POST] = UNIT_ACTIVATING,
-        [SOCKET_LISTENING] = UNIT_ACTIVE,
-        [SOCKET_RUNNING] = UNIT_ACTIVE,
-        [SOCKET_STOP_PRE] = UNIT_DEACTIVATING,
-        [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING,
-        [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING,
-        [SOCKET_STOP_POST] = UNIT_DEACTIVATING,
-        [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING,
-        [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING,
-        [SOCKET_MAINTAINANCE] = UNIT_INACTIVE,
-};
-
-static void socket_init(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        s->timer_watch.type = WATCH_INVALID;
-        s->backlog = SOMAXCONN;
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        s->directory_mode = 0755;
-        s->socket_mode = 0666;
-
-        exec_context_init(&s->exec_context);
-
-        s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
-}
-
-static void socket_unwatch_control_pid(Socket *s) {
-        assert(s);
-
-        if (s->control_pid <= 0)
-                return;
-
-        unit_unwatch_pid(UNIT(s), s->control_pid);
-        s->control_pid = 0;
-}
-
-static void socket_done(Unit *u) {
-        Socket *s = SOCKET(u);
-        SocketPort *p;
-
-        assert(s);
-
-        while ((p = s->ports)) {
-                LIST_REMOVE(SocketPort, port, s->ports, p);
-
-                if (p->fd >= 0) {
-                        unit_unwatch_fd(UNIT(s), &p->fd_watch);
-                        close_nointr_nofail(p->fd);
-                }
-
-                free(p->path);
-                free(p);
-        }
-
-        exec_context_done(&s->exec_context);
-        exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
-        s->control_command = NULL;
-
-        socket_unwatch_control_pid(s);
-
-        s->service = NULL;
-
-        free(s->bind_to_device);
-        s->bind_to_device = NULL;
-
-        unit_unwatch_timer(u, &s->timer_watch);
-}
-
-static bool have_non_accept_socket(Socket *s) {
-        SocketPort *p;
-
-        assert(s);
-
-        if (!s->accept)
-                return true;
-
-        LIST_FOREACH(port, p, s->ports) {
-
-                if (p->type != SOCKET_SOCKET)
-                        return true;
-
-                if (!socket_address_can_accept(&p->address))
-                        return true;
-        }
-
-        return false;
-}
-
-static int socket_verify(Socket *s) {
-        assert(s);
-
-        if (UNIT(s)->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (!s->ports) {
-                log_error("%s lacks Listen setting. Refusing.", UNIT(s)->meta.id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static bool socket_needs_mount(Socket *s, const char *prefix) {
-        SocketPort *p;
-
-        assert(s);
-
-        LIST_FOREACH(port, p, s->ports) {
-
-                if (p->type == SOCKET_SOCKET) {
-                        if (socket_address_needs_mount(&p->address, prefix))
-                                return true;
-                } else {
-                        assert(p->type == SOCKET_FIFO);
-                        if (path_startswith(p->path, prefix))
-                                return true;
-                }
-        }
-
-        return false;
-}
-
-int socket_add_one_mount_link(Socket *s, Mount *m) {
-        int r;
-
-        assert(s);
-        assert(m);
-
-        if (s->meta.load_state != UNIT_LOADED ||
-            m->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (!socket_needs_mount(s, m->where))
-                return 0;
-
-        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
-                return r;
-
-        if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
-                return r;
-
-        return 0;
-}
-
-static int socket_add_mount_links(Socket *s) {
-        Meta *other;
-        int r;
-
-        assert(s);
-
-        LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_MOUNT])
-                if ((r = socket_add_one_mount_link(s, (Mount*) other)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int socket_add_device_link(Socket *s) {
-        char *t;
-        int r;
-
-        assert(s);
-
-        if (!s->bind_to_device)
-                return 0;
-
-        if (asprintf(&t, "/sys/subsystem/net/devices/%s", s->bind_to_device) < 0)
-                return -ENOMEM;
-
-        r = unit_add_node_link(UNIT(s), t, false);
-        free(t);
-
-        return r;
-}
-
-static int socket_load(Unit *u) {
-        Socket *s = SOCKET(u);
-        int r;
-
-        assert(u);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        if ((r = unit_load_fragment_and_dropin(u)) < 0)
-                return r;
-
-        /* This is a new unit? Then let's add in some extras */
-        if (u->meta.load_state == UNIT_LOADED) {
-
-                if (have_non_accept_socket(s)) {
-                        if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service)))
-                                return r;
-
-                        if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service), true)) < 0)
-                                return r;
-                }
-
-                if ((r = socket_add_mount_links(s)) < 0)
-                        return r;
-
-                if ((r = socket_add_device_link(s)) < 0)
-                        return r;
-
-                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
-                        return r;
-
-                if ((r = unit_add_default_cgroup(u)) < 0)
-                        return r;
-        }
-
-        return socket_verify(s);
-}
-
-static const char* listen_lookup(int type) {
-
-        if (type == SOCK_STREAM)
-                return "ListenStream";
-        else if (type == SOCK_DGRAM)
-                return "ListenDatagram";
-        else if (type == SOCK_SEQPACKET)
-                return "ListenSequentialPacket";
-
-        assert_not_reached("Unknown socket type");
-        return NULL;
-}
-
-static void socket_dump(Unit *u, FILE *f, const char *prefix) {
-
-        SocketExecCommand c;
-        Socket *s = SOCKET(u);
-        SocketPort *p;
-        const char *prefix2;
-        char *p2;
-
-        assert(s);
-        assert(f);
-
-        p2 = strappend(prefix, "\t");
-        prefix2 = p2 ? p2 : prefix;
-
-        fprintf(f,
-                "%sSocket State: %s\n"
-                "%sBindIPv6Only: %s\n"
-                "%sBacklog: %u\n"
-                "%sKillMode: %s\n"
-                "%sSocketMode: %04o\n"
-                "%sDirectoryMode: %04o\n",
-                prefix, socket_state_to_string(s->state),
-                prefix, yes_no(s->bind_ipv6_only),
-                prefix, s->backlog,
-                prefix, kill_mode_to_string(s->kill_mode),
-                prefix, s->socket_mode,
-                prefix, s->directory_mode);
-
-        if (s->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %llu\n",
-                        prefix, (unsigned long long) s->control_pid);
-
-        if (s->bind_to_device)
-                fprintf(f,
-                        "%sBindToDevice: %s\n",
-                        prefix, s->bind_to_device);
-
-        if (s->accept)
-                fprintf(f,
-                        "%sAccepted: %u\n",
-                        prefix, s->n_accepted);
-
-        LIST_FOREACH(port, p, s->ports) {
-
-                if (p->type == SOCKET_SOCKET) {
-                        const char *t;
-                        int r;
-                        char *k;
-
-                        if ((r = socket_address_print(&p->address, &k)) < 0)
-                                t = strerror(-r);
-                        else
-                                t = k;
-
-                        fprintf(f, "%s%s: %s\n", prefix, listen_lookup(p->address.type), k);
-                        free(k);
-                } else
-                        fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
-        }
-
-        exec_context_dump(&s->exec_context, f, prefix);
-
-        for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
-                if (!s->exec_command[c])
-                        continue;
-
-                fprintf(f, "%s-> %s:\n",
-                        prefix, socket_exec_command_to_string(c));
-
-                exec_command_dump_list(s->exec_command[c], f, prefix2);
-        }
-
-        free(p2);
-}
-
-static int instance_from_socket(int fd, unsigned nr, char **instance) {
-        socklen_t l;
-        char *r;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_un un;
-                struct sockaddr_in in;
-                struct sockaddr_in6 in6;
-                struct sockaddr_storage storage;
-        } local, remote;
-
-        assert(fd >= 0);
-        assert(instance);
-
-        l = sizeof(local);
-        if (getsockname(fd, &local.sa, &l) < 0)
-                return -errno;
-
-        l = sizeof(remote);
-        if (getpeername(fd, &remote.sa, &l) < 0)
-                return -errno;
-
-        switch (local.sa.sa_family) {
-
-        case AF_INET: {
-                uint32_t
-                        a = ntohl(local.in.sin_addr.s_addr),
-                        b = ntohl(remote.in.sin_addr.s_addr);
-
-                if (asprintf(&r,
-                             "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
-                             nr,
-                             a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
-                             ntohs(local.in.sin_port),
-                             b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
-                             ntohs(remote.in.sin_port)) < 0)
-                        return -ENOMEM;
-
-                break;
-        }
-
-        case AF_INET6: {
-                char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN];
-
-                if (asprintf(&r,
-                             "%u-%s:%u-%s:%u",
-                             nr,
-                             inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)),
-                             ntohs(local.in6.sin6_port),
-                             inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)),
-                             ntohs(remote.in6.sin6_port)) < 0)
-                        return -ENOMEM;
-
-                break;
-        }
-
-        case AF_UNIX: {
-                struct ucred ucred;
-
-                l = sizeof(ucred);
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
-                        return -errno;
-
-                if (asprintf(&r,
-                             "%u-%llu-%llu",
-                             nr,
-                             (unsigned long long) ucred.pid,
-                             (unsigned long long) ucred.uid) < 0)
-                        return -ENOMEM;
-
-                break;
-        }
-
-        default:
-                assert_not_reached("Unhandled socket type.");
-        }
-
-        *instance = r;
-        return 0;
-}
-
-static void socket_close_fds(Socket *s) {
-        SocketPort *p;
-
-        assert(s);
-
-        LIST_FOREACH(port, p, s->ports) {
-                if (p->fd < 0)
-                        continue;
-
-                unit_unwatch_fd(UNIT(s), &p->fd_watch);
-                close_nointr_nofail(p->fd);
-
-                /* One little note: we should never delete any sockets
-                 * in the file system here! After all some other
-                 * process we spawned might still have a reference of
-                 * this fd and wants to continue to use it. Therefore
-                 * we delete sockets in the file system before we
-                 * create a new one, not after we stopped using
-                 * one! */
-
-                p->fd = -1;
-        }
-}
-
-static int socket_open_fds(Socket *s) {
-        SocketPort *p;
-        int r;
-
-        assert(s);
-
-        LIST_FOREACH(port, p, s->ports) {
-
-                if (p->fd >= 0)
-                        continue;
-
-                if (p->type == SOCKET_SOCKET) {
-
-                        if ((r = socket_address_listen(
-                                             &p->address,
-                                             s->backlog,
-                                             s->bind_ipv6_only,
-                                             s->bind_to_device,
-                                             s->directory_mode,
-                                             s->socket_mode,
-                                             &p->fd)) < 0)
-                                goto rollback;
-
-                } else {
-                        struct stat st;
-                        assert(p->type == SOCKET_FIFO);
-
-                        mkdir_parents(p->path, s->directory_mode);
-
-                        if (mkfifo(p->path, s->socket_mode) < 0 && errno != EEXIST) {
-                                r = -errno;
-                                goto rollback;
-                        }
-
-                        if ((p->fd = open(p->path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
-                                r = -errno;
-                                goto rollback;
-                        }
-
-                        if (fstat(p->fd, &st) < 0) {
-                                r = -errno;
-                                goto rollback;
-                        }
-
-                        /* FIXME verify user, access mode */
-
-                        if (!S_ISFIFO(st.st_mode)) {
-                                r = -EEXIST;
-                                goto rollback;
-                        }
-                }
-        }
-
-        return 0;
-
-rollback:
-        socket_close_fds(s);
-        return r;
-}
-
-static void socket_unwatch_fds(Socket *s) {
-        SocketPort *p;
-
-        assert(s);
-
-        LIST_FOREACH(port, p, s->ports) {
-                if (p->fd < 0)
-                        continue;
-
-                unit_unwatch_fd(UNIT(s), &p->fd_watch);
-        }
-}
-
-static int socket_watch_fds(Socket *s) {
-        SocketPort *p;
-        int r;
-
-        assert(s);
-
-        LIST_FOREACH(port, p, s->ports) {
-                if (p->fd < 0)
-                        continue;
-
-                p->fd_watch.socket_accept =
-                        s->accept &&
-                        p->type == SOCKET_SOCKET &&
-                        socket_address_can_accept(&p->address);
-
-                if ((r = unit_watch_fd(UNIT(s), p->fd, EPOLLIN, &p->fd_watch)) < 0)
-                        goto fail;
-        }
-
-        return 0;
-
-fail:
-        socket_unwatch_fds(s);
-        return r;
-}
-
-static void socket_set_state(Socket *s, SocketState state) {
-        SocketState old_state;
-        assert(s);
-
-        old_state = s->state;
-        s->state = state;
-
-        if (state != SOCKET_START_PRE &&
-            state != SOCKET_START_POST &&
-            state != SOCKET_STOP_PRE &&
-            state != SOCKET_STOP_PRE_SIGTERM &&
-            state != SOCKET_STOP_PRE_SIGKILL &&
-            state != SOCKET_STOP_POST &&
-            state != SOCKET_FINAL_SIGTERM &&
-            state != SOCKET_FINAL_SIGKILL) {
-                unit_unwatch_timer(UNIT(s), &s->timer_watch);
-                socket_unwatch_control_pid(s);
-                s->control_command = NULL;
-                s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
-        }
-
-        if (state != SOCKET_LISTENING)
-                socket_unwatch_fds(s);
-
-        if (state != SOCKET_START_POST &&
-            state != SOCKET_LISTENING &&
-            state != SOCKET_RUNNING &&
-            state != SOCKET_STOP_PRE &&
-            state != SOCKET_STOP_PRE_SIGTERM &&
-            state != SOCKET_STOP_PRE_SIGKILL)
-                socket_close_fds(s);
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          s->meta.id,
-                          socket_state_to_string(old_state),
-                          socket_state_to_string(state));
-
-        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int socket_coldplug(Unit *u) {
-        Socket *s = SOCKET(u);
-        int r;
-
-        assert(s);
-        assert(s->state == SOCKET_DEAD);
-
-        if (s->deserialized_state != s->state) {
-
-                if (s->deserialized_state == SOCKET_START_PRE ||
-                    s->deserialized_state == SOCKET_START_POST ||
-                    s->deserialized_state == SOCKET_STOP_PRE ||
-                    s->deserialized_state == SOCKET_STOP_PRE_SIGTERM ||
-                    s->deserialized_state == SOCKET_STOP_PRE_SIGKILL ||
-                    s->deserialized_state == SOCKET_STOP_POST ||
-                    s->deserialized_state == SOCKET_FINAL_SIGTERM ||
-                    s->deserialized_state == SOCKET_FINAL_SIGKILL) {
-
-                        if (s->control_pid <= 0)
-                                return -EBADMSG;
-
-                        if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
-                                return r;
-
-                        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                                return r;
-                }
-
-                if (s->deserialized_state == SOCKET_START_POST ||
-                    s->deserialized_state == SOCKET_LISTENING ||
-                    s->deserialized_state == SOCKET_RUNNING ||
-                    s->deserialized_state == SOCKET_STOP_PRE ||
-                    s->deserialized_state == SOCKET_STOP_PRE_SIGTERM ||
-                    s->deserialized_state == SOCKET_STOP_PRE_SIGKILL)
-                        if ((r = socket_open_fds(s)) < 0)
-                                return r;
-
-                if (s->deserialized_state == SOCKET_LISTENING)
-                        if ((r = socket_watch_fds(s)) < 0)
-                                return r;
-
-                socket_set_state(s, s->deserialized_state);
-        }
-
-        return 0;
-}
-
-static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
-        pid_t pid;
-        int r;
-        char **argv;
-
-        assert(s);
-        assert(c);
-        assert(_pid);
-
-        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                goto fail;
-
-        if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        r = exec_spawn(c,
-                       argv,
-                       &s->exec_context,
-                       NULL, 0,
-                       s->meta.manager->environment,
-                       true,
-                       true,
-                       UNIT(s)->meta.manager->confirm_spawn,
-                       UNIT(s)->meta.cgroup_bondings,
-                       &pid);
-
-        strv_free(argv);
-        if (r < 0)
-                goto fail;
-
-        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
-                /* FIXME: we need to do something here */
-                goto fail;
-
-        *_pid = pid;
-
-        return 0;
-
-fail:
-        unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
-        return r;
-}
-
-static void socket_enter_dead(Socket *s, bool success) {
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        socket_set_state(s, s->failure ? SOCKET_MAINTAINANCE : SOCKET_DEAD);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, bool success);
-
-static void socket_enter_stop_post(Socket *s, bool success) {
-        int r;
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        socket_unwatch_control_pid(s);
-
-        s->control_command_id = SOCKET_EXEC_STOP_POST;
-
-        if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) {
-                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
-                        goto fail;
-
-                socket_set_state(s, SOCKET_STOP_POST);
-        } else
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to run stop-post executable: %s", s->meta.id, strerror(-r));
-        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, bool success) {
-        int r;
-        bool sent = false;
-
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        if (s->kill_mode != KILL_NONE) {
-                int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
-
-                if (s->kill_mode == KILL_CONTROL_GROUP) {
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH)
-                                        goto fail;
-                        } else
-                                sent = true;
-                }
-
-                if (!sent && s->control_pid > 0)
-                        if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) {
-                                r = -errno;
-                                goto fail;
-                        }
-        }
-
-        if (sent && s->control_pid > 0) {
-                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                        goto fail;
-
-                socket_set_state(s, state);
-        } else if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
-                socket_enter_stop_post(s, true);
-        else
-                socket_enter_dead(s, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r));
-
-        if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
-                socket_enter_stop_post(s, false);
-        else
-                socket_enter_dead(s, false);
-}
-
-static void socket_enter_stop_pre(Socket *s, bool success) {
-        int r;
-        assert(s);
-
-        if (!success)
-                s->failure = true;
-
-        socket_unwatch_control_pid(s);
-
-        s->control_command_id = SOCKET_EXEC_STOP_PRE;
-
-        if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) {
-                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
-                        goto fail;
-
-                socket_set_state(s, SOCKET_STOP_PRE);
-        } else
-                socket_enter_stop_post(s, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to run stop-pre executable: %s", s->meta.id, strerror(-r));
-        socket_enter_stop_post(s, false);
-}
-
-static void socket_enter_listening(Socket *s) {
-        int r;
-        assert(s);
-
-        if ((r = socket_watch_fds(s)) < 0) {
-                log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r));
-                goto fail;
-        }
-
-        socket_set_state(s, SOCKET_LISTENING);
-        return;
-
-fail:
-        socket_enter_stop_pre(s, false);
-}
-
-static void socket_enter_start_post(Socket *s) {
-        int r;
-        assert(s);
-
-        if ((r = socket_open_fds(s)) < 0) {
-                log_warning("%s failed to listen on sockets: %s", s->meta.id, strerror(-r));
-                goto fail;
-        }
-
-        socket_unwatch_control_pid(s);
-
-        s->control_command_id = SOCKET_EXEC_START_POST;
-
-        if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) {
-                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) {
-                        log_warning("%s failed to run start-post executable: %s", s->meta.id, strerror(-r));
-                        goto fail;
-                }
-
-                socket_set_state(s, SOCKET_START_POST);
-        } else
-                socket_enter_listening(s);
-
-        return;
-
-fail:
-        socket_enter_stop_pre(s, false);
-}
-
-static void socket_enter_start_pre(Socket *s) {
-        int r;
-        assert(s);
-
-        socket_unwatch_control_pid(s);
-
-        s->control_command_id = SOCKET_EXEC_START_PRE;
-
-        if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) {
-                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
-                        goto fail;
-
-                socket_set_state(s, SOCKET_START_PRE);
-        } else
-                socket_enter_start_post(s);
-
-        return;
-
-fail:
-        log_warning("%s failed to run start-pre exectuable: %s", s->meta.id, strerror(-r));
-        socket_enter_dead(s, false);
-}
-
-static void socket_enter_running(Socket *s, int cfd) {
-        int r;
-
-        assert(s);
-
-        if (cfd < 0) {
-                if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0)
-                        goto fail;
-
-                socket_set_state(s, SOCKET_RUNNING);
-        } else {
-                Unit *u;
-                char *prefix, *instance, *name;
-
-                if ((r = instance_from_socket(cfd, s->n_accepted++, &instance)))
-                        goto fail;
-
-                if (!(prefix = unit_name_to_prefix(UNIT(s)->meta.id))) {
-                        free(instance);
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                name = unit_name_build(prefix, instance, ".service");
-                free(prefix);
-                free(instance);
-
-                if (!name)
-                        r = -ENOMEM;
-
-                r = manager_load_unit(UNIT(s)->meta.manager, name, NULL, &u);
-                free(name);
-
-                if (r < 0)
-                        goto fail;
-
-                if ((r = service_set_socket_fd(SERVICE(u), cfd) < 0))
-                        goto fail;
-
-                cfd = -1;
-
-                if ((r = manager_add_job(u->meta.manager, JOB_START, u, JOB_REPLACE, true, NULL)) < 0)
-                        goto fail;
-        }
-
-        return;
-
-fail:
-        log_warning("%s failed to queue socket startup job: %s", s->meta.id, strerror(-r));
-        socket_enter_stop_pre(s, false);
-
-        if (cfd >= 0)
-                close_nointr_nofail(cfd);
-}
-
-static void socket_run_next(Socket *s, bool success) {
-        int r;
-
-        assert(s);
-        assert(s->control_command);
-        assert(s->control_command->command_next);
-
-        if (!success)
-                s->failure = true;
-
-        socket_unwatch_control_pid(s);
-
-        s->control_command = s->control_command->command_next;
-
-        if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
-                goto fail;
-
-        return;
-
-fail:
-        log_warning("%s failed to run spawn next executable: %s", s->meta.id, strerror(-r));
-
-        if (s->state == SOCKET_START_POST)
-                socket_enter_stop_pre(s, false);
-        else if (s->state == SOCKET_STOP_POST)
-                socket_enter_dead(s, false);
-        else
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
-}
-
-static int socket_start(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-
-        /* We cannot fulfill this request right now, try again later
-         * please! */
-        if (s->state == SOCKET_STOP_PRE ||
-            s->state == SOCKET_STOP_PRE_SIGKILL ||
-            s->state == SOCKET_STOP_PRE_SIGTERM ||
-            s->state == SOCKET_STOP_POST ||
-            s->state == SOCKET_FINAL_SIGTERM ||
-            s->state == SOCKET_FINAL_SIGKILL)
-                return -EAGAIN;
-
-        if (s->state == SOCKET_START_PRE ||
-            s->state == SOCKET_START_POST)
-                return 0;
-
-        /* Cannot run this without the service being around */
-        if (s->service) {
-                if (s->service->meta.load_state != UNIT_LOADED)
-                        return -ENOENT;
-
-                /* If the service is alredy actvie we cannot start the
-                 * socket */
-                if (s->service->state != SERVICE_DEAD &&
-                    s->service->state != SERVICE_MAINTAINANCE &&
-                    s->service->state != SERVICE_AUTO_RESTART)
-                        return -EBUSY;
-        }
-
-        assert(s->state == SOCKET_DEAD || s->state == SOCKET_MAINTAINANCE);
-
-        s->failure = false;
-        socket_enter_start_pre(s);
-        return 0;
-}
-
-static int socket_stop(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-
-        /* We cannot fulfill this request right now, try again later
-         * please! */
-        if (s->state == SOCKET_START_PRE ||
-            s->state == SOCKET_START_POST)
-                return -EAGAIN;
-
-        /* Already on it */
-        if (s->state == SOCKET_STOP_PRE ||
-            s->state == SOCKET_STOP_PRE_SIGTERM ||
-            s->state == SOCKET_STOP_PRE_SIGKILL ||
-            s->state == SOCKET_STOP_POST ||
-            s->state == SOCKET_FINAL_SIGTERM ||
-            s->state == SOCKET_FINAL_SIGTERM)
-                return 0;
-
-        assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
-
-        socket_enter_stop_pre(s, true);
-        return 0;
-}
-
-static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Socket *s = SOCKET(u);
-        SocketPort *p;
-        int r;
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", socket_state_to_string(s->state));
-        unit_serialize_item(u, f, "failure", yes_no(s->failure));
-        unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted);
-
-        if (s->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) s->control_pid);
-
-        if (s->control_command_id >= 0)
-                unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id));
-
-        LIST_FOREACH(port, p, s->ports) {
-                int copy;
-
-                if (p->fd < 0)
-                        continue;
-
-                if ((copy = fdset_put_dup(fds, p->fd)) < 0)
-                        return copy;
-
-                if (p->type == SOCKET_SOCKET) {
-                        char *t;
-
-                        if ((r = socket_address_print(&p->address, &t)) < 0)
-                                return r;
-
-                        unit_serialize_item_format(u, f, "socket", "%i %s", copy, t);
-                        free(t);
-                } else {
-                        assert(p->type == SOCKET_FIFO);
-                        unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path);
-                }
-        }
-
-        return 0;
-}
-
-static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Socket *s = SOCKET(u);
-        int r;
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                SocketState state;
-
-                if ((state = socket_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        s->deserialized_state = state;
-        } else if (streq(key, "failure")) {
-                int b;
-
-                if ((b = parse_boolean(value)) < 0)
-                        log_debug("Failed to parse failure value %s", value);
-                else
-                        s->failure = b || s->failure;
-
-        } else if (streq(key, "n-accepted")) {
-                unsigned k;
-
-                if ((r = safe_atou(value, &k)) < 0)
-                        log_debug("Failed to parse n-accepted value %s", value);
-                else
-                        s->n_accepted += k;
-        } else if (streq(key, "control-pid")) {
-                unsigned pid;
-
-                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        s->control_pid = (pid_t) pid;
-        } else if (streq(key, "control-command")) {
-                SocketExecCommand id;
-
-                if ((id = socket_exec_command_from_string(value)) < 0)
-                        log_debug("Failed to parse exec-command value %s", value);
-                else {
-                        s->control_command_id = id;
-                        s->control_command = s->exec_command[id];
-                }
-        } else if (streq(key, "fifo")) {
-                int fd, skip = 0;
-                SocketPort *p;
-
-                if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
-                        log_debug("Failed to parse fifo value %s", value);
-                else {
-
-                        LIST_FOREACH(port, p, s->ports)
-                                if (streq(p->path, value+skip))
-                                        break;
-
-                        if (p) {
-                                if (p->fd >= 0)
-                                        close_nointr_nofail(p->fd);
-                                p->fd = fdset_remove(fds, fd);
-                        }
-                }
-
-        } else if (streq(key, "socket")) {
-                int fd, skip = 0;
-                SocketPort *p;
-
-                if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
-                        log_debug("Failed to parse socket value %s", value);
-                else {
-
-                        LIST_FOREACH(port, p, s->ports)
-                                if (socket_address_is(&p->address, value+skip))
-                                        break;
-
-                        if (p) {
-                                if (p->fd >= 0)
-                                        close_nointr_nofail(p->fd);
-                                p->fd = fdset_remove(fds, fd);
-                        }
-                }
-
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState socket_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[SOCKET(u)->state];
-}
-
-static const char *socket_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return socket_state_to_string(SOCKET(u)->state);
-}
-
-static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
-        Socket *s = SOCKET(u);
-        int cfd = -1;
-
-        assert(s);
-        assert(fd >= 0);
-
-        log_debug("Incoming traffic on %s", u->meta.id);
-
-        if (events != EPOLLIN) {
-                log_error("Got invalid poll event on socket.");
-                goto fail;
-        }
-
-        if (w->socket_accept) {
-                for (;;) {
-
-                        if ((cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK)) < 0) {
-
-                                if (errno == EINTR)
-                                        continue;
-
-                                log_error("Failed to accept socket: %m");
-                                goto fail;
-                        }
-
-                        break;
-                }
-        }
-
-        socket_enter_running(s, cfd);
-        return;
-
-fail:
-        socket_enter_stop_pre(s, false);
-}
-
-static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-        Socket *s = SOCKET(u);
-        bool success;
-
-        assert(s);
-        assert(pid >= 0);
-
-        success = is_clean_exit(code, status);
-        s->failure = s->failure || !success;
-
-        assert(s->control_pid == pid);
-        s->control_pid = 0;
-
-        if (s->control_command)
-                exec_status_fill(&s->control_command->exec_status, pid, code, status);
-
-        log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
-
-        if (s->control_command && s->control_command->command_next && success) {
-                log_debug("%s running next command for state %s", u->meta.id, socket_state_to_string(s->state));
-                socket_run_next(s, success);
-        } else {
-                s->control_command = NULL;
-                s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
-
-                /* No further commands for this step, so let's figure
-                 * out what to do next */
-
-                log_debug("%s got final SIGCHLD for state %s", u->meta.id, socket_state_to_string(s->state));
-
-                switch (s->state) {
-
-                case SOCKET_START_PRE:
-                        if (success)
-                                socket_enter_start_post(s);
-                        else
-                                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
-                        break;
-
-                case SOCKET_START_POST:
-                        if (success)
-                                socket_enter_listening(s);
-                        else
-                                socket_enter_stop_pre(s, false);
-                        break;
-
-                case SOCKET_STOP_PRE:
-                case SOCKET_STOP_PRE_SIGTERM:
-                case SOCKET_STOP_PRE_SIGKILL:
-                        socket_enter_stop_post(s, success);
-                        break;
-
-                case SOCKET_STOP_POST:
-                case SOCKET_FINAL_SIGTERM:
-                case SOCKET_FINAL_SIGKILL:
-                        socket_enter_dead(s, success);
-                        break;
-
-                default:
-                        assert_not_reached("Uh, control process died at wrong time.");
-                }
-        }
-}
-
-static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-        assert(elapsed == 1);
-        assert(w == &s->timer_watch);
-
-        switch (s->state) {
-
-        case SOCKET_START_PRE:
-                log_warning("%s starting timed out. Terminating.", u->meta.id);
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
-
-        case SOCKET_START_POST:
-                log_warning("%s starting timed out. Stopping.", u->meta.id);
-                socket_enter_stop_pre(s, false);
-                break;
-
-        case SOCKET_STOP_PRE:
-                log_warning("%s stopping timed out. Terminating.", u->meta.id);
-                socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, false);
-                break;
-
-        case SOCKET_STOP_PRE_SIGTERM:
-                log_warning("%s stopping timed out. Killing.", u->meta.id);
-                socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false);
-                break;
-
-        case SOCKET_STOP_PRE_SIGKILL:
-                log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id);
-                socket_enter_stop_post(s, false);
-                break;
-
-        case SOCKET_STOP_POST:
-                log_warning("%s stopping timed out (2). Terminating.", u->meta.id);
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
-                break;
-
-        case SOCKET_FINAL_SIGTERM:
-                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
-                socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false);
-                break;
-
-        case SOCKET_FINAL_SIGKILL:
-                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", u->meta.id);
-                socket_enter_dead(s, false);
-                break;
-
-        default:
-                assert_not_reached("Timeout at wrong time.");
-        }
-}
-
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
-        int *rfds;
-        unsigned rn_fds, k;
-        SocketPort *p;
-
-        assert(s);
-        assert(fds);
-        assert(n_fds);
-
-        /* Called from the service code for requesting our fds */
-
-        rn_fds = 0;
-        LIST_FOREACH(port, p, s->ports)
-                if (p->fd >= 0)
-                        rn_fds++;
-
-        if (!(rfds = new(int, rn_fds)) < 0)
-                return -ENOMEM;
-
-        k = 0;
-        LIST_FOREACH(port, p, s->ports)
-                if (p->fd >= 0)
-                        rfds[k++] = p->fd;
-
-        assert(k == rn_fds);
-
-        *fds = rfds;
-        *n_fds = rn_fds;
-
-        return 0;
-}
-
-void socket_notify_service_dead(Socket *s) {
-        assert(s);
-
-        /* The service is dead. Dang. */
-
-        if (s->state == SOCKET_RUNNING) {
-                log_debug("%s got notified about service death.", s->meta.id);
-                socket_enter_listening(s);
-        }
-}
-
-static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
-        [SOCKET_DEAD] = "dead",
-        [SOCKET_START_PRE] = "start-pre",
-        [SOCKET_START_POST] = "start-post",
-        [SOCKET_LISTENING] = "listening",
-        [SOCKET_RUNNING] = "running",
-        [SOCKET_STOP_PRE] = "stop-pre",
-        [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
-        [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
-        [SOCKET_STOP_POST] = "stop-post",
-        [SOCKET_FINAL_SIGTERM] = "final-sigterm",
-        [SOCKET_FINAL_SIGKILL] = "final-sigkill",
-        [SOCKET_MAINTAINANCE] = "maintainance"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
-
-static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
-        [SOCKET_EXEC_START_PRE] = "StartPre",
-        [SOCKET_EXEC_START_POST] = "StartPost",
-        [SOCKET_EXEC_STOP_PRE] = "StopPre",
-        [SOCKET_EXEC_STOP_POST] = "StopPost"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
-
-const UnitVTable socket_vtable = {
-        .suffix = ".socket",
-
-        .init = socket_init,
-        .done = socket_done,
-        .load = socket_load,
-
-        .coldplug = socket_coldplug,
-
-        .dump = socket_dump,
-
-        .start = socket_start,
-        .stop = socket_stop,
-
-        .serialize = socket_serialize,
-        .deserialize_item = socket_deserialize_item,
-
-        .active_state = socket_active_state,
-        .sub_state_to_string = socket_sub_state_to_string,
-
-        .fd_event = socket_fd_event,
-        .sigchld_event = socket_sigchld_event,
-        .timer_event = socket_timer_event,
-
-        .bus_message_handler = bus_socket_message_handler
-};
diff --git a/socket.h b/socket.h
deleted file mode 100644
index 43d28d7..0000000
--- a/socket.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foosockethfoo
-#define foosockethfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Socket Socket;
-
-#include "manager.h"
-#include "unit.h"
-#include "socket-util.h"
-#include "mount.h"
-
-typedef enum SocketState {
-        SOCKET_DEAD,
-        SOCKET_START_PRE,
-        SOCKET_START_POST,
-        SOCKET_LISTENING,
-        SOCKET_RUNNING,
-        SOCKET_STOP_PRE,
-        SOCKET_STOP_PRE_SIGTERM,
-        SOCKET_STOP_PRE_SIGKILL,
-        SOCKET_STOP_POST,
-        SOCKET_FINAL_SIGTERM,
-        SOCKET_FINAL_SIGKILL,
-        SOCKET_MAINTAINANCE,
-        _SOCKET_STATE_MAX,
-        _SOCKET_STATE_INVALID = -1
-} SocketState;
-
-typedef enum SocketExecCommand {
-        SOCKET_EXEC_START_PRE,
-        SOCKET_EXEC_START_POST,
-        SOCKET_EXEC_STOP_PRE,
-        SOCKET_EXEC_STOP_POST,
-        _SOCKET_EXEC_COMMAND_MAX,
-        _SOCKET_EXEC_COMMAND_INVALID = -1
-} SocketExecCommand;
-
-typedef enum SocketType {
-        SOCKET_SOCKET,
-        SOCKET_FIFO,
-        _SOCKET_FIFO_MAX,
-        _SOCKET_FIFO_INVALID = -1
-} SocketType;
-
-typedef struct SocketPort SocketPort;
-
-struct SocketPort {
-        SocketType type;
-        int fd;
-
-        SocketAddress address;
-        char *path;
-
-        Watch fd_watch;
-
-        LIST_FIELDS(SocketPort, port);
-};
-
-struct Socket {
-        Meta meta;
-
-        LIST_HEAD(SocketPort, ports);
-
-        /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
-        bool bind_ipv6_only;
-        unsigned backlog;
-
-        usec_t timeout_usec;
-
-        ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        Service *service;
-
-        SocketState state, deserialized_state;
-
-        KillMode kill_mode;
-
-        ExecCommand* control_command;
-        SocketExecCommand control_command_id;
-        pid_t control_pid;
-
-        char *bind_to_device;
-        mode_t directory_mode;
-        mode_t socket_mode;
-
-        bool accept;
-        unsigned n_accepted;
-
-        bool failure;
-        Watch timer_watch;
-};
-
-/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
-
-/* Called from the service when it shut down */
-void socket_notify_service_dead(Socket *s);
-
-/* Called from the mount code figure out if a mount is a dependency of
- * any of the sockets of this socket */
-int socket_add_one_mount_link(Socket *s, Mount *m);
-
-extern const UnitVTable socket_vtable;
-
-const char* socket_state_to_string(SocketState i);
-SocketState socket_state_from_string(const char *s);
-
-const char* socket_exec_command_to_string(SocketExecCommand i);
-SocketExecCommand socket_exec_command_from_string(const char *s);
-
-#endif
diff --git a/specifier.c b/specifier.c
deleted file mode 100644
index d8472e9..0000000
--- a/specifier.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-
-#include "macro.h"
-#include "util.h"
-#include "specifier.h"
-
-/*
- * Generic infrastructure for replacing %x style specifiers in
- * strings. Will call a callback for each replacement.
- *
- */
-
-char *specifier_printf(const char *text, const Specifier table[], void *userdata) {
-        char *r, *t;
-        const char *f;
-        bool percent = false;
-        size_t l;
-
-        assert(text);
-        assert(table);
-
-        l = strlen(text);
-        if (!(r = new(char, l+1)))
-                return NULL;
-
-        t = r;
-
-        for (f = text; *f; f++, l--) {
-
-                if (percent) {
-                        if (*f == '%')
-                                *(t++) = '%';
-                        else {
-                                const Specifier *i;
-
-                                for (i = table; i->specifier; i++)
-                                        if (i->specifier == *f)
-                                                break;
-
-                                if (i->lookup) {
-                                        char *n, *w;
-                                        size_t k, j;
-
-                                        if (!(w = i->lookup(i->specifier, i->data, userdata))) {
-                                                free(r);
-                                                return NULL;
-                                        }
-
-                                        j = t - r;
-                                        k = strlen(w);
-
-                                        if (!(n = new(char, j + k + l + 1))) {
-                                                free(r);
-                                                free(w);
-                                                return NULL;
-                                        }
-
-                                        memcpy(n, r, j);
-                                        memcpy(n + j, w, k);
-
-                                        free(r);
-                                        free(w);
-
-                                        r = n;
-                                        t = n + j + k;
-                                } else {
-                                        *(t++) = '%';
-                                        *(t++) = *f;
-                                }
-                        }
-
-                        percent = false;
-                } else if (*f == '%')
-                        percent = true;
-                else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-        return r;
-}
-
-/* Generic handler for simple string replacements */
-
-char* specifier_string(char specifier, void *data, void *userdata) {
-        assert(data);
-
-        return strdup(strempty(data));
-}
diff --git a/specifier.h b/specifier.h
deleted file mode 100644
index 4b3b94c..0000000
--- a/specifier.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foospecifierhfoo
-#define foospecifierhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata);
-
-typedef struct Specifier {
-        const char specifier;
-        const SpecifierCallback lookup;
-        void *data;
-} Specifier;
-
-char *specifier_printf(const char *text, const Specifier table[], void *userdata);
-
-char* specifier_string(char specifier, void *data, void *userdata);
-
-#endif
diff --git a/src/automount.c b/src/automount.c
new file mode 100644
index 0000000..465354f
--- /dev/null
+++ b/src/automount.c
@@ -0,0 +1,784 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <linux/auto_fs4.h>
+#include <linux/auto_dev-ioctl.h>
+
+#include "unit.h"
+#include "automount.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "unit-name.h"
+#include "dbus-automount.h"
+
+static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
+        [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
+        [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
+        [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
+        [AUTOMOUNT_MAINTAINANCE] = UNIT_INACTIVE,
+};
+
+static int open_dev_autofs(Manager *m);
+
+static void automount_init(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        a->pipe_watch.fd = a->pipe_fd = -1;
+        a->pipe_watch.type = WATCH_INVALID;
+}
+
+static void repeat_unmout(const char *path) {
+        assert(path);
+
+        for (;;) {
+
+                if (umount2(path, MNT_DETACH) >= 0)
+                        continue;
+
+                if (errno != EINVAL)
+                        log_error("Failed to unmount: %m");
+
+                break;
+        }
+}
+
+static void unmount_autofs(Automount *a) {
+        assert(a);
+
+        if (a->pipe_fd < 0)
+                return;
+
+        automount_send_ready(a, -EHOSTDOWN);
+
+        unit_unwatch_fd(UNIT(a), &a->pipe_watch);
+        close_nointr_nofail(a->pipe_fd);
+        a->pipe_fd = -1;
+
+        /* If we reload/reexecute things we keep the mount point
+         * around */
+        if (a->where &&
+            (UNIT(a)->meta.manager->exit_code != MANAGER_RELOAD &&
+             UNIT(a)->meta.manager->exit_code != MANAGER_REEXECUTE))
+                repeat_unmout(a->where);
+}
+
+static void automount_done(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        unmount_autofs(a);
+        a->mount = NULL;
+
+        free(a->where);
+        a->where = NULL;
+
+        set_free(a->tokens);
+        a->tokens = NULL;
+}
+
+int automount_add_one_mount_link(Automount *a, Mount *m) {
+        int r;
+
+        assert(a);
+        assert(m);
+
+        if (a->meta.load_state != UNIT_LOADED ||
+            m->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (!path_startswith(a->where, m->where))
+                return 0;
+
+        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(a), true)) < 0)
+                return r;
+
+        if ((r = unit_add_dependency(UNIT(a), UNIT_REQUIRES, UNIT(m), true)) < 0)
+                return r;
+
+        return 0;
+}
+
+static int automount_add_mount_links(Automount *a) {
+        Meta *other;
+        int r;
+
+        assert(a);
+
+        LIST_FOREACH(units_per_type, other, a->meta.manager->units_per_type[UNIT_MOUNT])
+                if ((r = automount_add_one_mount_link(a, (Mount*) other)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int automount_verify(Automount *a) {
+        bool b;
+        char *e;
+        assert(a);
+
+        if (UNIT(a)->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (!(e = unit_name_from_path(a->where, ".automount")))
+                return -ENOMEM;
+
+        b = unit_has_name(UNIT(a), e);
+        free(e);
+
+        if (!b) {
+                log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->meta.id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int automount_load(Unit *u) {
+        int r;
+        Automount *a = AUTOMOUNT(u);
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        /* Load a .automount file */
+        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
+                return r;
+
+        if (u->meta.load_state == UNIT_LOADED) {
+
+                if (!a->where)
+                        if (!(a->where = unit_name_to_path(u->meta.id)))
+                                return -ENOMEM;
+
+                path_kill_slashes(a->where);
+
+                if ((r = automount_add_mount_links(a)) < 0)
+                        return r;
+
+                if ((r = unit_load_related_unit(u, ".mount", (Unit**) &a->mount)) < 0)
+                        return r;
+
+                if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(a->mount), true)) < 0)
+                        return r;
+        }
+
+        return automount_verify(a);
+}
+
+static void automount_set_state(Automount *a, AutomountState state) {
+        AutomountState old_state;
+        assert(a);
+
+        old_state = a->state;
+        a->state = state;
+
+        if (state != AUTOMOUNT_WAITING &&
+            state != AUTOMOUNT_RUNNING)
+                unmount_autofs(a);
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(a)->meta.id,
+                          automount_state_to_string(old_state),
+                          automount_state_to_string(state));
+
+        unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int automount_coldplug(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+        int r;
+
+        assert(a);
+        assert(a->state == AUTOMOUNT_DEAD);
+
+        if (a->deserialized_state != a->state) {
+
+                if ((r = open_dev_autofs(u->meta.manager)) < 0)
+                        return r;
+
+                if (a->deserialized_state == AUTOMOUNT_WAITING ||
+                    a->deserialized_state == AUTOMOUNT_RUNNING) {
+
+                        assert(a->pipe_fd >= 0);
+
+                        if ((r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch)) < 0)
+                                return r;
+                }
+
+                automount_set_state(a, a->deserialized_state);
+        }
+
+        return 0;
+}
+
+static void automount_dump(Unit *u, FILE *f, const char *prefix) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        fprintf(f,
+                "%sAutomount State: %s\n"
+                "%sWhere: %s\n",
+                prefix, automount_state_to_string(a->state),
+                prefix, a->where);
+}
+
+static void automount_enter_dead(Automount *a, bool success) {
+        assert(a);
+
+        if (!success)
+                a->failure = true;
+
+        automount_set_state(a, a->failure ? AUTOMOUNT_MAINTAINANCE : AUTOMOUNT_DEAD);
+}
+
+static int open_dev_autofs(Manager *m) {
+        struct autofs_dev_ioctl param;
+
+        assert(m);
+
+        if (m->dev_autofs_fd >= 0)
+                return m->dev_autofs_fd;
+
+        if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) {
+                log_error("Failed to open /dev/autofs: %s", strerror(errno));
+                return -errno;
+        }
+
+        init_autofs_dev_ioctl(&param);
+        if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
+                close_nointr_nofail(m->dev_autofs_fd);
+                m->dev_autofs_fd = -1;
+                return -errno;
+        }
+
+        log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
+
+        return m->dev_autofs_fd;
+}
+
+static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
+        struct autofs_dev_ioctl *param;
+        size_t l;
+        int r;
+
+        assert(dev_autofs_fd >= 0);
+        assert(where);
+
+        l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
+
+        if (!(param = malloc(l)))
+                return -ENOMEM;
+
+        init_autofs_dev_ioctl(param);
+        param->size = l;
+        param->ioctlfd = -1;
+        param->openmount.devid = devid;
+        strcpy(param->path, where);
+
+        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (param->ioctlfd < 0) {
+                r = -EIO;
+                goto finish;
+        }
+
+        fd_cloexec(param->ioctlfd, true);
+        r = param->ioctlfd;
+
+finish:
+        free(param);
+        return r;
+}
+
+static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
+        uint32_t major, minor;
+        struct autofs_dev_ioctl param;
+
+        assert(dev_autofs_fd >= 0);
+        assert(ioctl_fd >= 0);
+
+        init_autofs_dev_ioctl(&param);
+        param.ioctlfd = ioctl_fd;
+
+        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
+                return -errno;
+
+        major = param.protover.version;
+
+        init_autofs_dev_ioctl(&param);
+        param.ioctlfd = ioctl_fd;
+
+        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
+                return -errno;
+
+        minor = param.protosubver.sub_version;
+
+        log_debug("Autofs protocol version %i.%i", major, minor);
+        return 0;
+}
+
+static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
+        struct autofs_dev_ioctl param;
+
+        assert(dev_autofs_fd >= 0);
+        assert(ioctl_fd >= 0);
+
+        init_autofs_dev_ioctl(&param);
+        param.ioctlfd = ioctl_fd;
+        param.timeout.timeout = sec;
+
+        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
+        struct autofs_dev_ioctl param;
+
+        assert(dev_autofs_fd >= 0);
+        assert(ioctl_fd >= 0);
+
+        init_autofs_dev_ioctl(&param);
+        param.ioctlfd = ioctl_fd;
+
+        if (status) {
+                param.fail.token = token;
+                param.fail.status = status;
+        } else
+                param.ready.token = token;
+
+        if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int automount_send_ready(Automount *a, int status) {
+        int ioctl_fd, r;
+        unsigned token;
+
+        assert(a);
+        assert(status <= 0);
+
+        if (set_isempty(a->tokens))
+                return 0;
+
+        if ((ioctl_fd = open_ioctl_fd(UNIT(a)->meta.manager->dev_autofs_fd, a->where, a->dev_id)) < 0) {
+                r = ioctl_fd;
+                goto fail;
+        }
+
+        if (status)
+                log_debug("Sending failure: %s", strerror(-status));
+        else
+                log_debug("Sending success.");
+
+        /* Autofs thankfully does not hand out 0 as a token */
+        while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
+                int k;
+
+                /* Autofs fun fact II:
+                 *
+                 * if you pass a positive status code here, the kernel will
+                 * freeze! Yay! */
+
+                if ((k = autofs_send_ready(UNIT(a)->meta.manager->dev_autofs_fd,
+                                           ioctl_fd,
+                                           token,
+                                           status)) < 0)
+                        r = k;
+        }
+
+        r = 0;
+
+fail:
+        if (ioctl_fd >= 0)
+                close_nointr_nofail(ioctl_fd);
+
+        return r;
+}
+
+static void automount_enter_waiting(Automount *a) {
+        int p[2] = { -1, -1 };
+        char name[32], options[128];
+        bool mounted = false;
+        int r, ioctl_fd = -1, dev_autofs_fd;
+        struct stat st;
+
+        assert(a);
+        assert(a->pipe_fd < 0);
+        assert(a->where);
+
+        if (a->tokens)
+                set_clear(a->tokens);
+
+        if ((dev_autofs_fd = open_dev_autofs(UNIT(a)->meta.manager)) < 0) {
+                r = dev_autofs_fd;
+                goto fail;
+        }
+
+        /* We knowingly ignore the results of this call */
+        mkdir_p(a->where, 0555);
+
+        if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp());
+        char_array_0(options);
+
+        snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid());
+        char_array_0(name);
+
+        if (mount(name, a->where, "autofs", 0, options) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        mounted = true;
+
+        close_nointr_nofail(p[1]);
+        p[1] = -1;
+
+        if (stat(a->where, &st) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if ((ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev)) < 0) {
+                r = ioctl_fd;
+                goto fail;
+        }
+
+        if ((r = autofs_protocol(dev_autofs_fd, ioctl_fd)) < 0)
+                goto fail;
+
+        if ((r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300)) < 0)
+                goto fail;
+
+        /* Autofs fun fact:
+         *
+         * Unless we close the ioctl fd here, for some weird reason
+         * the direct mount will not receive events from the
+         * kernel. */
+
+        close_nointr_nofail(ioctl_fd);
+        ioctl_fd = -1;
+
+        if ((r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch)) < 0)
+                goto fail;
+
+        a->pipe_fd = p[0];
+        a->dev_id = st.st_dev;
+
+        automount_set_state(a, AUTOMOUNT_WAITING);
+
+        return;
+
+fail:
+        assert_se(close_pipe(p) == 0);
+
+        if (ioctl_fd >= 0)
+                close_nointr_nofail(ioctl_fd);
+
+        if (mounted)
+                repeat_unmout(a->where);
+
+        log_error("Failed to initialize automounter: %s", strerror(-r));
+        automount_enter_dead(a, false);
+}
+
+static void automount_enter_runnning(Automount *a) {
+        int r;
+        struct stat st;
+
+        assert(a);
+        assert(a->mount);
+
+        /* Before we do anything, let's see if somebody is playing games with us? */
+
+        if (stat(a->where, &st) < 0) {
+                log_warning("%s failed stat automount point: %m", a->meta.id);
+                goto fail;
+        }
+
+        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
+                log_info("%s's automount point already active?", a->meta.id);
+        else if ((r = manager_add_job(UNIT(a)->meta.manager, JOB_START, UNIT(a->mount), JOB_REPLACE, true, NULL)) < 0) {
+                log_warning("%s failed to queue mount startup job: %s", a->meta.id, strerror(-r));
+                goto fail;
+        }
+
+        automount_set_state(a, AUTOMOUNT_RUNNING);
+        return;
+
+fail:
+        automount_enter_dead(a, false);
+}
+
+static int automount_start(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        if (path_is_mount_point(a->where)) {
+                log_error("Path %s is already a mount point, refusing start for %s", a->where, u->meta.id);
+                return -EEXIST;
+        }
+
+        assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_MAINTAINANCE);
+
+        a->failure = false;
+        automount_enter_waiting(a);
+        return 0;
+}
+
+static int automount_stop(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
+
+        automount_enter_dead(a, true);
+        return 0;
+}
+
+static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Automount *a = AUTOMOUNT(u);
+        void *p;
+        Iterator i;
+
+        assert(a);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
+        unit_serialize_item(u, f, "failure", yes_no(a->failure));
+        unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
+
+        SET_FOREACH(p, a->tokens, i)
+                unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
+
+        if (a->pipe_fd >= 0) {
+                int copy;
+
+                if ((copy = fdset_put_dup(fds, a->pipe_fd)) < 0)
+                        return copy;
+
+                unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
+        }
+
+        return 0;
+}
+
+static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Automount *a = AUTOMOUNT(u);
+        int r;
+
+        assert(a);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                AutomountState state;
+
+                if ((state = automount_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        a->deserialized_state = state;
+        } else if (streq(key, "failure")) {
+                int b;
+
+                if ((b = parse_boolean(value)) < 0)
+                        log_debug("Failed to parse failure value %s", value);
+                else
+                        a->failure = b || a->failure;
+        } else if (streq(key, "dev-id")) {
+                unsigned d;
+
+                if (safe_atou(value, &d) < 0)
+                        log_debug("Failed to parse dev-id value %s", value);
+                else
+                        a->dev_id = (unsigned) d;
+        } else if (streq(key, "token")) {
+                unsigned token;
+
+                if (safe_atou(value, &token) < 0)
+                        log_debug("Failed to parse token value %s", value);
+                else {
+                        if (!a->tokens)
+                                if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func)))
+                                        return -ENOMEM;
+
+                        if ((r = set_put(a->tokens, UINT_TO_PTR(token))) < 0)
+                                return r;
+                }
+        } else if (streq(key, "pipe-fd")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                        log_debug("Failed to parse pipe-fd value %s", value);
+                else {
+                        if (a->pipe_fd >= 0)
+                                close_nointr_nofail(a->pipe_fd);
+
+                        a->pipe_fd = fdset_remove(fds, fd);
+                }
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState automount_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[AUTOMOUNT(u)->state];
+}
+
+static const char *automount_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return automount_state_to_string(AUTOMOUNT(u)->state);
+}
+
+static bool automount_check_gc(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        return UNIT_VTABLE(UNIT(a->mount))->check_gc(UNIT(a->mount));
+}
+
+static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
+        Automount *a = AUTOMOUNT(u);
+        union autofs_v5_packet_union packet;
+        ssize_t l;
+        int r;
+
+        assert(a);
+        assert(fd == a->pipe_fd);
+
+        if (events != EPOLLIN) {
+                log_error("Got invalid poll event on pipe.");
+                goto fail;
+        }
+
+        if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet))) != sizeof(packet)) {
+                log_error("Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
+                goto fail;
+        }
+
+        switch (packet.hdr.type) {
+
+        case autofs_ptype_missing_direct:
+                log_debug("Got direct mount request for %s", packet.v5_packet.name);
+
+                if (!a->tokens)
+                        if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) {
+                                log_error("Failed to allocate token set.");
+                                goto fail;
+                        }
+
+                if ((r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token))) < 0) {
+                        log_error("Failed to remember token: %s", strerror(-r));
+                        goto fail;
+                }
+
+                automount_enter_runnning(a);
+                break;
+
+        default:
+                log_error("Received unknown automount request %i", packet.hdr.type);
+                break;
+        }
+
+        return;
+
+fail:
+        automount_enter_dead(a, false);
+}
+
+static void automount_shutdown(Manager *m) {
+        assert(m);
+
+        if (m->dev_autofs_fd >= 0)
+                close_nointr_nofail(m->dev_autofs_fd);
+}
+
+static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
+        [AUTOMOUNT_DEAD] = "dead",
+        [AUTOMOUNT_WAITING] = "waiting",
+        [AUTOMOUNT_RUNNING] = "running",
+        [AUTOMOUNT_MAINTAINANCE] = "maintainance"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
+
+const UnitVTable automount_vtable = {
+        .suffix = ".automount",
+
+        .no_alias = true,
+        .no_instances = true,
+
+        .init = automount_init,
+        .load = automount_load,
+        .done = automount_done,
+
+        .coldplug = automount_coldplug,
+
+        .dump = automount_dump,
+
+        .start = automount_start,
+        .stop = automount_stop,
+
+        .serialize = automount_serialize,
+        .deserialize_item = automount_deserialize_item,
+
+        .active_state = automount_active_state,
+        .sub_state_to_string = automount_sub_state_to_string,
+
+        .check_gc = automount_check_gc,
+
+        .fd_event = automount_fd_event,
+
+        .bus_message_handler = bus_automount_message_handler,
+
+        .shutdown = automount_shutdown
+};
diff --git a/src/automount.h b/src/automount.h
new file mode 100644
index 0000000..014482c
--- /dev/null
+++ b/src/automount.h
@@ -0,0 +1,65 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooautomounthfoo
+#define fooautomounthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Automount Automount;
+
+#include "unit.h"
+
+typedef enum AutomountState {
+        AUTOMOUNT_DEAD,
+        AUTOMOUNT_WAITING,
+        AUTOMOUNT_RUNNING,
+        AUTOMOUNT_MAINTAINANCE,
+        _AUTOMOUNT_STATE_MAX,
+        _AUTOMOUNT_STATE_INVALID = -1
+} AutomountState;
+
+struct Automount {
+        Meta meta;
+
+        AutomountState state, deserialized_state;
+
+        char *where;
+
+        Mount *mount;
+
+        int pipe_fd;
+        Watch pipe_watch;
+        dev_t dev_id;
+
+        Set *tokens;
+
+        bool failure:1;
+};
+
+extern const UnitVTable automount_vtable;
+
+int automount_send_ready(Automount *a, int status);
+
+int automount_add_one_mount_link(Automount *a, Mount *m);
+
+const char* automount_state_to_string(AutomountState i);
+AutomountState automount_state_from_string(const char *s);
+
+#endif
diff --git a/src/cgroup.c b/src/cgroup.c
new file mode 100644
index 0000000..301fc94
--- /dev/null
+++ b/src/cgroup.c
@@ -0,0 +1,561 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/mount.h>
+
+#include "cgroup.h"
+#include "log.h"
+
+static int translate_error(int error, int _errno) {
+
+        switch (error) {
+
+        case ECGROUPNOTCOMPILED:
+        case ECGROUPNOTMOUNTED:
+        case ECGROUPNOTEXIST:
+        case ECGROUPNOTCREATED:
+                return -ENOENT;
+
+        case ECGINVAL:
+                return -EINVAL;
+
+        case ECGROUPNOTALLOWED:
+                return -EPERM;
+
+        case ECGOTHER:
+                return -_errno;
+        }
+
+        return -EIO;
+}
+
+int cgroup_bonding_realize(CGroupBonding *b) {
+        int r;
+
+        assert(b);
+        assert(b->path);
+        assert(b->controller);
+
+        if (b->cgroup)
+                return 0;
+
+        if (!(b->cgroup = cgroup_new_cgroup(b->path)))
+                return -ENOMEM;
+
+        if (!cgroup_add_controller(b->cgroup, b->controller)) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (b->inherit)
+                r = cgroup_create_cgroup_from_parent(b->cgroup, true);
+        else
+                r = cgroup_create_cgroup(b->cgroup, true);
+
+        if (r != 0) {
+                r = translate_error(r, errno);
+                goto fail;
+        }
+
+        return 0;
+
+fail:
+        cgroup_free(&b->cgroup);
+        b->cgroup = NULL;
+        return r;
+}
+
+int cgroup_bonding_realize_list(CGroupBonding *first) {
+        CGroupBonding *b;
+
+        LIST_FOREACH(by_unit, b, first) {
+                int r;
+
+                if ((r = cgroup_bonding_realize(b)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+void cgroup_bonding_free(CGroupBonding *b) {
+        assert(b);
+
+        if (b->unit) {
+                CGroupBonding *f;
+
+                LIST_REMOVE(CGroupBonding, by_unit, b->unit->meta.cgroup_bondings, b);
+
+                assert_se(f = hashmap_get(b->unit->meta.manager->cgroup_bondings, b->path));
+                LIST_REMOVE(CGroupBonding, by_path, f, b);
+
+                if (f)
+                        hashmap_replace(b->unit->meta.manager->cgroup_bondings, b->path, f);
+                else
+                        hashmap_remove(b->unit->meta.manager->cgroup_bondings, b->path);
+        }
+
+        if (b->cgroup) {
+                if (b->only_us && b->clean_up && cgroup_bonding_is_empty(b) > 0)
+                        cgroup_delete_cgroup_ext(b->cgroup, true);
+
+                cgroup_free(&b->cgroup);
+        }
+
+        free(b->controller);
+        free(b->path);
+        free(b);
+}
+
+void cgroup_bonding_free_list(CGroupBonding *first) {
+        CGroupBonding *b, *n;
+
+        LIST_FOREACH_SAFE(by_unit, b, n, first)
+                cgroup_bonding_free(b);
+}
+
+int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
+        int r;
+
+        assert(b);
+        assert(pid >= 0);
+
+        if (pid == 0)
+                pid = getpid();
+
+        if (!b->cgroup)
+                return -ENOENT;
+
+        if ((r = cgroup_attach_task_pid(b->cgroup, pid)))
+                return translate_error(r, errno);
+
+        return 0;
+}
+
+int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
+        CGroupBonding *b;
+
+        LIST_FOREACH(by_unit, b, first) {
+                int r;
+
+                if ((r = cgroup_bonding_install(b, pid)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int cgroup_bonding_kill(CGroupBonding *b, int sig) {
+        int r;
+        Set *s;
+        bool done;
+        bool killed = false;
+
+        assert(b);
+        assert(sig > 0);
+
+        if (!b->only_us)
+                return -EAGAIN;
+
+        if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
+                return -ENOMEM;
+
+        do {
+                void *iterator;
+                pid_t pid;
+
+                done = true;
+
+                if ((r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid)) != 0) {
+                        if (r == ECGEOF) {
+                                r = 0;
+                                goto kill_done;
+                        } else {
+                                r = translate_error(r, errno);
+                                break;
+                        }
+                }
+
+                for (;;) {
+                        if (set_get(s, INT_TO_PTR(pid)) != INT_TO_PTR(pid)) {
+
+                                /* If we haven't killed this process
+                                 * yet, kill it */
+
+                                if (kill(pid, sig) < 0 && errno != ESRCH) {
+                                        r = -errno;
+                                        break;
+                                }
+
+                                killed = true;
+                                done = false;
+
+                                if ((r = set_put(s, INT_TO_PTR(pid))) < 0)
+                                    break;
+                        }
+
+                        if ((r = cgroup_get_task_next(&iterator, &pid)) != 0) {
+
+                                if (r == ECGEOF)
+                                        r = 0;
+                                else
+                                        r = translate_error(r, errno);
+
+                                break;
+                        }
+                }
+
+        kill_done:
+                assert_se(cgroup_get_task_end(&iterator) == 0);
+
+                /* To avoid racing against processes which fork
+                 * quicker than we can kill them we repeat this until
+                 * no new pids need to be killed. */
+
+        } while (!done && r >= 0);
+
+        set_free(s);
+
+        if (r < 0)
+                return r;
+
+        return killed ? 0 : -ESRCH;
+}
+
+int cgroup_bonding_kill_list(CGroupBonding *first, int sig) {
+        CGroupBonding *b;
+        int r = -EAGAIN;
+
+        LIST_FOREACH(by_unit, b, first) {
+                if ((r = cgroup_bonding_kill(b, sig)) < 0) {
+                        if (r == -EAGAIN || -ESRCH)
+                                continue;
+
+                        return r;
+                }
+
+                return 0;
+        }
+
+        return r;
+}
+
+/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
+ * cannot know */
+int cgroup_bonding_is_empty(CGroupBonding *b) {
+        void *iterator;
+        pid_t pid;
+        int r;
+
+        assert(b);
+
+        r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid);
+
+        if (r == 0 || r == ECGEOF)
+                cgroup_get_task_end(&iterator);
+
+        /* Hmm, no PID in this group? Then it is definitely empty */
+        if (r == ECGEOF)
+                return 1;
+
+        /* Some error? Let's return it */
+        if (r != 0)
+                return translate_error(r, errno);
+
+        /* It's not empty, and we are the only user, then it is
+         * definitely not empty */
+        if (b->only_us)
+                return 0;
+
+        /* There are PIDs in the group but we aren't the only users,
+         * hence we cannot say */
+        return -EAGAIN;
+}
+
+int cgroup_bonding_is_empty_list(CGroupBonding *first) {
+        CGroupBonding *b;
+
+        LIST_FOREACH(by_unit, b, first) {
+                int r;
+
+                if ((r = cgroup_bonding_is_empty(b)) < 0) {
+                        /* If this returned -EAGAIN, then we don't know if the
+                         * group is empty, so let's see if another group can
+                         * tell us */
+
+                        if (r != -EAGAIN)
+                                return r;
+                } else
+                        return r;
+        }
+
+        return -EAGAIN;
+}
+
+static int install_release_agent(Manager *m, const char *mount_point) {
+        char *p, *c, *sc;
+        int r;
+
+        assert(m);
+        assert(mount_point);
+
+        if (asprintf(&p, "%s/release_agent", mount_point) < 0)
+                return -ENOMEM;
+
+        if ((r = read_one_line_file(p, &c)) < 0) {
+                free(p);
+                return r;
+        }
+
+        sc = strstrip(c);
+
+        if (sc[0] == 0) {
+                if ((r = write_one_line_file(p, CGROUP_AGENT_PATH "\n" )) < 0) {
+                        free(p);
+                        free(c);
+                        return r;
+                }
+        } else if (!streq(sc, CGROUP_AGENT_PATH)) {
+                free(p);
+                free(c);
+                return -EEXIST;
+        }
+
+        free(c);
+        free(p);
+
+        if (asprintf(&p, "%s/notify_on_release", mount_point) < 0)
+                return -ENOMEM;
+
+        if ((r = read_one_line_file(p, &c)) < 0) {
+                free(p);
+                return r;
+        }
+
+        sc = strstrip(c);
+
+        if (streq(sc, "0")) {
+                if ((r = write_one_line_file(p, "1\n")) < 0) {
+                        free(p);
+                        free(c);
+                        return r;
+                }
+        } else if (!streq(sc, "1")) {
+                free(p);
+                free(c);
+                return -EIO;
+        }
+
+        free(p);
+        free(c);
+
+        return 0;
+}
+
+static int create_hierarchy_cgroup(Manager *m) {
+        struct cgroup *cg;
+        int r;
+
+        assert(m);
+
+        if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy)))
+                return -ENOMEM;
+
+        if (!(cgroup_add_controller(cg, m->cgroup_controller))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if ((r = cgroup_create_cgroup(cg, true)) != 0) {
+                log_error("Failed to create cgroup hierarchy group: %s", cgroup_strerror(r));
+                r = translate_error(r, errno);
+                goto finish;
+        }
+
+        if ((r = cgroup_attach_task(cg)) != 0) {
+                log_error("Failed to add ourselves to hierarchy group: %s", cgroup_strerror(r));
+                r = translate_error(r, errno);
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        cgroup_free(&cg);
+        return r;
+}
+
+int manager_setup_cgroup(Manager *m) {
+        char *mp, *cp;
+        int r;
+        pid_t pid;
+        char suffix[32];
+
+        assert(m);
+
+        if ((r = cgroup_init()) != 0) {
+                log_error("Failed to initialize libcg: %s", cgroup_strerror(r));
+                return translate_error(r, errno);
+        }
+
+        free(m->cgroup_controller);
+        if (!(m->cgroup_controller = strdup("debug")))
+                return -ENOMEM;
+
+        if ((r = cgroup_get_subsys_mount_point(m->cgroup_controller, &mp)))
+                return translate_error(r, errno);
+
+        pid = getpid();
+
+        if ((r = cgroup_get_current_controller_path(pid, m->cgroup_controller, &cp))) {
+                free(mp);
+                return translate_error(r, errno);
+        }
+
+        snprintf(suffix, sizeof(suffix), "/systemd-%u", (unsigned) pid);
+        char_array_0(suffix);
+
+        free(m->cgroup_hierarchy);
+
+        if (endswith(cp, suffix))
+                /* We probably got reexecuted and can continue to use our root cgroup */
+                m->cgroup_hierarchy = cp;
+        else {
+                /* We need a new root cgroup */
+
+                m->cgroup_hierarchy = NULL;
+                r = asprintf(&m->cgroup_hierarchy, "%s%s", streq(cp, "/") ? "" : cp, suffix);
+                free(cp);
+
+                if (r < 0) {
+                        free(mp);
+                        return -ENOMEM;
+                }
+        }
+
+        log_debug("Using cgroup controller <%s>, hierarchy mounted at <%s>, using root group <%s>.",
+                  m->cgroup_controller,
+                  mp,
+                  m->cgroup_hierarchy);
+
+        if ((r = install_release_agent(m, mp)) < 0)
+                log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
+        else
+                log_debug("Installed release agent, or already installed.");
+
+        free(mp);
+
+        if ((r = create_hierarchy_cgroup(m)) < 0)
+                log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
+        else
+                log_debug("Created root group.");
+
+        return r;
+}
+
+int manager_shutdown_cgroup(Manager *m, bool delete) {
+        struct cgroup *cg;
+        int r;
+
+        assert(m);
+
+        if (!m->cgroup_hierarchy)
+                return 0;
+
+        if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy)))
+                return -ENOMEM;
+
+        if (!(cgroup_add_controller(cg, m->cgroup_controller))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        /* Often enough we won't be able to delete the cgroup we
+         * ourselves are in, hence ignore all errors here */
+        if (delete)
+                cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_IGNORE_MIGRATION|CGFLAG_DELETE_RECURSIVE);
+        r = 0;
+
+finish:
+        cgroup_free(&cg);
+        return r;
+
+}
+
+int cgroup_notify_empty(Manager *m, const char *group) {
+        CGroupBonding *l, *b;
+
+        assert(m);
+        assert(group);
+
+        if (!(l = hashmap_get(m->cgroup_bondings, group)))
+                return 0;
+
+        LIST_FOREACH(by_path, b, l) {
+                int t;
+
+                if (!b->unit)
+                        continue;
+
+                if ((t = cgroup_bonding_is_empty_list(b)) < 0) {
+
+                        /* If we don't know, we don't know */
+                        if (t != -EAGAIN)
+                                log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
+
+                        continue;
+                }
+
+                if (t > 0)
+                        if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
+                                UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
+        }
+
+        return 0;
+}
+
+CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
+        CGroupBonding *b;
+
+        assert(controller);
+
+        LIST_FOREACH(by_unit, b, first)
+                if (streq(b->controller, controller))
+                        return b;
+
+        return NULL;
+}
+
+char *cgroup_bonding_to_string(CGroupBonding *b) {
+        char *r;
+
+        assert(b);
+
+        if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
+                return NULL;
+
+        return r;
+}
diff --git a/src/cgroup.h b/src/cgroup.h
new file mode 100644
index 0000000..d27c063
--- /dev/null
+++ b/src/cgroup.h
@@ -0,0 +1,82 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foocgrouphfoo
+#define foocgrouphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <libcgroup.h>
+
+typedef struct CGroupBonding CGroupBonding;
+
+#include "unit.h"
+
+/* Binds a cgroup to a name */
+struct CGroupBonding {
+        char *controller;
+        char *path;
+
+        Unit *unit;
+
+        struct cgroup *cgroup;
+
+        /* For the Unit::cgroup_bondings list */
+        LIST_FIELDS(CGroupBonding, by_unit);
+
+        /* For the Manager::cgroup_bondings hashmap */
+        LIST_FIELDS(CGroupBonding, by_path);
+
+        /* When shutting down, remove cgroup? */
+        bool clean_up:1;
+
+        /* When our tasks are the only ones in this group */
+        bool only_us:1;
+
+        /* Inherit parameters from parent group */
+        bool inherit:1;
+};
+
+int cgroup_bonding_realize(CGroupBonding *b);
+int cgroup_bonding_realize_list(CGroupBonding *first);
+
+void cgroup_bonding_free(CGroupBonding *b);
+void cgroup_bonding_free_list(CGroupBonding *first);
+
+int cgroup_bonding_install(CGroupBonding *b, pid_t pid);
+int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid);
+
+int cgroup_bonding_kill(CGroupBonding *b, int sig);
+int cgroup_bonding_kill_list(CGroupBonding *first, int sig);
+
+int cgroup_bonding_is_empty(CGroupBonding *b);
+int cgroup_bonding_is_empty_list(CGroupBonding *first);
+
+CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller);
+
+char *cgroup_bonding_to_string(CGroupBonding *b);
+
+#include "manager.h"
+
+int manager_setup_cgroup(Manager *m);
+int manager_shutdown_cgroup(Manager *m, bool delete);
+
+int cgroup_notify_empty(Manager *m, const char *group);
+
+#endif
diff --git a/src/cgroups-agent.c b/src/cgroups-agent.c
new file mode 100644
index 0000000..232b63e
--- /dev/null
+++ b/src/cgroups-agent.c
@@ -0,0 +1,72 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "log.h"
+
+int main(int argc, char *argv[]) {
+        DBusError error;
+        DBusConnection *bus = NULL;
+        DBusMessage *m = NULL;
+        int r = 1;
+
+        dbus_error_init(&error);
+
+        if (argc != 2) {
+                log_error("Incorrect number of arguments.");
+                goto finish;
+        }
+
+        if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+                log_error("Failed to get D-Bus connection: %s", error.message);
+                goto finish;
+        }
+
+        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1/agent", "org.freedesktop.systemd1.Agent", "Released"))) {
+                log_error("Could not allocate signal message.");
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &argv[1],
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not attach group information to signal message.");
+                goto finish;
+        }
+
+        if (!dbus_connection_send(bus, m, NULL)) {
+                log_error("Failed to send signal message.");
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (bus)
+                dbus_connection_unref(bus);
+
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+        return r;
+}
diff --git a/src/conf-parser.c b/src/conf-parser.c
new file mode 100644
index 0000000..6994211
--- /dev/null
+++ b/src/conf-parser.c
@@ -0,0 +1,460 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "conf-parser.h"
+#include "util.h"
+#include "macro.h"
+#include "strv.h"
+#include "log.h"
+
+#define COMMENTS "#;\n"
+#define LINE_MAX 4096
+
+/* Run the user supplied parser for an assignment */
+static int next_assignment(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const ConfigItem *t,
+                const char *lvalue,
+                const char *rvalue,
+                void *userdata) {
+
+        assert(filename);
+        assert(t);
+        assert(lvalue);
+        assert(rvalue);
+
+        for (; t->parse; t++) {
+
+                if (t->lvalue && !streq(lvalue, t->lvalue))
+                        continue;
+
+                if (t->section && !section)
+                        continue;
+
+                if (t->section && !streq(section, t->section))
+                        continue;
+
+                return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
+        }
+
+        /* Warn about unknown non-extension fields. */
+        if (!startswith(lvalue, "X-"))
+                log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
+
+        return 0;
+}
+
+/* Parse a variable assignment line */
+static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
+        char *e;
+
+        l = strstrip(l);
+
+        if (!*l)
+                return 0;
+
+        if (strchr(COMMENTS, *l))
+                return 0;
+
+        if (startswith(l, ".include ")) {
+                char *fn;
+                int r;
+
+                if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
+                        return -ENOMEM;
+
+                r = config_parse(fn, NULL, sections, t, userdata);
+                free(fn);
+
+                return r;
+        }
+
+        if (*l == '[') {
+                size_t k;
+                char *n;
+
+                k = strlen(l);
+                assert(k > 0);
+
+                if (l[k-1] != ']') {
+                        log_error("[%s:%u] Invalid section header.", filename, line);
+                        return -EBADMSG;
+                }
+
+                if (!(n = strndup(l+1, k-2)))
+                        return -ENOMEM;
+
+                if (sections && !strv_contains((char**) sections, n)) {
+                        log_error("[%s:%u] Unknown section '%s'.", filename, line, n);
+                        free(n);
+                        return -EBADMSG;
+                }
+
+                free(*section);
+                *section = n;
+
+                return 0;
+        }
+
+        if (!(e = strchr(l, '='))) {
+                log_error("[%s:%u] Missing '='.", filename, line);
+                return -EBADMSG;
+        }
+
+        *e = 0;
+        e++;
+
+        return next_assignment(filename, line, *section, t, strstrip(l), strstrip(e), userdata);
+}
+
+/* Go through the file and parse each line */
+int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
+        unsigned line = 0;
+        char *section = NULL;
+        int r;
+        bool ours = false;
+
+        assert(filename);
+        assert(t);
+
+        if (!f) {
+                if (!(f = fopen(filename, "re"))) {
+                        r = -errno;
+                        log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
+                        goto finish;
+                }
+
+                ours = true;
+        }
+
+        while (!feof(f)) {
+                char l[LINE_MAX];
+
+                if (!fgets(l, sizeof(l), f)) {
+                        if (feof(f))
+                                break;
+
+                        r = -errno;
+                        log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
+                        goto finish;
+                }
+
+                if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        free(section);
+
+        if (f && ours)
+                fclose(f);
+
+        return r;
+}
+
+int config_parse_int(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *i = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atoi(rvalue, i)) < 0) {
+                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        return 0;
+}
+
+int config_parse_unsigned(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        unsigned *u = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atou(rvalue, u)) < 0) {
+                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        return 0;
+}
+
+int config_parse_size(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        size_t *sz = data;
+        unsigned u;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atou(rvalue, &u)) < 0) {
+                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        *sz = (size_t) u;
+        return 0;
+}
+
+int config_parse_bool(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int k;
+        bool *b = data;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((k = parse_boolean(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
+                return k;
+        }
+
+        *b = !!k;
+        return 0;
+}
+
+int config_parse_string(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char **s = data;
+        char *n;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (*rvalue) {
+                if (!(n = strdup(rvalue)))
+                        return -ENOMEM;
+        } else
+                n = NULL;
+
+        free(*s);
+        *s = n;
+
+        return 0;
+}
+
+int config_parse_path(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char **s = data;
+        char *n;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (!path_is_absolute(rvalue)) {
+                log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
+                return -EINVAL;
+        }
+
+        if (!(n = strdup(rvalue)))
+                return -ENOMEM;
+
+        free(*s);
+        *s = n;
+
+        return 0;
+}
+
+int config_parse_strv(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char*** sv = data;
+        char **n;
+        char *w;
+        unsigned k;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        k = strv_length(*sv);
+        FOREACH_WORD_QUOTED(w, l, rvalue, state)
+                k++;
+
+        if (!(n = new(char*, k+1)))
+                return -ENOMEM;
+
+        if (*sv)
+                for (k = 0; (*sv)[k]; k++)
+                        n[k] = (*sv)[k];
+        else
+                k = 0;
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state)
+                if (!(n[k++] = strndup(w, l)))
+                        goto fail;
+
+        n[k] = NULL;
+        free(*sv);
+        *sv = n;
+
+        return 0;
+
+fail:
+        for (; k > 0; k--)
+                free(n[k-1]);
+        free(n);
+
+        return -ENOMEM;
+}
+
+int config_parse_path_strv(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char*** sv = data;
+        char **n;
+        char *w;
+        unsigned k;
+        size_t l;
+        char *state;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        k = strv_length(*sv);
+        FOREACH_WORD_QUOTED(w, l, rvalue, state)
+                k++;
+
+        if (!(n = new(char*, k+1)))
+                return -ENOMEM;
+
+        k = 0;
+        if (*sv)
+                for (; (*sv)[k]; k++)
+                        n[k] = (*sv)[k];
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                if (!(n[k] = strndup(w, l))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                if (!path_is_absolute(n[k])) {
+                        log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
+                        r = -EINVAL;
+                        goto fail;
+                }
+
+                k++;
+        }
+
+        n[k] = NULL;
+        free(*sv);
+        *sv = n;
+
+        return 0;
+
+fail:
+        free(n[k]);
+        for (; k > 0; k--)
+                free(n[k-1]);
+        free(n);
+
+        return r;
+}
diff --git a/src/conf-parser.h b/src/conf-parser.h
new file mode 100644
index 0000000..bea2a8e
--- /dev/null
+++ b/src/conf-parser.h
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooconfparserhfoo
+#define fooconfparserhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+
+/* An abstract parser for simple, line based, shallow configuration
+ * files consisting of variable assignments only. */
+
+typedef int (*ConfigParserCallback)(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+
+/* Wraps info for parsing a specific configuration variable */
+typedef struct ConfigItem {
+        const char *lvalue; /* name of the variable */
+        ConfigParserCallback parse; /* Function that is called to parse the variable's value */
+        void *data; /* Where to store the variable's data */
+        const char *section;
+} ConfigItem;
+
+/* The configuration file parsing routine. Expects a table of
+ * config_items in *t that is terminated by an item where lvalue is
+ * NULL */
+int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata);
+
+/* Generic parsers */
+int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+
+#endif
diff --git a/src/dbus-automount.c b/src/dbus-automount.c
new file mode 100644
index 0000000..9003b74
--- /dev/null
+++ b/src/dbus-automount.c
@@ -0,0 +1,44 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dbus-unit.h"
+#include "dbus-automount.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Automount\">"
+        "  <property name=\"Where\" type=\"s\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+DBusHandlerResult bus_automount_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Automount", "Where", bus_property_append_string, "s", u->automount.where },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-automount.h b/src/dbus-automount.h
new file mode 100644
index 0000000..947bf0f
--- /dev/null
+++ b/src/dbus-automount.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusautomounthfoo
+#define foodbusautomounthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_automount_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-device.c b/src/dbus-device.c
new file mode 100644
index 0000000..8376478
--- /dev/null
+++ b/src/dbus-device.c
@@ -0,0 +1,44 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dbus-unit.h"
+#include "dbus-device.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Device\">"
+        "  <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+DBusHandlerResult bus_device_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Device", "SysFSPath", bus_property_append_string, "s", u->device.sysfs },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-device.h b/src/dbus-device.h
new file mode 100644
index 0000000..f2850a6
--- /dev/null
+++ b/src/dbus-device.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusdevicehfoo
+#define foodbusdevicehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_device_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-execute.c b/src/dbus-execute.c
new file mode 100644
index 0000000..8840396
--- /dev/null
+++ b/src/dbus-execute.c
@@ -0,0 +1,28 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <dbus/dbus.h>
+
+#include "dbus-execute.h"
+
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
new file mode 100644
index 0000000..25ecd98
--- /dev/null
+++ b/src/dbus-execute.h
@@ -0,0 +1,79 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusexecutehfoo
+#define foodbusexecutehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "manager.h"
+
+#define BUS_EXEC_CONTEXT_INTERFACE                                      \
+        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>" \
+        "  <property name=\"UMask\" type=\"u\" access=\"read\"/>"       \
+        "  <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>" \
+        "  <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>" \
+        "  <property name=\"StandardInput\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"StandardError\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>"     \
+        "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>" \
+        "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>"  \
+        "  <property name=\"CapabilityBoundingSetDrop\" type=\"t\" access=\"read\"/>" \
+        "  <property name=\"User\" type=\"s\" access=\"read\"/>"        \
+        "  <property name=\"Group\" type=\"s\" access=\"read\"/>"       \
+        "  <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>"
+
+#define BUS_EXEC_CONTEXT_PROPERTIES(interface, context)                 \
+        { interface, "Environment",                   bus_property_append_strv,   "as",    (context).environment                   }, \
+        { interface, "UMask",                         bus_property_append_mode,   "u",     &(context).umask                        }, \
+            /* RLimits */                                               \
+        { interface, "WorkingDirectory",              bus_property_append_string, "s",     (context).working_directory             }, \
+        { interface, "RootDirectory",                 bus_property_append_string, "s",     (context).root_directory                }, \
+            /* OOM Adjust */                                            \
+            /* Nice */                                                  \
+            /* IOPrio */                                                \
+            /* CPUSchedPolicy */                                        \
+            /* CPUSchedPriority */                                      \
+            /* CPUAffinity */                                           \
+            /* TimerSlackNS */                                          \
+        { interface, "CPUSchedulingResetOnFork",      bus_property_append_bool,   "b",     &(context).cpu_sched_reset_on_fork      }, \
+        { interface, "NonBlocking",                   bus_property_append_bool,   "b",     &(context).non_blocking                 }, \
+        { interface, "StandardInput",                 bus_execute_append_input,   "s",     &(context).std_input                    }, \
+        { interface, "StandardOutput",                bus_execute_append_output,  "s",     &(context).std_output                   }, \
+        { interface, "StandardError",                 bus_execute_append_output,  "s",     &(context).std_error                    }, \
+        { interface, "TTYPath",                       bus_property_append_string, "s",     (context).tty_path                      }, \
+        { interface, "SyslogPriority",                bus_property_append_int,    "i",     &(context).syslog_priority              }, \
+        { interface, "SyslogIdentifier",              bus_property_append_string, "s",     (context).syslog_identifier             }, \
+            /* CAPABILITIES */                                          \
+        { interface, "SecureBits",                    bus_property_append_int,    "i",     &(context).secure_bits                  }, \
+        { interface, "CapabilityBoundingSetDrop",     bus_property_append_uint64, "t",     &(context).capability_bounding_set_drop }, \
+        { interface, "User",                          bus_property_append_string, "s",     (context).user                          }, \
+        { interface, "Group",                         bus_property_append_string, "s",     (context).group                         }, \
+        { interface, "SupplementaryGroups",           bus_property_append_strv,   "as",    (context).supplementary_groups          }
+
+int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data);
+
+#endif
diff --git a/src/dbus-job.c b/src/dbus-job.c
new file mode 100644
index 0000000..3a6e715
--- /dev/null
+++ b/src/dbus-job.c
@@ -0,0 +1,236 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "dbus-job.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        " <interface name=\"org.freedesktop.systemd1.Job\">"
+        "  <method name=\"Cancel\"/>"
+        "  <signal name=\"Changed\"/>"
+        "  <property name=\"Id\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>"
+        "  <property name=\"JobType\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"State\" type=\"s\" access=\"read\"/>"
+        " </interface>"
+        BUS_PROPERTIES_INTERFACE
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType);
+
+static int bus_job_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Job *j = data;
+        DBusMessageIter sub;
+        char *p;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(j);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        if (!(p = unit_dbus_path(j->unit)))
+                return -ENOMEM;
+
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->meta.id) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
+                free(p);
+                return -ENOMEM;
+        }
+
+        free(p);
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusMessage *message) {
+        const BusProperty properties[] = {
+                { "org.freedesktop.systemd1.Job", "Id",      bus_property_append_uint32, "u",    &j->id    },
+                { "org.freedesktop.systemd1.Job", "State",   bus_job_append_state,       "s",    &j->state },
+                { "org.freedesktop.systemd1.Job", "JobType", bus_job_append_type,        "s",    &j->type  },
+                { "org.freedesktop.systemd1.Job", "Unit",    bus_job_append_unit,        "(so)", j         },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusMessage *reply = NULL;
+        Manager *m = j->manager;
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                job_free(j);
+
+        } else
+                return bus_default_message_handler(j->manager, message, introspection, properties);
+
+        if (reply) {
+                if (!dbus_connection_send(m->api_bus, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+static DBusHandlerResult bus_job_message_handler(DBusConnection  *connection, DBusMessage  *message, void *data) {
+        Manager *m = data;
+        Job *j;
+        int r;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        log_debug("Got D-Bus request: %s.%s() on %s",
+                  dbus_message_get_interface(message),
+                  dbus_message_get_member(message),
+                  dbus_message_get_path(message));
+
+        if ((r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j)) < 0) {
+
+                if (r == -ENOMEM)
+                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+                if (r == -ENOENT)
+                        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+                return bus_send_error_reply(m, message, NULL, r);
+        }
+
+        return bus_job_message_dispatch(j, message);
+}
+
+const DBusObjectPathVTable bus_job_vtable = {
+        .message_function = bus_job_message_handler
+};
+
+void bus_job_send_change_signal(Job *j) {
+        char *p = NULL;
+        DBusMessage *m = NULL;
+
+        assert(j);
+        assert(j->in_dbus_queue);
+
+        LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
+        j->in_dbus_queue = false;
+
+        if (set_isempty(j->manager->subscribed)) {
+                j->sent_dbus_new_signal = true;
+                return;
+        }
+
+        if (!(p = job_dbus_path(j)))
+                goto oom;
+
+        if (j->sent_dbus_new_signal) {
+                /* Send a change signal */
+
+                if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Job", "Changed")))
+                        goto oom;
+        } else {
+                /* Send a new signal */
+
+                if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew")))
+                        goto oom;
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_UINT32, &j->id,
+                                              DBUS_TYPE_OBJECT_PATH, &p,
+                                              DBUS_TYPE_INVALID))
+                        goto oom;
+        }
+
+        if (!dbus_connection_send(j->manager->api_bus, m, NULL))
+                goto oom;
+
+        free(p);
+        dbus_message_unref(m);
+
+        j->sent_dbus_new_signal = true;
+
+        return;
+
+oom:
+        free(p);
+
+        if (m)
+                dbus_message_unref(m);
+
+        log_error("Failed to allocate job change signal.");
+}
+
+void bus_job_send_removed_signal(Job *j) {
+        char *p = NULL;
+        DBusMessage *m = NULL;
+
+        assert(j);
+
+        if (set_isempty(j->manager->subscribed) || !j->sent_dbus_new_signal)
+                return;
+
+        if (!(p = job_dbus_path(j)))
+                goto oom;
+
+        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved")))
+                goto oom;
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_UINT32, &j->id,
+                                      DBUS_TYPE_OBJECT_PATH, &p,
+                                      DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (!dbus_connection_send(j->manager->api_bus, m, NULL))
+                goto oom;
+
+        free(p);
+        dbus_message_unref(m);
+
+        return;
+
+oom:
+        free(p);
+
+        if (m)
+                dbus_message_unref(m);
+
+        log_error("Failed to allocate job remove signal.");
+}
diff --git a/src/dbus-job.h b/src/dbus-job.h
new file mode 100644
index 0000000..cf91760
--- /dev/null
+++ b/src/dbus-job.h
@@ -0,0 +1,32 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusjobhfoo
+#define foodbusjobhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+void bus_job_send_change_signal(Job *j);
+void bus_job_send_removed_signal(Job *j);
+
+extern const DBusObjectPathVTable bus_job_vtable;
+
+#endif
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
new file mode 100644
index 0000000..90ab8d1
--- /dev/null
+++ b/src/dbus-manager.c
@@ -0,0 +1,657 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "dbus-manager.h"
+#include "strv.h"
+
+#define INTROSPECTION_BEGIN                                             \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>"                                                        \
+        " <interface name=\"org.freedesktop.systemd1.Manager\">"        \
+        "  <method name=\"GetUnit\">"                                   \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>"          \
+        "  </method>"                                                   \
+        "  <method name=\"LoadUnit\">"                                  \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>"          \
+        "  </method>"                                                   \
+        "  <method name=\"GetJob\">"                                    \
+        "   <arg name=\"id\" type=\"u\" direction=\"in\"/>"             \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
+        "  </method>"                                                   \
+        "  <method name=\"ClearJobs\"/>"                                \
+        "  <method name=\"ListUnits\">"                                 \
+        "   <arg name=\"units\" type=\"a(sssssouso)\" direction=\"out\"/>" \
+        "  </method>"                                                   \
+        "  <method name=\"ListJobs\">"                                  \
+        "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>"  \
+        "  </method>"                                                   \
+        "  <method name=\"Subscribe\"/>"                                \
+        "  <method name=\"Unsubscribe\"/>"                              \
+        "  <method name=\"Dump\"/>"                                     \
+        "  <method name=\"CreateSnapshot\">"                            \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg nane=\"cleanup\" type=\"b\" direction=\"in\"/>"        \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>"          \
+        "  </method>"                                                   \
+        "  <method name=\"Reload\"/>"                                   \
+        "  <method name=\"Reexecute\"/>"                                \
+        "  <method name=\"Exit\"/>"                                     \
+        "  <method name=\"SetEnvironment\">"                            \
+        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>"         \
+        "  </method>"                                                   \
+        "  <method name=\"UnsetEnvironment\">"                          \
+        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>"         \
+        "  </method>"                                                   \
+        "  <signal name=\"UnitNew\">"                                   \
+        "   <arg name=\"id\" type=\"s\"/>"                              \
+        "   <arg name=\"unit\" type=\"o\"/>"                            \
+        "  </signal>"                                                   \
+        "  <signal name=\"UnitRemoved\">"                               \
+        "   <arg name=\"id\" type=\"s\"/>"                              \
+        "   <arg name=\"unit\" type=\"o\"/>"                            \
+        "  </signal>"                                                   \
+        "  <signal name=\"JobNew\">"                                    \
+        "   <arg name=\"id\" type=\"u\"/>"                              \
+        "   <arg name=\"job\" type=\"o\"/>"                             \
+        "  </signal>"                                                   \
+        "  <signal name=\"JobRemoved\">"                                \
+        "   <arg name=\"id\" type=\"u\"/>"                              \
+        "   <arg name=\"job\" type=\"o\"/>"                             \
+        "  </signal>"                                                   \
+        "  <property name=\"Version\" type=\"s\" access=\"read\"/>"     \
+        "  <property name=\"RunningAs\" type=\"s\" access=\"read\"/>"   \
+        "  <property name=\"BootTimestamp\" type=\"t\" access=\"read\"/>" \
+        "  <property name=\"LogLevel\" type=\"s\" access=\"read\"/>"    \
+        "  <property name=\"LogTarget\" type=\"s\" access=\"read\"/>"   \
+        "  <property name=\"NNames\" type=\"u\" access=\"read\"/>"      \
+        "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>"       \
+        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>" \
+        " </interface>"                                                 \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_INTROSPECTABLE_INTERFACE
+
+#define INTROSPECTION_END                                               \
+        "</node>"
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
+
+static int bus_manager_append_log_target(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        t = log_target_to_string(log_get_target());
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_append_log_level(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        t = log_level_to_string(log_get_max_level());
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_append_n_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        uint32_t u;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        u = hashmap_size(m->units);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_append_n_jobs(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        uint32_t u;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        u = hashmap_size(m->jobs);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection, DBusMessage *message, void *data) {
+        Manager *m = data;
+
+        const BusProperty properties[] = {
+                { "org.freedesktop.systemd1.Manager", "Version",       bus_property_append_string,    "s", PACKAGE_STRING     },
+                { "org.freedesktop.systemd1.Manager", "RunningAs",     bus_manager_append_running_as, "s", &m->running_as     },
+                { "org.freedesktop.systemd1.Manager", "BootTimestamp", bus_property_append_uint64,    "t", &m->boot_timestamp },
+                { "org.freedesktop.systemd1.Manager", "LogLevel",      bus_manager_append_log_level,  "s", NULL               },
+                { "org.freedesktop.systemd1.Manager", "LogTarget",     bus_manager_append_log_target, "s", NULL               },
+                { "org.freedesktop.systemd1.Manager", "NNames",        bus_manager_append_n_names,    "u", NULL               },
+                { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u", NULL               },
+                { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment   },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        int r;
+        DBusError error;
+        DBusMessage *reply = NULL;
+        char * path = NULL;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        log_debug("Got D-Bus request: %s.%s() on %s",
+                  dbus_message_get_interface(message),
+                  dbus_message_get_member(message),
+                  dbus_message_get_path(message));
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
+                const char *name;
+                Unit *u;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                if (!(u = manager_get_unit(m, name)))
+                        return bus_send_error_reply(m, message, NULL, -ENOENT);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!(path = unit_dbus_path(u)))
+                        goto oom;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_OBJECT_PATH, &path,
+                                    DBUS_TYPE_INVALID))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
+                const char *name;
+                Unit *u;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                if ((r = manager_load_unit(m, name, NULL, &u)) < 0)
+                        return bus_send_error_reply(m, message, NULL, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!(path = unit_dbus_path(u)))
+                        goto oom;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_OBJECT_PATH, &path,
+                                    DBUS_TYPE_INVALID))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
+                uint32_t id;
+                Job *j;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_UINT32, &id,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                if (!(j = manager_get_job(m, id)))
+                        return bus_send_error_reply(m, message, NULL, -ENOENT);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!(path = job_dbus_path(j)))
+                        goto oom;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_OBJECT_PATH, &path,
+                                    DBUS_TYPE_INVALID))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
+
+                manager_clear_jobs(m);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
+                DBusMessageIter iter, sub;
+                Iterator i;
+                Unit *u;
+                const char *k;
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssssouso)", &sub))
+                        goto oom;
+
+                HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+                        char *u_path, *j_path;
+                        const char *description, *load_state, *active_state, *sub_state, *job_type;
+                        DBusMessageIter sub2;
+                        uint32_t job_id;
+
+                        if (k != u->meta.id)
+                                continue;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                                goto oom;
+
+                        description = unit_description(u);
+                        load_state = unit_load_state_to_string(u->meta.load_state);
+                        active_state = unit_active_state_to_string(unit_active_state(u));
+                        sub_state = unit_sub_state_to_string(u);
+
+                        if (!(u_path = unit_dbus_path(u)))
+                                goto oom;
+
+                        if (u->meta.job) {
+                                job_id = (uint32_t) u->meta.job->id;
+
+                                if (!(j_path = job_dbus_path(u->meta.job))) {
+                                        free(u_path);
+                                        goto oom;
+                                }
+
+                                job_type = job_type_to_string(u->meta.job->type);
+                        } else {
+                                job_id = 0;
+                                j_path = u_path;
+                                job_type = "";
+                        }
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &job_type) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
+                                free(u_path);
+                                if (u->meta.job)
+                                        free(j_path);
+                                goto oom;
+                        }
+
+                        free(u_path);
+                        if (u->meta.job)
+                                free(j_path);
+
+                        if (!dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
+                DBusMessageIter iter, sub;
+                Iterator i;
+                Job *j;
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
+                        goto oom;
+
+                HASHMAP_FOREACH(j, m->jobs, i) {
+                        char *u_path, *j_path;
+                        const char *state, *type;
+                        uint32_t id;
+                        DBusMessageIter sub2;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                                goto oom;
+
+                        id = (uint32_t) j->id;
+                        state = job_state_to_string(j->state);
+                        type = job_type_to_string(j->type);
+
+                        if (!(j_path = job_dbus_path(j)))
+                                goto oom;
+
+                        if (!(u_path = unit_dbus_path(j->unit))) {
+                                free(j_path);
+                                goto oom;
+                        }
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->meta.id) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
+                                free(j_path);
+                                free(u_path);
+                                goto oom;
+                        }
+
+                        free(j_path);
+                        free(u_path);
+
+                        if (!dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
+                char *client;
+
+                if (!(client = strdup(dbus_message_get_sender(message))))
+                        goto oom;
+
+                r = set_put(m->subscribed, client);
+
+                if (r < 0)
+                        return bus_send_error_reply(m, message, NULL, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
+                char *client;
+
+                if (!(client = set_remove(m->subscribed, (char*) dbus_message_get_sender(message))))
+                        return bus_send_error_reply(m, message, NULL, -ENOENT);
+
+                free(client);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
+                FILE *f;
+                char *dump = NULL;
+                size_t size;
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!(f = open_memstream(&dump, &size)))
+                        goto oom;
+
+                manager_dump_units(m, f, NULL);
+                manager_dump_jobs(m, f, NULL);
+
+                if (ferror(f)) {
+                        fclose(f);
+                        free(dump);
+                        goto oom;
+                }
+
+                fclose(f);
+
+                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
+                        free(dump);
+                        goto oom;
+                }
+
+                free(dump);
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
+                const char *name;
+                dbus_bool_t cleanup;
+                Snapshot *s;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_BOOLEAN, &cleanup,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                if (name && name[0] == 0)
+                        name = NULL;
+
+                if ((r = snapshot_create(m, name, cleanup, &s)) < 0)
+                        return bus_send_error_reply(m, message, NULL, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!(path = unit_dbus_path(UNIT(s))))
+                        goto oom;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_OBJECT_PATH, &path,
+                                    DBUS_TYPE_INVALID))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+                char *introspection = NULL;
+                FILE *f;
+                Iterator i;
+                Unit *u;
+                Job *j;
+                const char *k;
+                size_t size;
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                /* We roll our own introspection code here, instead of
+                 * relying on bus_default_message_handler() because we
+                 * need to generate our introspection string
+                 * dynamically. */
+
+                if (!(f = open_memstream(&introspection, &size)))
+                        goto oom;
+
+                fputs(INTROSPECTION_BEGIN, f);
+
+                HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+                        char *p;
+
+                        if (k != u->meta.id)
+                                continue;
+
+                        if (!(p = bus_path_escape(k))) {
+                                fclose(f);
+                                free(introspection);
+                                goto oom;
+                        }
+
+                        fprintf(f, "<node name=\"unit/%s\"/>", p);
+                        free(p);
+                }
+
+                HASHMAP_FOREACH(j, m->jobs, i)
+                        fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
+
+                fputs(INTROSPECTION_END, f);
+
+                if (ferror(f)) {
+                        fclose(f);
+                        free(introspection);
+                        goto oom;
+                }
+
+                fclose(f);
+
+                if (!introspection)
+                        goto oom;
+
+                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
+                        free(introspection);
+                        goto oom;
+                }
+
+                free(introspection);
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
+
+                assert(!m->queued_message);
+
+                /* Instead of sending the reply back right away, we
+                 * just remember that we need to and then send it
+                 * after the reload is finished. That way the caller
+                 * knows when the reload finished. */
+
+                if (!(m->queued_message = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_RELOAD;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_REEXECUTE;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
+
+                if (m->running_as == MANAGER_INIT)
+                        return bus_send_error_reply(m, message, NULL, -ENOTSUP);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_EXIT;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
+                char **l = NULL, **e = NULL;
+
+                if ((r = bus_parse_strv(message, &l)) < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        return bus_send_error_reply(m, message, NULL, r);
+                }
+
+                e = strv_env_merge(m->environment, l, NULL);
+                strv_free(l);
+
+                if (!e)
+                        goto oom;
+
+                if (!(reply = dbus_message_new_method_return(message))) {
+                        strv_free(e);
+                        goto oom;
+                }
+
+                strv_free(m->environment);
+                m->environment = e;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
+                char **l = NULL, **e = NULL;
+
+                if ((r = bus_parse_strv(message, &l)) < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        return bus_send_error_reply(m, message, NULL, r);
+                }
+
+                e = strv_env_delete(m->environment, l, NULL);
+                strv_free(l);
+
+                if (!e)
+                        goto oom;
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                strv_free(m->environment);
+                m->environment = e;
+
+        } else
+                return bus_default_message_handler(m, message, NULL, properties);
+
+        free(path);
+
+        if (reply) {
+                if (!dbus_connection_send(connection, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        free(path);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+const DBusObjectPathVTable bus_manager_vtable = {
+        .message_function = bus_manager_message_handler
+};
diff --git a/src/dbus-manager.h b/src/dbus-manager.h
new file mode 100644
index 0000000..0acd2d0
--- /dev/null
+++ b/src/dbus-manager.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusmanagerhfoo
+#define foodbusmanagerhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+extern const DBusObjectPathVTable bus_manager_vtable;
+
+#endif
diff --git a/src/dbus-mount.c b/src/dbus-mount.c
new file mode 100644
index 0000000..500b773
--- /dev/null
+++ b/src/dbus-mount.c
@@ -0,0 +1,134 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus-unit.h"
+#include "dbus-mount.h"
+#include "dbus-execute.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Mount\">"
+        "  <property name=\"Where\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"What\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"Options\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"Type\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>"
+        BUS_EXEC_CONTEXT_INTERFACE
+        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+static int bus_mount_append_what(Manager *n, DBusMessageIter *i, const char *property, void *data) {
+        Mount *m = data;
+        const char *d;
+
+        assert(n);
+        assert(i);
+        assert(property);
+        assert(m);
+
+        if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what)
+                d = m->parameters_proc_self_mountinfo.what;
+        else if (m->from_fragment && m->parameters_fragment.what)
+                d = m->parameters_fragment.what;
+        else if (m->from_etc_fstab && m->parameters_etc_fstab.what)
+                d = m->parameters_etc_fstab.what;
+        else
+                d = "";
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_mount_append_options(Manager *n, DBusMessageIter *i, const char *property, void *data) {
+        Mount *m = data;
+        const char *d;
+
+        assert(n);
+        assert(i);
+        assert(property);
+        assert(m);
+
+        if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options)
+                d = m->parameters_proc_self_mountinfo.options;
+        else if (m->from_fragment && m->parameters_fragment.options)
+                d = m->parameters_fragment.options;
+        else if (m->from_etc_fstab && m->parameters_etc_fstab.options)
+                d = m->parameters_etc_fstab.options;
+        else
+                d = "";
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_mount_append_type(Manager *n, DBusMessageIter *i, const char *property, void *data) {
+        Mount *m = data;
+        const char *d;
+
+        assert(n);
+        assert(i);
+        assert(property);
+        assert(m);
+
+        if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype)
+                d = m->parameters_proc_self_mountinfo.fstype;
+        else if (m->from_fragment && m->parameters_fragment.fstype)
+                d = m->parameters_fragment.fstype;
+        else if (m->from_etc_fstab && m->parameters_etc_fstab.fstype)
+                d = m->parameters_etc_fstab.fstype;
+        else
+                d = "";
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
+DBusHandlerResult bus_mount_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Mount", "Where",       bus_property_append_string, "s", u->mount.where         },
+                { "org.freedesktop.systemd1.Mount", "What",        bus_mount_append_what,      "s", u                      },
+                { "org.freedesktop.systemd1.Mount", "Options",     bus_mount_append_options,   "s", u                      },
+                { "org.freedesktop.systemd1.Mount", "Type",        bus_mount_append_type,      "s", u                      },
+                { "org.freedesktop.systemd1.Mount", "TimeoutUSec", bus_property_append_usec,   "t", &u->mount.timeout_usec },
+                /* ExecCommand */
+                BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Mount", u->mount.exec_context),
+                { "org.freedesktop.systemd1.Mount", "KillMode",    bus_unit_append_kill_mode,  "s", &u->mount.kill_mode    },
+                { "org.freedesktop.systemd1.Mount", "ControlPID",  bus_property_append_pid,    "u", &u->mount.control_pid  },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-mount.h b/src/dbus-mount.h
new file mode 100644
index 0000000..b92867d
--- /dev/null
+++ b/src/dbus-mount.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusmounthfoo
+#define foodbusmounthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_mount_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-service.c b/src/dbus-service.c
new file mode 100644
index 0000000..24dd6c1
--- /dev/null
+++ b/src/dbus-service.c
@@ -0,0 +1,78 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus-unit.h"
+#include "dbus-execute.h"
+#include "dbus-service.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Service\">"
+        "  <property name=\"Type\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"Restart\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"PIDFile\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>"
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>"
+        BUS_EXEC_CONTEXT_INTERFACE
+        "  <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>"
+        "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>"
+        "  <property name=\"ValidNoProcess\" type=\"b\" access=\"read\"/>"
+        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"MainPID\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"SysVPath\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"BusName\" type=\"s\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
+
+DBusHandlerResult bus_service_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Service", "Type",                   bus_service_append_type,    "s", &u->service.type },
+                { "org.freedesktop.systemd1.Service", "Restart",                bus_service_append_restart, "s", &u->service.restart },
+                { "org.freedesktop.systemd1.Service", "PIDFile",                bus_property_append_string, "s", u->service.pid_file },
+                { "org.freedesktop.systemd1.Service", "RestartUSec",            bus_property_append_usec,   "t", &u->service.restart_usec },
+                { "org.freedesktop.systemd1.Service", "TimeoutUSec",            bus_property_append_usec,   "t", &u->service.timeout_usec },
+                /* ExecCommand */
+                BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Service", u->service.exec_context),
+                { "org.freedesktop.systemd1.Service", "PermissionsStartOnly",   bus_property_append_bool,   "b", &u->service.permissions_start_only },
+                { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool,   "b", &u->service.root_directory_start_only },
+                { "org.freedesktop.systemd1.Service", "ValidNoProcess",         bus_property_append_bool,   "b", &u->service.valid_no_process },
+                { "org.freedesktop.systemd1.Service", "KillMode",               bus_unit_append_kill_mode,  "s", &u->service.kill_mode },
+                /* MainExecStatus */
+                { "org.freedesktop.systemd1.Service", "MainPID",                bus_property_append_pid,    "u", &u->service.main_pid },
+                { "org.freedesktop.systemd1.Service", "ControlPID",             bus_property_append_pid,    "u", &u->service.control_pid },
+                { "org.freedesktop.systemd1.Service", "SysVPath",               bus_property_append_string, "s", u->service.sysv_path },
+                { "org.freedesktop.systemd1.Service", "BusName",                bus_property_append_string, "s", u->service.bus_name },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-service.h b/src/dbus-service.h
new file mode 100644
index 0000000..f0a468e
--- /dev/null
+++ b/src/dbus-service.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusservicehfoo
+#define foodbusservicehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_service_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-snapshot.c b/src/dbus-snapshot.c
new file mode 100644
index 0000000..8aeca15
--- /dev/null
+++ b/src/dbus-snapshot.c
@@ -0,0 +1,75 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dbus-unit.h"
+#include "dbus-snapshot.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Snapshot\">"
+        "  <method name=\"Remove\"/>"
+        "  <property name=\"Cleanup\" type=\"b\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Snapshot", "Cleanup", bus_property_append_bool, "b", &u->snapshot.cleanup },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusMessage *reply = NULL;
+        DBusError error;
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Snapshot", "Remove")) {
+
+                snapshot_remove(SNAPSHOT(u));
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else
+                return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+
+        if (reply) {
+                if (!dbus_connection_send(u->meta.manager->api_bus, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
diff --git a/src/dbus-snapshot.h b/src/dbus-snapshot.h
new file mode 100644
index 0000000..5f28550
--- /dev/null
+++ b/src/dbus-snapshot.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbussnapshothfoo
+#define foodbussnapshothfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-socket.c b/src/dbus-socket.c
new file mode 100644
index 0000000..2a2349c
--- /dev/null
+++ b/src/dbus-socket.c
@@ -0,0 +1,64 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dbus-unit.h"
+#include "dbus-socket.h"
+#include "dbus-execute.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Socket\">"
+        "  <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>"
+        "  <property name=\"Backlog\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>"
+        BUS_EXEC_CONTEXT_INTERFACE
+        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"SocketMode\" type=\"u\" access=\"read\"/>"
+        "  <property name=\"Accept\" type=\"b\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+DBusHandlerResult bus_socket_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Socket", "BindIPv6Only",  bus_property_append_bool,     "b", &u->socket.bind_ipv6_only },
+                { "org.freedesktop.systemd1.Socket", "Backlog",       bus_property_append_unsigned, "u", &u->socket.backlog },
+                { "org.freedesktop.systemd1.Socket", "TimeoutUSec",   bus_property_append_usec,     "t", &u->socket.timeout_usec },
+                /* ExecCommand */
+                BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Socket", u->socket.exec_context),
+                { "org.freedesktop.systemd1.Socket", "KillMode",      bus_unit_append_kill_mode,    "s", &u->socket.kill_mode },
+                { "org.freedesktop.systemd1.Socket", "ControlPID",    bus_property_append_pid,      "u", &u->socket.control_pid },
+                { "org.freedesktop.systemd1.Socket", "BindToDevice",  bus_property_append_string,   "s", u->socket.bind_to_device },
+                { "org.freedesktop.systemd1.Socket", "DirectoryMode", bus_property_append_mode,     "u", &u->socket.directory_mode },
+                { "org.freedesktop.systemd1.Socket", "SocketMode",    bus_property_append_mode,     "u", &u->socket.socket_mode },
+                { "org.freedesktop.systemd1.Socket", "Accept",        bus_property_append_bool,     "b", &u->socket.accept },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-socket.h b/src/dbus-socket.h
new file mode 100644
index 0000000..6a8f534
--- /dev/null
+++ b/src/dbus-socket.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbussockethfoo
+#define foodbussockethfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_socket_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-swap.c b/src/dbus-swap.c
new file mode 100644
index 0000000..e935e09
--- /dev/null
+++ b/src/dbus-swap.c
@@ -0,0 +1,73 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2010 Maarten Lankhorst
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus-unit.h"
+#include "dbus-swap.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Swap\">"
+        "  <property name=\"What\" type=\"s\" access=\"read\"/>"
+        "  <property name=\"Priority\" type=\"i\" access=\"read\"/>"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+static int bus_swap_append_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Swap *s = data;
+        dbus_int32_t j;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(s);
+
+        if (s->from_proc_swaps)
+                j = s->parameters_proc_swaps.priority;
+        else if (s->from_fragment)
+                j = s->parameters_fragment.priority;
+        else if (s->from_etc_fstab)
+                j = s->parameters_etc_fstab.priority;
+        else
+                j = -1;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &j))
+                return -ENOMEM;
+
+        return 0;
+}
+
+DBusHandlerResult bus_swap_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Swap", "What",     bus_property_append_string, "s", u->swap.what },
+                { "org.freedesktop.systemd1.Swap", "Priority", bus_swap_append_priority,   "i", u            },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-swap.h b/src/dbus-swap.h
new file mode 100644
index 0000000..3bef6ad
--- /dev/null
+++ b/src/dbus-swap.h
@@ -0,0 +1,32 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusswaphfoo
+#define foodbusswaphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2010 Maarten Lankhorst
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_swap_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-target.c b/src/dbus-target.c
new file mode 100644
index 0000000..be984b9
--- /dev/null
+++ b/src/dbus-target.c
@@ -0,0 +1,42 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dbus-unit.h"
+#include "dbus-target.h"
+
+static const char introspection[] =
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+        "<node>"
+        BUS_UNIT_INTERFACE
+        BUS_PROPERTIES_INTERFACE
+        " <interface name=\"org.freedesktop.systemd1.Target\">"
+        " </interface>"
+        BUS_INTROSPECTABLE_INTERFACE
+        "</node>";
+
+DBusHandlerResult bus_target_message_handler(Unit *u, DBusMessage *message) {
+        const BusProperty properties[] = {
+                BUS_UNIT_PROPERTIES,
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        return bus_default_message_handler(u->meta.manager, message, introspection, properties);
+}
diff --git a/src/dbus-target.h b/src/dbus-target.h
new file mode 100644
index 0000000..f6a1ac5
--- /dev/null
+++ b/src/dbus-target.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbustargethfoo
+#define foodbustargethfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_target_message_handler(Unit *u, DBusMessage *message);
+
+#endif
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
new file mode 100644
index 0000000..e3e1be1
--- /dev/null
+++ b/src/dbus-unit.c
@@ -0,0 +1,451 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "dbus-unit.h"
+
+int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        char *t;
+        Iterator j;
+        DBusMessageIter sub;
+        Unit *u = data;
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
+                return -ENOMEM;
+
+        SET_FOREACH(t, u->meta.names, j)
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t))
+                        return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u;
+        Iterator j;
+        DBusMessageIter sub;
+        Set *s = data;
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
+                return -ENOMEM;
+
+        SET_FOREACH(u, s, j)
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->meta.id))
+                        return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *d;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        d = unit_description(u);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState);
+
+int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *state;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        state = unit_active_state_to_string(unit_active_state(u));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *state;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        state = unit_sub_state_to_string(u);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = unit_can_start(u);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = unit_can_reload(u);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        DBusMessageIter sub;
+        char *p;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        if (u->meta.job) {
+
+                if (!(p = job_dbus_path(u->meta.job)))
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->meta.job->id) ||
+                    !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
+                        free(p);
+                        return -ENOMEM;
+                }
+        } else {
+                uint32_t id = 0;
+
+                /* No job, so let's fill in some placeholder
+                 * data. Since we need to fill in a valid path we
+                 * simple point to ourselves. */
+
+                if (!(p = unit_dbus_path(u)))
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
+                    !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
+                        free(p);
+                        return -ENOMEM;
+                }
+        }
+
+        free(p);
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        char *t;
+        CGroupBonding *cgb;
+        bool success;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        if ((cgb = unit_get_default_cgroup(u))) {
+                if (!(t = cgroup_bonding_to_string(cgb)))
+                        return -ENOMEM;
+        } else
+                t = (char*) "";
+
+        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
+
+        if (cgb)
+                free(t);
+
+        return success ? 0 : -ENOMEM;
+}
+
+int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        CGroupBonding *cgb;
+        DBusMessageIter sub;
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(by_unit, cgb, u->meta.cgroup_bondings) {
+                char *t;
+                bool success;
+
+                if (!(t = cgroup_bonding_to_string(cgb)))
+                        return -ENOMEM;
+
+                success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t);
+                free(t);
+
+                if (!success)
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_kill_mode, kill_mode, KillMode);
+
+static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message) {
+        DBusMessage *reply = NULL;
+        Manager *m = u->meta.manager;
+        DBusError error;
+        JobType job_type = _JOB_TYPE_INVALID;
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start"))
+                job_type = JOB_START;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop"))
+                job_type = JOB_STOP;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload"))
+                job_type = JOB_RELOAD;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart"))
+                job_type = JOB_RESTART;
+        else if (UNIT_VTABLE(u)->bus_message_handler)
+                return UNIT_VTABLE(u)->bus_message_handler(u, message);
+        else
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+        if (job_type != _JOB_TYPE_INVALID) {
+                const char *smode;
+                JobMode mode;
+                Job *j;
+                int r;
+                char *path;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &smode,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID)
+                        return bus_send_error_reply(m, message, NULL, -EINVAL);
+
+                if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0)
+                        return bus_send_error_reply(m, message, NULL, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!(path = job_dbus_path(j)))
+                        goto oom;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_OBJECT_PATH, &path,
+                                    DBUS_TYPE_INVALID))
+                        goto oom;
+        }
+
+        if (reply) {
+                if (!dbus_connection_send(m->api_bus, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+static DBusHandlerResult bus_unit_message_handler(DBusConnection  *connection, DBusMessage  *message, void *data) {
+        Manager *m = data;
+        Unit *u;
+        int r;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        log_debug("Got D-Bus request: %s.%s() on %s",
+                  dbus_message_get_interface(message),
+                  dbus_message_get_member(message),
+                  dbus_message_get_path(message));
+
+        if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) {
+
+                if (r == -ENOMEM)
+                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+                if (r == -ENOENT)
+                        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+                return bus_send_error_reply(m, message, NULL, r);
+        }
+
+        return bus_unit_message_dispatch(u, message);
+}
+
+const DBusObjectPathVTable bus_unit_vtable = {
+        .message_function = bus_unit_message_handler
+};
+
+void bus_unit_send_change_signal(Unit *u) {
+        char *p = NULL;
+        DBusMessage *m = NULL;
+
+        assert(u);
+        assert(u->meta.in_dbus_queue);
+
+        LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
+        u->meta.in_dbus_queue = false;
+
+        if (set_isempty(u->meta.manager->subscribed)) {
+                u->meta.sent_dbus_new_signal = true;
+                return;
+        }
+
+        if (!(p = unit_dbus_path(u)))
+                goto oom;
+
+        if (u->meta.sent_dbus_new_signal) {
+                /* Send a change signal */
+
+                if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Unit", "Changed")))
+                        goto oom;
+        } else {
+                /* Send a new signal */
+
+                if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew")))
+                        goto oom;
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &u->meta.id,
+                                              DBUS_TYPE_OBJECT_PATH, &p,
+                                              DBUS_TYPE_INVALID))
+                        goto oom;
+        }
+
+        if (!dbus_connection_send(u->meta.manager->api_bus, m, NULL))
+                goto oom;
+
+        free(p);
+        dbus_message_unref(m);
+
+        u->meta.sent_dbus_new_signal = true;
+
+        return;
+
+oom:
+        free(p);
+
+        if (m)
+                dbus_message_unref(m);
+
+        log_error("Failed to allocate unit change/new signal.");
+}
+
+void bus_unit_send_removed_signal(Unit *u) {
+        char *p = NULL;
+        DBusMessage *m = NULL;
+
+        assert(u);
+
+        if (set_isempty(u->meta.manager->subscribed) || !u->meta.sent_dbus_new_signal)
+                return;
+
+        if (!(p = unit_dbus_path(u)))
+                goto oom;
+
+        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved")))
+                goto oom;
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &u->meta.id,
+                                      DBUS_TYPE_OBJECT_PATH, &p,
+                                      DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (!dbus_connection_send(u->meta.manager->api_bus, m, NULL))
+                goto oom;
+
+        free(p);
+        dbus_message_unref(m);
+
+        return;
+
+oom:
+        free(p);
+
+        if (m)
+                dbus_message_unref(m);
+
+        log_error("Failed to allocate unit remove signal.");
+}
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
new file mode 100644
index 0000000..c5840d5
--- /dev/null
+++ b/src/dbus-unit.h
@@ -0,0 +1,128 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbusunithfoo
+#define foodbusunithfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "manager.h"
+
+#define BUS_UNIT_INTERFACE \
+        " <interface name=\"org.freedesktop.systemd1.Unit\">"           \
+        "  <method name=\"Start\">"                                     \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
+        "  </method>"                                                   \
+        "  <method name=\"Stop\">"                                      \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
+        "  </method>"                                                   \
+        "  <method name=\"Restart\">"                                   \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
+        "  </method>"                                                   \
+        "  <method name=\"Reload\">"                                    \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>"           \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>"           \
+        "  </method>"                                                   \
+        "  <signal name=\"Changed\"/>"                                  \
+        "  <property name=\"Id\" type=\"s\" access=\"read\"/>"          \
+        "  <property name=\"Names\" type=\"as\" access=\"read\"/>"      \
+        "  <property name=\"Requires\" type=\"as\" access=\"read\"/>"   \
+        "  <property name=\"RequiresOverridable\" type=\"as\" access=\"read\"/>" \
+        "  <property name=\"Requisite\" type=\"as\" access=\"read\"/>"  \
+        "  <property name=\"RequisiteOverridable\" type=\"as\" access=\"read\"/>" \
+        "  <property name=\"Wants\" type=\"as\" access=\"read\"/>"      \
+        "  <property name=\"RequiredBy\" type=\"as\" access=\"read\"/>" \
+        "  <property name=\"RequiredByOverridable\" type=\"as\" access=\"read\"/>" \
+        "  <property name=\"WantedBy\" type=\"as\" access=\"read\"/>"   \
+        "  <property name=\"Conflicts\" type=\"as\" access=\"read\"/>"  \
+        "  <property name=\"Before\" type=\"as\" access=\"read\"/>"     \
+        "  <property name=\"After\" type=\"as\" access=\"read\"/>"      \
+        "  <property name=\"Description\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"LoadState\" type=\"s\" access=\"read\"/>"   \
+        "  <property name=\"ActiveState\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"SubState\" type=\"s\" access=\"read\"/>"    \
+        "  <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>" \
+        "  <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>" \
+        "  <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>" \
+        "  <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>" \
+        "  <property name=\"CanReload\" type=\"b\" access=\"read\"/>"   \
+        "  <property name=\"CanStart\" type=\"b\" access=\"read\"/>"    \
+        "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>"      \
+        "  <property name=\"RecursiveStop\" type=\"b\" access=\"read\"/>" \
+        "  <property name=\"StopWhenUneeded\" type=\"b\" access=\"read\"/>" \
+        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>" \
+        "  <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>" \
+        " </interface>"
+
+#define BUS_UNIT_PROPERTIES \
+        { "org.freedesktop.systemd1.Unit", "Id",                   bus_property_append_string,     "s",    u->meta.id                        }, \
+        { "org.freedesktop.systemd1.Unit", "Names",                bus_unit_append_names,          "as",   u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "Requires",             bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRES] }, \
+        { "org.freedesktop.systemd1.Unit", "RequiresOverridable",  bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE] }, \
+        { "org.freedesktop.systemd1.Unit", "Requisite",            bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUISITE] }, \
+        { "org.freedesktop.systemd1.Unit", "RequisiteOverridable", bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE] }, \
+        { "org.freedesktop.systemd1.Unit", "Wants",                bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_WANTS]  }, \
+        { "org.freedesktop.systemd1.Unit", "RequiredBy",           bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRED_BY] }, \
+        { "org.freedesktop.systemd1.Unit", "RequiredByOverridable",bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE] }, \
+        { "org.freedesktop.systemd1.Unit", "WantedBy",             bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_WANTED_BY] }, \
+        { "org.freedesktop.systemd1.Unit", "Conflicts",            bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_CONFLICTS] }, \
+        { "org.freedesktop.systemd1.Unit", "Before",               bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_BEFORE] }, \
+        { "org.freedesktop.systemd1.Unit", "After",                bus_unit_append_dependencies,   "as",   u->meta.dependencies[UNIT_AFTER]  }, \
+        { "org.freedesktop.systemd1.Unit", "Description",          bus_unit_append_description,    "s",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "LoadState",            bus_unit_append_load_state,     "s",    &u->meta.load_state               }, \
+        { "org.freedesktop.systemd1.Unit", "ActiveState",          bus_unit_append_active_state,   "s",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "SubState",             bus_unit_append_sub_state,      "s",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "FragmentPath",         bus_property_append_string,     "s",    u->meta.fragment_path             }, \
+        { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_uint64,     "t",    &u->meta.inactive_exit_timestamp  }, \
+        { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_uint64,     "t",    &u->meta.active_enter_timestamp   }, \
+        { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp",  bus_property_append_uint64,     "t",    &u->meta.active_exit_timestamp    }, \
+        { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_uint64,    "t",    &u->meta.inactive_enter_timestamp }, \
+        { "org.freedesktop.systemd1.Unit", "CanStart",             bus_unit_append_can_start,      "b",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "CanReload",            bus_unit_append_can_reload,     "b",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "Job",                  bus_unit_append_job,            "(uo)", u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "RecursiveStop",        bus_property_append_bool,       "b",    &u->meta.recursive_stop           }, \
+        { "org.freedesktop.systemd1.Unit", "StopWhenUneeded",      bus_property_append_bool,       "b",    &u->meta.stop_when_unneeded       }, \
+        { "org.freedesktop.systemd1.Unit", "DefaultControlGroup",  bus_unit_append_default_cgroup, "s",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "ControlGroups",        bus_unit_append_cgroups,        "as",   u                                 }
+
+int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_kill_mode(Manager *m, DBusMessageIter *i, const char *property, void *data);
+
+void bus_unit_send_change_signal(Unit *u);
+void bus_unit_send_removed_signal(Unit *u);
+
+extern const DBusObjectPathVTable bus_unit_vtable;
+
+#endif
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100644
index 0000000..6ed659a
--- /dev/null
+++ b/src/dbus.c
@@ -0,0 +1,1136 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dbus/dbus.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "strv.h"
+#include "cgroup.h"
+#include "dbus-unit.h"
+#include "dbus-job.h"
+#include "dbus-manager.h"
+
+static void api_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
+        Manager *m = data;
+
+        assert(bus);
+        assert(m);
+
+        if (!m->api_bus)
+                return;
+
+        assert(m->api_bus == bus);
+
+        m->request_api_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
+}
+
+static void system_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
+        Manager *m = data;
+
+        assert(bus);
+        assert(m);
+
+        if (!m->system_bus)
+                return;
+
+        assert(m->system_bus == bus);
+
+        m->request_system_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
+}
+
+static uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
+        unsigned flags;
+        uint32_t events = 0;
+
+        assert(bus_watch);
+
+        /* no watch flags for disabled watches */
+        if (!dbus_watch_get_enabled(bus_watch))
+                return 0;
+
+        flags = dbus_watch_get_flags(bus_watch);
+
+        if (flags & DBUS_WATCH_READABLE)
+                events |= EPOLLIN;
+        if (flags & DBUS_WATCH_WRITABLE)
+                events |= EPOLLOUT;
+
+        return events | EPOLLHUP | EPOLLERR;
+}
+
+static unsigned events_to_bus_flags(uint32_t events) {
+        unsigned flags = 0;
+
+        if (events & EPOLLIN)
+                flags |= DBUS_WATCH_READABLE;
+        if (events & EPOLLOUT)
+                flags |= DBUS_WATCH_WRITABLE;
+        if (events & EPOLLHUP)
+                flags |= DBUS_WATCH_HANGUP;
+        if (events & EPOLLERR)
+                flags |= DBUS_WATCH_ERROR;
+
+        return flags;
+}
+
+void bus_watch_event(Manager *m, Watch *w, int events) {
+        assert(m);
+        assert(w);
+
+        /* This is called by the event loop whenever there is
+         * something happening on D-Bus' file handles. */
+
+        if (!dbus_watch_get_enabled(w->data.bus_watch))
+                return;
+
+        dbus_watch_handle(w->data.bus_watch, events_to_bus_flags(events));
+}
+
+static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
+        Manager *m = data;
+        Watch *w;
+        struct epoll_event ev;
+
+        assert(bus_watch);
+        assert(m);
+
+        if (!(w = new0(Watch, 1)))
+                return FALSE;
+
+        w->fd = dbus_watch_get_unix_fd(bus_watch);
+        w->type = WATCH_DBUS_WATCH;
+        w->data.bus_watch = bus_watch;
+
+        zero(ev);
+        ev.events = bus_flags_to_events(bus_watch);
+        ev.data.ptr = w;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
+
+                if (errno != EEXIST) {
+                        free(w);
+                        return FALSE;
+                }
+
+                /* Hmm, bloody D-Bus creates multiple watches on the
+                 * same fd. epoll() does not like that. As a dirty
+                 * hack we simply dup() the fd and hence get a second
+                 * one we can safely add to the epoll(). */
+
+                if ((w->fd = dup(w->fd)) < 0) {
+                        free(w);
+                        return FALSE;
+                }
+
+                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
+                        free(w);
+                        close_nointr_nofail(w->fd);
+                        return FALSE;
+                }
+
+                w->fd_is_dupped = true;
+        }
+
+        dbus_watch_set_data(bus_watch, w, NULL);
+
+        return TRUE;
+}
+
+static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
+        Manager *m = data;
+        Watch *w;
+
+        assert(bus_watch);
+        assert(m);
+
+        if (!(w = dbus_watch_get_data(bus_watch)))
+                return;
+
+        assert(w->type == WATCH_DBUS_WATCH);
+        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
+
+        if (w->fd_is_dupped)
+                close_nointr_nofail(w->fd);
+
+        free(w);
+}
+
+static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
+        Manager *m = data;
+        Watch *w;
+        struct epoll_event ev;
+
+        assert(bus_watch);
+        assert(m);
+
+        assert_se(w = dbus_watch_get_data(bus_watch));
+        assert(w->type == WATCH_DBUS_WATCH);
+
+        zero(ev);
+        ev.events = bus_flags_to_events(bus_watch);
+        ev.data.ptr = w;
+
+        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
+}
+
+static int bus_timeout_arm(Manager *m, Watch *w) {
+        struct itimerspec its;
+
+        assert(m);
+        assert(w);
+
+        zero(its);
+
+        if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
+                timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
+                its.it_interval = its.it_interval;
+        }
+
+        if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
+                return -errno;
+
+        return 0;
+}
+
+void bus_timeout_event(Manager *m, Watch *w, int events) {
+        assert(m);
+        assert(w);
+
+        /* This is called by the event loop whenever there is
+         * something happening on D-Bus' file handles. */
+
+        if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
+                return;
+
+        dbus_timeout_handle(w->data.bus_timeout);
+}
+
+static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
+        Manager *m = data;
+        Watch *w;
+        struct epoll_event ev;
+
+        assert(timeout);
+        assert(m);
+
+        if (!(w = new0(Watch, 1)))
+                return FALSE;
+
+        if (!(w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
+                goto fail;
+
+        w->type = WATCH_DBUS_TIMEOUT;
+        w->data.bus_timeout = timeout;
+
+        if (bus_timeout_arm(m, w) < 0)
+                goto fail;
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.ptr = w;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
+                goto fail;
+
+        dbus_timeout_set_data(timeout, w, NULL);
+
+        return TRUE;
+
+fail:
+        if (w->fd >= 0)
+                close_nointr_nofail(w->fd);
+
+        free(w);
+        return FALSE;
+}
+
+static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
+        Manager *m = data;
+        Watch *w;
+
+        assert(timeout);
+        assert(m);
+
+        if (!(w = dbus_timeout_get_data(timeout)))
+                return;
+
+        assert(w->type == WATCH_DBUS_TIMEOUT);
+        assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
+        close_nointr_nofail(w->fd);
+        free(w);
+}
+
+static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
+        Manager *m = data;
+        Watch *w;
+        int r;
+
+        assert(timeout);
+        assert(m);
+
+        assert_se(w = dbus_timeout_get_data(timeout));
+        assert(w->type == WATCH_DBUS_TIMEOUT);
+
+        if ((r = bus_timeout_arm(m, w)) < 0)
+                log_error("Failed to rearm timer: %s", strerror(-r));
+}
+
+static DBusHandlerResult api_bus_message_filter(DBusConnection  *connection, DBusMessage  *message, void *data) {
+        Manager *m = data;
+        DBusError error;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        /* log_debug("Got D-Bus request: %s.%s() on %s", */
+        /*           dbus_message_get_interface(message), */
+        /*           dbus_message_get_member(message), */
+        /*           dbus_message_get_path(message)); */
+
+        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
+                log_error("Warning! API D-Bus connection terminated.");
+                bus_done_api(m);
+
+        } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
+                const char *name, *old_owner, *new_owner;
+
+                if (!dbus_message_get_args(message, &error,
+                                           DBUS_TYPE_STRING, &name,
+                                           DBUS_TYPE_STRING, &old_owner,
+                                           DBUS_TYPE_STRING, &new_owner,
+                                           DBUS_TYPE_INVALID))
+                        log_error("Failed to parse NameOwnerChanged message: %s", error.message);
+                else  {
+                        if (set_remove(m->subscribed, (char*) name))
+                                log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
+
+                        if (old_owner[0] == 0)
+                                old_owner = NULL;
+
+                        if (new_owner[0] == 0)
+                                new_owner = NULL;
+
+                        manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
+                }
+        }
+
+        dbus_error_free(&error);
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult system_bus_message_filter(DBusConnection  *connection, DBusMessage  *message, void *data) {
+        Manager *m = data;
+        DBusError error;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        /* log_debug("Got D-Bus request: %s.%s() on %s", */
+        /*           dbus_message_get_interface(message), */
+        /*           dbus_message_get_member(message), */
+        /*           dbus_message_get_path(message)); */
+
+        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
+                log_error("Warning! System D-Bus connection terminated.");
+                bus_done_system(m);
+
+        } if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
+                const char *cgroup;
+
+                if (!dbus_message_get_args(message, &error,
+                                           DBUS_TYPE_STRING, &cgroup,
+                                           DBUS_TYPE_INVALID))
+                        log_error("Failed to parse Released message: %s", error.message);
+                else
+                        cgroup_notify_empty(m, cgroup);
+        }
+
+        dbus_error_free(&error);
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+unsigned bus_dispatch(Manager *m) {
+        assert(m);
+
+        if (m->queued_message) {
+                /* If we cannot get rid of this message we won't
+                 * dispatch any D-Bus messages, so that we won't end
+                 * up wanting to queue another message. */
+
+                if (!dbus_connection_send(m->api_bus, m->queued_message, NULL))
+                        return 0;
+
+                dbus_message_unref(m->queued_message);
+                m->queued_message = NULL;
+        }
+
+        if (m->request_api_bus_dispatch) {
+                if (dbus_connection_dispatch(m->api_bus) == DBUS_DISPATCH_COMPLETE)
+                        m->request_api_bus_dispatch = false;
+
+                return 1;
+        }
+
+        if (m->request_system_bus_dispatch) {
+                if (dbus_connection_dispatch(m->system_bus) == DBUS_DISPATCH_COMPLETE)
+                        m->request_system_bus_dispatch = false;
+
+                return 1;
+        }
+
+        return 0;
+}
+
+static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
+        DBusMessage *reply;
+        DBusError error;
+
+        dbus_error_init(&error);
+
+        assert_se(reply = dbus_pending_call_steal_reply(pending));
+
+        switch (dbus_message_get_type(reply)) {
+
+        case DBUS_MESSAGE_TYPE_ERROR:
+
+                assert_se(dbus_set_error_from_message(&error, reply));
+                log_warning("RequestName() failed: %s", error.message);
+                break;
+
+        case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
+                uint32_t r;
+
+                if (!dbus_message_get_args(reply,
+                                           &error,
+                                           DBUS_TYPE_UINT32, &r,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse RequestName() reply: %s", error.message);
+                        break;
+                }
+
+                if (r == 1)
+                        log_debug("Successfully acquired name.");
+                else
+                        log_error("Name already owned.");
+
+                break;
+        }
+
+        default:
+                assert_not_reached("Invalid reply message");
+        }
+
+        dbus_message_unref(reply);
+        dbus_error_free(&error);
+}
+
+static int request_name(Manager *m) {
+        const char *name = "org.freedesktop.systemd1";
+        uint32_t flags = 0;
+        DBusMessage *message = NULL;
+        DBusPendingCall *pending = NULL;
+
+        if (!(message = dbus_message_new_method_call(
+                              DBUS_SERVICE_DBUS,
+                              DBUS_PATH_DBUS,
+                              DBUS_INTERFACE_DBUS,
+                              "RequestName")))
+                goto oom;
+
+        if (!dbus_message_append_args(
+                            message,
+                            DBUS_TYPE_STRING, &name,
+                            DBUS_TYPE_UINT32, &flags,
+                            DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
+                goto oom;
+
+        if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
+                goto oom;
+
+        dbus_message_unref(message);
+        dbus_pending_call_unref(pending);
+
+        /* We simple ask for the name and don't wait for it. Sooner or
+         * later we'll have it. */
+
+        return 0;
+
+oom:
+        if (pending) {
+                dbus_pending_call_cancel(pending);
+                dbus_pending_call_unref(pending);
+        }
+
+        if (message)
+                dbus_message_unref(message);
+
+        return -ENOMEM;
+}
+
+static int bus_setup_loop(Manager *m, DBusConnection *bus) {
+        assert(m);
+        assert(bus);
+
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
+            !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_init_system(Manager *m) {
+        DBusError error;
+        char *id;
+        int r;
+
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (m->system_bus)
+                return 0;
+
+        if (m->running_as != MANAGER_SESSION && m->api_bus)
+                m->system_bus = m->api_bus;
+        else {
+                if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
+                        log_debug("Failed to get system D-Bus connection, retrying later: %s", error.message);
+                        dbus_error_free(&error);
+                        return 0;
+                }
+
+                dbus_connection_set_dispatch_status_function(m->system_bus, system_bus_dispatch_status, m, NULL);
+                m->request_system_bus_dispatch = true;
+
+                if ((r = bus_setup_loop(m, m->system_bus)) < 0) {
+                        bus_done_system(m);
+                        return r;
+                }
+        }
+
+        if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
+                bus_done_system(m);
+                return -ENOMEM;
+        }
+
+        dbus_bus_add_match(m->system_bus,
+                           "type='signal',"
+                           "interface='org.freedesktop.systemd1.Agent',"
+                           "path='/org/freedesktop/systemd1/agent'",
+                           &error);
+
+        if (dbus_error_is_set(&error)) {
+                log_error("Failed to register match: %s", error.message);
+                dbus_error_free(&error);
+                bus_done_system(m);
+                return -ENOMEM;
+        }
+
+        log_debug("Successfully connected to system D-Bus bus %s as %s",
+                  strnull((id = dbus_connection_get_server_id(m->system_bus))),
+                  strnull(dbus_bus_get_unique_name(m->system_bus)));
+        dbus_free(id);
+
+        return 0;
+}
+
+int bus_init_api(Manager *m) {
+        DBusError error;
+        char *id;
+        int r;
+
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (m->api_bus)
+                return 0;
+
+        if (m->name_data_slot < 0)
+                if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
+                        return -ENOMEM;
+
+        if (m->running_as != MANAGER_SESSION && m->system_bus)
+                m->api_bus = m->system_bus;
+        else {
+                if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_SESSION ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
+                        log_debug("Failed to get API D-Bus connection, retrying later: %s", error.message);
+                        dbus_error_free(&error);
+                        return 0;
+                }
+
+                dbus_connection_set_dispatch_status_function(m->api_bus, api_bus_dispatch_status, m, NULL);
+                m->request_api_bus_dispatch = true;
+
+                if ((r = bus_setup_loop(m, m->api_bus)) < 0) {
+                        bus_done_api(m);
+                        return r;
+                }
+        }
+
+        if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
+            !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
+            !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
+            !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) {
+                bus_done_api(m);
+                return -ENOMEM;
+        }
+
+        dbus_bus_add_match(m->api_bus,
+                           "type='signal',"
+                           "sender='"DBUS_SERVICE_DBUS"',"
+                           "interface='"DBUS_INTERFACE_DBUS"',"
+                           "path='"DBUS_PATH_DBUS"'",
+                           &error);
+
+        if (dbus_error_is_set(&error)) {
+                log_error("Failed to register match: %s", error.message);
+                dbus_error_free(&error);
+                bus_done_api(m);
+                return -ENOMEM;
+        }
+
+        if ((r = request_name(m)) < 0) {
+                bus_done_api(m);
+                return r;
+        }
+
+        log_debug("Successfully connected to API D-Bus bus %s as %s",
+                  strnull((id = dbus_connection_get_server_id(m->api_bus))),
+                  strnull(dbus_bus_get_unique_name(m->api_bus)));
+        dbus_free(id);
+
+        if (!m->subscribed)
+                if (!(m->subscribed = set_new(string_hash_func, string_compare_func)))
+                        return -ENOMEM;
+
+        return 0;
+}
+
+void bus_done_api(Manager *m) {
+        assert(m);
+
+        if (m->api_bus) {
+                if (m->system_bus == m->api_bus)
+                        m->system_bus = NULL;
+
+                dbus_connection_set_dispatch_status_function(m->api_bus, NULL, NULL, NULL);
+                dbus_connection_flush(m->api_bus);
+                dbus_connection_close(m->api_bus);
+                dbus_connection_unref(m->api_bus);
+                m->api_bus = NULL;
+        }
+
+        if (m->subscribed) {
+                char *c;
+
+                while ((c = set_steal_first(m->subscribed)))
+                        free(c);
+
+                set_free(m->subscribed);
+                m->subscribed = NULL;
+        }
+
+       if (m->name_data_slot >= 0)
+               dbus_pending_call_free_data_slot(&m->name_data_slot);
+
+       if (m->queued_message) {
+               dbus_message_unref(m->queued_message);
+               m->queued_message = NULL;
+       }
+}
+
+void bus_done_system(Manager *m) {
+        assert(m);
+
+        if (m->system_bus == m->api_bus)
+                bus_done_api(m);
+
+        if (m->system_bus) {
+                dbus_connection_set_dispatch_status_function(m->system_bus, NULL, NULL, NULL);
+                dbus_connection_flush(m->system_bus);
+                dbus_connection_close(m->system_bus);
+                dbus_connection_unref(m->system_bus);
+                m->system_bus = NULL;
+        }
+}
+
+static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
+        Manager *m = userdata;
+        DBusMessage *reply;
+        DBusError error;
+        const char *name;
+
+        dbus_error_init(&error);
+
+        assert_se(name = dbus_pending_call_get_data(pending, m->name_data_slot));
+        assert_se(reply = dbus_pending_call_steal_reply(pending));
+
+        switch (dbus_message_get_type(reply)) {
+
+        case DBUS_MESSAGE_TYPE_ERROR:
+
+                assert_se(dbus_set_error_from_message(&error, reply));
+                log_warning("GetConnectionUnixProcessID() failed: %s", error.message);
+                break;
+
+        case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
+                uint32_t r;
+
+                if (!dbus_message_get_args(reply,
+                                           &error,
+                                           DBUS_TYPE_UINT32, &r,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", error.message);
+                        break;
+                }
+
+                manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
+                break;
+        }
+
+        default:
+                assert_not_reached("Invalid reply message");
+        }
+
+        dbus_message_unref(reply);
+        dbus_error_free(&error);
+}
+
+int bus_query_pid(Manager *m, const char *name) {
+        DBusMessage *message = NULL;
+        DBusPendingCall *pending = NULL;
+        char *n = NULL;
+
+        assert(m);
+        assert(name);
+
+        if (!(message = dbus_message_new_method_call(
+                              DBUS_SERVICE_DBUS,
+                              DBUS_PATH_DBUS,
+                              DBUS_INTERFACE_DBUS,
+                              "GetConnectionUnixProcessID")))
+                goto oom;
+
+        if (!(dbus_message_append_args(
+                              message,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_INVALID)))
+                goto oom;
+
+        if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
+                goto oom;
+
+        if (!(n = strdup(name)))
+                goto oom;
+
+        if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
+                goto oom;
+
+        n = NULL;
+
+        if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
+                goto oom;
+
+        dbus_message_unref(message);
+        dbus_pending_call_unref(pending);
+
+        return 0;
+
+oom:
+        free(n);
+
+        if (pending) {
+                dbus_pending_call_cancel(pending);
+                dbus_pending_call_unref(pending);
+        }
+
+        if (message)
+                dbus_message_unref(message);
+
+        return -ENOMEM;
+}
+
+DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char*introspection, const BusProperty *properties) {
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
+        assert(m);
+        assert(message);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) {
+                const char *interface, *property;
+                const BusProperty *p;
+
+                if (!dbus_message_get_args(
+                            message,
+                            &error,
+                            DBUS_TYPE_STRING, &interface,
+                            DBUS_TYPE_STRING, &property,
+                            DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                for (p = properties; p->property; p++)
+                        if (streq(p->interface, interface) && streq(p->property, property))
+                                break;
+
+                if (p->property) {
+                        DBusMessageIter iter, sub;
+
+                        if (!(reply = dbus_message_new_method_return(message)))
+                                goto oom;
+
+                        dbus_message_iter_init_append(reply, &iter);
+
+                        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
+                                goto oom;
+
+                        if ((r = p->append(m, &sub, property, (void*) p->data)) < 0) {
+
+                                if (r == -ENOMEM)
+                                        goto oom;
+
+                                dbus_message_unref(reply);
+                                return bus_send_error_reply(m, message, NULL, r);
+                        }
+
+                        if (!dbus_message_iter_close_container(&iter, &sub))
+                                goto oom;
+                }
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
+                const char *interface;
+                const BusProperty *p;
+                DBusMessageIter iter, sub, sub2, sub3;
+                bool any = false;
+
+                if (!dbus_message_get_args(
+                            message,
+                            &error,
+                            DBUS_TYPE_STRING, &interface,
+                            DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, message, &error, -EINVAL);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
+                        goto oom;
+
+                for (p = properties; p->property; p++) {
+                        if (!streq(p->interface, interface))
+                                continue;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
+                            !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
+                                goto oom;
+
+                        if ((r = p->append(m, &sub3, p->property, (void*) p->data)) < 0) {
+
+                                if (r == -ENOMEM)
+                                        goto oom;
+
+                                dbus_message_unref(reply);
+                                return bus_send_error_reply(m, message, NULL, r);
+                        }
+
+                        if (!dbus_message_iter_close_container(&sub2, &sub3) ||
+                            !dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+
+                        any = true;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+        }
+
+        if (reply) {
+                if (!dbus_connection_send(m->api_bus, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+                return DBUS_HANDLER_RESULT_HANDLED;
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+static const char *error_to_dbus(int error) {
+
+        switch(error) {
+
+        case -EINVAL:
+                return DBUS_ERROR_INVALID_ARGS;
+
+        case -ENOMEM:
+                return DBUS_ERROR_NO_MEMORY;
+
+        case -EPERM:
+        case -EACCES:
+                return DBUS_ERROR_ACCESS_DENIED;
+
+        case -ESRCH:
+                return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
+
+        case -ENOENT:
+                return DBUS_ERROR_FILE_NOT_FOUND;
+
+        case -EEXIST:
+                return DBUS_ERROR_FILE_EXISTS;
+
+        case -ETIMEDOUT:
+                return DBUS_ERROR_TIMEOUT;
+
+        case -EIO:
+                return DBUS_ERROR_IO_ERROR;
+
+        case -ENETRESET:
+        case -ECONNABORTED:
+        case -ECONNRESET:
+                return DBUS_ERROR_DISCONNECTED;
+        }
+
+        return DBUS_ERROR_FAILED;
+}
+
+DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error) {
+        DBusMessage *reply = NULL;
+        const char *name, *text;
+
+        if (bus_error && dbus_error_is_set(bus_error)) {
+                name = bus_error->name;
+                text = bus_error->message;
+        } else {
+                name = error_to_dbus(error);
+                text = strerror(-error);
+        }
+
+        if (!(reply = dbus_message_new_error(message, name, text)))
+                goto oom;
+
+        if (!dbus_connection_send(m->api_bus, reply, NULL))
+                goto oom;
+
+        dbus_message_unref(reply);
+
+        if (bus_error)
+                dbus_error_free(bus_error);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        if (bus_error)
+                dbus_error_free(bus_error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        const char *t = data;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        if (!t)
+                t = "";
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub;
+        char **t = data;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
+                return -ENOMEM;
+
+        STRV_FOREACH(t, t)
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t))
+                        return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        bool *b = data;
+        dbus_bool_t db;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(b);
+
+        db = *b;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(data);
+
+        /* Let's ensure that pid_t is actually 64bit, and hence this
+         * function can be used for usec_t */
+        assert_cc(sizeof(uint64_t) == sizeof(usec_t));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(data);
+
+        /* Let's ensure that pid_t and mode_t is actually 32bit, and
+         * hence this function can be used for pid_t/mode_t */
+        assert_cc(sizeof(uint32_t) == sizeof(pid_t));
+        assert_cc(sizeof(uint32_t) == sizeof(mode_t));
+        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(data);
+
+        assert_cc(sizeof(int32_t) == sizeof(int));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_parse_strv(DBusMessage *m, char ***_l) {
+        DBusMessageIter iter, sub;
+        unsigned n = 0, i = 0;
+        char **l;
+
+        assert(m);
+        assert(_l);
+
+        if (!dbus_message_iter_init(m, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
+            return -EINVAL;
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                n++;
+                dbus_message_iter_next(&sub);
+        }
+
+        if (!(l = new(char*, n+1)))
+                return -ENOMEM;
+
+        assert_se(dbus_message_iter_init(m, &iter));
+        dbus_message_iter_recurse(&iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *s;
+
+                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+                dbus_message_iter_get_basic(&sub, &s);
+
+                if (!(l[i++] = strdup(s))) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+                dbus_message_iter_next(&sub);
+        }
+
+        assert(i == n);
+        l[i] = NULL;
+
+        if (_l)
+                *_l = l;
+
+        return 0;
+}
diff --git a/src/dbus.h b/src/dbus.h
new file mode 100644
index 0000000..51b71ea
--- /dev/null
+++ b/src/dbus.h
@@ -0,0 +1,107 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodbushfoo
+#define foodbushfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "manager.h"
+
+typedef int (*BusPropertyCallback)(Manager *m, DBusMessageIter *iter, const char *property, void *data);
+
+typedef struct BusProperty {
+        const char *interface;           /* interface of the property */
+        const char *property;            /* name of the property */
+        BusPropertyCallback append;      /* Function that is called to serialize this property */
+        const char *signature;
+        const void *data;                /* The data of this property */
+} BusProperty;
+
+#define BUS_PROPERTIES_INTERFACE                                        \
+        " <interface name=\"org.freedesktop.DBus.Properties\">"         \
+        "  <method name=\"Get\">"                                       \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>"      \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>"       \
+        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>"         \
+        "  </method>"                                                   \
+        "  <method name=\"GetAll\">"                                    \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>"      \
+        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>" \
+        "  </method>"                                                   \
+        " </interface>"
+
+#define BUS_INTROSPECTABLE_INTERFACE                                    \
+        " <interface name=\"org.freedesktop.DBus.Introspectable\">"     \
+        "  <method name=\"Introspect\">"                                \
+        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"          \
+        "  </method>"                                                   \
+        " </interface>"
+
+int bus_init_system(Manager *m);
+int bus_init_api(Manager *m);
+void bus_done_system(Manager *m);
+void bus_done_api(Manager *m);
+
+unsigned bus_dispatch(Manager *m);
+
+void bus_watch_event(Manager *m, Watch *w, int events);
+void bus_timeout_event(Manager *m, Watch *w, int events);
+
+int bus_query_pid(Manager *m, const char *name);
+
+DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char* introspection, const BusProperty *properties);
+
+DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error);
+
+int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data);
+
+#define bus_property_append_int bus_property_append_int32
+#define bus_property_append_pid bus_property_append_uint32
+#define bus_property_append_mode bus_property_append_uint32
+#define bus_property_append_unsigned bus_property_append_uint32
+#define bus_property_append_usec bus_property_append_uint64
+
+#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type)             \
+        int function(Manager *m, DBusMessageIter *i, const char *property, void *data) { \
+                const char *value;                                      \
+                type *field = data;                                     \
+                                                                        \
+                assert(m);                                              \
+                assert(i);                                              \
+                assert(property);                                       \
+                                                                        \
+                value = name##_to_string(*field);                       \
+                                                                        \
+                if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \
+                        return -ENOMEM;                                 \
+                                                                        \
+                return 0;                                               \
+        }
+
+int bus_parse_strv(DBusMessage *m, char ***_l);
+
+#endif
diff --git a/src/device.c b/src/device.c
new file mode 100644
index 0000000..e67d0a6
--- /dev/null
+++ b/src/device.c
@@ -0,0 +1,471 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <sys/epoll.h>
+#include <libudev.h>
+
+#include "unit.h"
+#include "device.h"
+#include "strv.h"
+#include "log.h"
+#include "unit-name.h"
+#include "dbus-device.h"
+
+static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
+        [DEVICE_DEAD] = UNIT_INACTIVE,
+        [DEVICE_AVAILABLE] = UNIT_ACTIVE
+};
+
+static void device_done(Unit *u) {
+        Device *d = DEVICE(u);
+
+        assert(d);
+
+        free(d->sysfs);
+        d->sysfs = NULL;
+}
+
+static void device_set_state(Device *d, DeviceState state) {
+        DeviceState old_state;
+        assert(d);
+
+        old_state = d->state;
+        d->state = state;
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(d)->meta.id,
+                          device_state_to_string(old_state),
+                          device_state_to_string(state));
+
+        unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int device_coldplug(Unit *u) {
+        Device *d = DEVICE(u);
+
+        assert(d);
+        assert(d->state == DEVICE_DEAD);
+
+        if (d->sysfs)
+                device_set_state(d, DEVICE_AVAILABLE);
+
+        return 0;
+}
+
+static void device_dump(Unit *u, FILE *f, const char *prefix) {
+        Device *d = DEVICE(u);
+
+        assert(d);
+
+        fprintf(f,
+                "%sDevice State: %s\n"
+                "%sSysfs Path: %s\n",
+                prefix, device_state_to_string(d->state),
+                prefix, strna(d->sysfs));
+}
+
+static UnitActiveState device_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[DEVICE(u)->state];
+}
+
+static const char *device_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return device_state_to_string(DEVICE(u)->state);
+}
+
+static int device_add_escaped_name(Unit *u, const char *dn, bool make_id) {
+        char *e;
+        int r;
+
+        assert(u);
+        assert(dn);
+        assert(dn[0] == '/');
+
+        if (!(e = unit_name_from_path(dn, ".device")))
+                return -ENOMEM;
+
+        r = unit_add_name(u, e);
+
+        if (r >= 0 && make_id)
+                unit_choose_id(u, e);
+
+        free(e);
+
+        if (r < 0 && r != -EEXIST)
+                return r;
+
+        return 0;
+}
+
+static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
+        char *e;
+        Unit *u;
+
+        assert(m);
+        assert(dn);
+        assert(dn[0] == '/');
+        assert(_u);
+
+        if (!(e = unit_name_from_path(dn, ".device")))
+                return -ENOMEM;
+
+        u = manager_get_unit(m, e);
+        free(e);
+
+        if (u) {
+                *_u = u;
+                return 1;
+        }
+
+        return 0;
+}
+
+static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
+        const char *dn, *wants, *sysfs, *expose, *model, *alias;
+        Unit *u = NULL;
+        int r;
+        char *w, *state;
+        size_t l;
+        bool delete;
+        struct udev_list_entry *item = NULL, *first = NULL;
+        int b;
+
+        assert(m);
+
+        if (!(sysfs = udev_device_get_syspath(dev)))
+                return -ENOMEM;
+
+        if (!(expose = udev_device_get_property_value(dev, "SYSTEMD_EXPOSE")))
+                return 0;
+
+        if ((b = parse_boolean(expose)) < 0) {
+                log_error("Failed to parse SYSTEMD_EXPOSE udev property for device %s: %s", sysfs, expose);
+                return 0;
+        }
+
+        if (!b)
+                return 0;
+
+        /* Check whether this entry is even relevant for us. */
+        dn = udev_device_get_devnode(dev);
+        wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
+        alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
+
+        /* We allow exactly one alias to be configured a this time and
+         * it must be a path */
+
+        if (alias && !is_path(alias)) {
+                log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, alias);
+                alias = NULL;
+        }
+
+        if ((r = device_find_escape_name(m, sysfs, &u)) < 0)
+                return r;
+
+        if (r == 0 && dn)
+                if ((r = device_find_escape_name(m, dn, &u)) < 0)
+                        return r;
+
+        if (r == 0) {
+                first = udev_device_get_devlinks_list_entry(dev);
+                udev_list_entry_foreach(item, first) {
+                        if ((r = device_find_escape_name(m, udev_list_entry_get_name(item), &u)) < 0)
+                                return r;
+
+                        if (r > 0)
+                                break;
+                }
+        }
+
+        if (r == 0 && alias)
+                if ((r = device_find_escape_name(m, alias, &u)) < 0)
+                        return r;
+
+        /* FIXME: this needs proper merging */
+
+        assert((r > 0) == !!u);
+
+        /* If this is a different unit, then let's not merge things */
+        if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
+                u = NULL;
+
+        if (!u) {
+                delete = true;
+
+                if (!(u = unit_new(m)))
+                        return -ENOMEM;
+
+                if ((r = device_add_escaped_name(u, sysfs, true)) < 0)
+                        goto fail;
+
+                unit_add_to_load_queue(u);
+        } else
+                delete = false;
+
+        if (!(DEVICE(u)->sysfs))
+                if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+        if (alias)
+                if ((r = device_add_escaped_name(u, alias, true)) < 0)
+                        goto fail;
+
+        if (dn)
+                if ((r = device_add_escaped_name(u, dn, true)) < 0)
+                        goto fail;
+
+        first = udev_device_get_devlinks_list_entry(dev);
+        udev_list_entry_foreach(item, first)
+                if ((r = device_add_escaped_name(u, udev_list_entry_get_name(item), false)) < 0)
+                        goto fail;
+
+        if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
+            (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
+                if ((r = unit_set_description(u, model)) < 0)
+                        goto fail;
+        } else if (dn) {
+                if ((r = unit_set_description(u, dn)) < 0)
+                        goto fail;
+        } else
+                if ((r = unit_set_description(u, sysfs)) < 0)
+                        goto fail;
+
+        if (wants) {
+                FOREACH_WORD(w, l, wants, state) {
+                        char *e;
+
+                        if (!(e = strndup(w, l))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        r = unit_add_dependency_by_name(u, UNIT_WANTS, NULL, e, true);
+                        free(e);
+
+                        if (r < 0)
+                                goto fail;
+                }
+        }
+
+        if (update_state) {
+                manager_dispatch_load_queue(u->meta.manager);
+                device_set_state(DEVICE(u), DEVICE_AVAILABLE);
+        }
+
+        unit_add_to_dbus_queue(u);
+
+        return 0;
+
+fail:
+        if (delete && u)
+                unit_free(u);
+        return r;
+}
+
+static int device_process_path(Manager *m, const char *path, bool update_state) {
+        int r;
+        struct udev_device *dev;
+
+        assert(m);
+        assert(path);
+
+        if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
+                log_warning("Failed to get udev device object from udev for path %s.", path);
+                return -ENOMEM;
+        }
+
+        r = device_process_new_device(m, dev, update_state);
+        udev_device_unref(dev);
+        return r;
+}
+
+static int device_process_removed_device(Manager *m, struct udev_device *dev) {
+        const char *sysfs;
+        char *e;
+        Unit *u;
+        Device *d;
+
+        assert(m);
+        assert(dev);
+
+        if (!(sysfs = udev_device_get_syspath(dev)))
+                return -ENOMEM;
+
+        assert(sysfs[0] == '/');
+        if (!(e = unit_name_from_path(sysfs, ".device")))
+                return -ENOMEM;
+
+        u = manager_get_unit(m, e);
+        free(e);
+
+        if (!u)
+                return 0;
+
+        d = DEVICE(u);
+        free(d->sysfs);
+        d->sysfs = NULL;
+
+        device_set_state(d, DEVICE_DEAD);
+        return 0;
+}
+
+static void device_shutdown(Manager *m) {
+        assert(m);
+
+        if (m->udev_monitor) {
+                udev_monitor_unref(m->udev_monitor);
+                m->udev_monitor = NULL;
+        }
+
+        if (m->udev) {
+                udev_unref(m->udev);
+                m->udev = NULL;
+        }
+}
+
+static int device_enumerate(Manager *m) {
+        struct epoll_event ev;
+        int r;
+        struct udev_enumerate *e = NULL;
+        struct udev_list_entry *item = NULL, *first = NULL;
+
+        assert(m);
+
+        if (!m->udev) {
+                if (!(m->udev = udev_new()))
+                        return -ENOMEM;
+
+                if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
+                        r = -EIO;
+                        goto fail;
+                }
+
+                m->udev_watch.type = WATCH_UDEV;
+                m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
+
+                zero(ev);
+                ev.events = EPOLLIN;
+                ev.data.ptr = &m->udev_watch;
+
+                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
+                        return -errno;
+        }
+
+        if (!(e = udev_enumerate_new(m->udev))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (udev_enumerate_scan_devices(e) < 0) {
+                r = -EIO;
+                goto fail;
+        }
+
+        first = udev_enumerate_get_list_entry(e);
+        udev_list_entry_foreach(item, first)
+                device_process_path(m, udev_list_entry_get_name(item), false);
+
+        udev_enumerate_unref(e);
+        return 0;
+
+fail:
+        if (e)
+                udev_enumerate_unref(e);
+
+        device_shutdown(m);
+        return r;
+}
+
+void device_fd_event(Manager *m, int events) {
+        struct udev_device *dev;
+        int r;
+        const char *action;
+
+        assert(m);
+        assert(events == EPOLLIN);
+
+        if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
+                log_error("Failed to receive device.");
+                return;
+        }
+
+        if (!(action = udev_device_get_action(dev))) {
+                log_error("Failed to get udev action string.");
+                goto fail;
+        }
+
+        if (streq(action, "remove")) {
+                if ((r = device_process_removed_device(m, dev)) < 0) {
+                        log_error("Failed to process udev device event: %s", strerror(-r));
+                        goto fail;
+                }
+        } else {
+                if ((r = device_process_new_device(m, dev, true)) < 0) {
+                        log_error("Failed to process udev device event: %s", strerror(-r));
+                        goto fail;
+                }
+        }
+
+fail:
+        udev_device_unref(dev);
+}
+
+static const char* const device_state_table[_DEVICE_STATE_MAX] = {
+        [DEVICE_DEAD] = "dead",
+        [DEVICE_AVAILABLE] = "available"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
+
+const UnitVTable device_vtable = {
+        .suffix = ".device",
+
+        .no_requires = true,
+        .no_instances = true,
+        .no_snapshots = true,
+        .no_isolate = true,
+
+        .load = unit_load_fragment_and_dropin_optional,
+        .done = device_done,
+        .coldplug = device_coldplug,
+
+        .dump = device_dump,
+
+        .active_state = device_active_state,
+        .sub_state_to_string = device_sub_state_to_string,
+
+        .bus_message_handler = bus_device_message_handler,
+
+        .enumerate = device_enumerate,
+        .shutdown = device_shutdown
+};
diff --git a/src/device.h b/src/device.h
new file mode 100644
index 0000000..a5c5f74
--- /dev/null
+++ b/src/device.h
@@ -0,0 +1,53 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foodevicehfoo
+#define foodevicehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Device Device;
+
+#include "unit.h"
+
+/* We simply watch devices, we cannot plug/unplug them. That
+ * simplifies the state engine greatly */
+typedef enum DeviceState {
+        DEVICE_DEAD,
+        DEVICE_AVAILABLE,
+        _DEVICE_STATE_MAX,
+        _DEVICE_STATE_INVALID = -1
+} DeviceState;
+
+struct Device {
+        Meta meta;
+
+        DeviceState state;
+
+        char *sysfs;
+};
+
+extern const UnitVTable device_vtable;
+
+void device_fd_event(Manager *m, int events);
+
+const char* device_state_to_string(DeviceState i);
+DeviceState device_state_from_string(const char *s);
+
+#endif
diff --git a/src/execute.c b/src/execute.c
new file mode 100644
index 0000000..12f5145
--- /dev/null
+++ b/src/execute.c
@@ -0,0 +1,1619 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/prctl.h>
+#include <linux/sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include "execute.h"
+#include "strv.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+#include "ioprio.h"
+#include "securebits.h"
+#include "cgroup.h"
+#include "namespace.h"
+
+/* This assumes there is a 'tty' group */
+#define TTY_MODE 0620
+
+static int shift_fds(int fds[], unsigned n_fds) {
+        int start, restart_from;
+
+        if (n_fds <= 0)
+                return 0;
+
+        /* Modifies the fds array! (sorts it) */
+
+        assert(fds);
+
+        start = 0;
+        for (;;) {
+                int i;
+
+                restart_from = -1;
+
+                for (i = start; i < (int) n_fds; i++) {
+                        int nfd;
+
+                        /* Already at right index? */
+                        if (fds[i] == i+3)
+                                continue;
+
+                        if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
+                                return -errno;
+
+                        close_nointr_nofail(fds[i]);
+                        fds[i] = nfd;
+
+                        /* Hmm, the fd we wanted isn't free? Then
+                         * let's remember that and try again from here*/
+                        if (nfd != i+3 && restart_from < 0)
+                                restart_from = i;
+                }
+
+                if (restart_from < 0)
+                        break;
+
+                start = restart_from;
+        }
+
+        return 0;
+}
+
+static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
+        unsigned i;
+        int r;
+
+        if (n_fds <= 0)
+                return 0;
+
+        assert(fds);
+
+        /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
+
+        for (i = 0; i < n_fds; i++) {
+
+                if ((r = fd_nonblock(fds[i], nonblock)) < 0)
+                        return r;
+
+                /* We unconditionally drop FD_CLOEXEC from the fds,
+                 * since after all we want to pass these fds to our
+                 * children */
+
+                if ((r = fd_cloexec(fds[i], false)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static const char *tty_path(const ExecContext *context) {
+        assert(context);
+
+        if (context->tty_path)
+                return context->tty_path;
+
+        return "/dev/console";
+}
+
+static int open_null_as(int flags, int nfd) {
+        int fd, r;
+
+        assert(nfd >= 0);
+
+        if ((fd = open("/dev/null", flags|O_NOCTTY)) < 0)
+                return -errno;
+
+        if (fd != nfd) {
+                r = dup2(fd, nfd) < 0 ? -errno : nfd;
+                close_nointr_nofail(fd);
+        } else
+                r = nfd;
+
+        return r;
+}
+
+static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, int nfd) {
+        int fd, r;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_un un;
+        } sa;
+
+        assert(context);
+        assert(output < _EXEC_OUTPUT_MAX);
+        assert(ident);
+        assert(nfd >= 0);
+
+        if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+                return -errno;
+
+        zero(sa);
+        sa.sa.sa_family = AF_UNIX;
+        strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
+
+        if (connect(fd, &sa.sa, sizeof(sa)) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        if (shutdown(fd, SHUT_RD) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        /* We speak a very simple protocol between log server
+         * and client: one line for the log destination (kmsg
+         * or syslog), followed by the priority field,
+         * followed by the process name. Since we replaced
+         * stdin/stderr we simple use stdio to write to
+         * it. Note that we use stderr, to minimize buffer
+         * flushing issues. */
+
+        dprintf(fd,
+                "%s\n"
+                "%i\n"
+                "%s\n"
+                "%i\n",
+                output == EXEC_OUTPUT_KERNEL ? "kmsg" : "syslog",
+                context->syslog_priority,
+                context->syslog_identifier ? context->syslog_identifier : ident,
+                !context->syslog_no_prefix);
+
+        if (fd != nfd) {
+                r = dup2(fd, nfd) < 0 ? -errno : nfd;
+                close_nointr_nofail(fd);
+        } else
+                r = nfd;
+
+        return r;
+}
+static int open_terminal_as(const char *path, mode_t mode, int nfd) {
+        int fd, r;
+
+        assert(path);
+        assert(nfd >= 0);
+
+        if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
+                return fd;
+
+        if (fd != nfd) {
+                r = dup2(fd, nfd) < 0 ? -errno : nfd;
+                close_nointr_nofail(fd);
+        } else
+                r = nfd;
+
+        return r;
+}
+
+static bool is_terminal_input(ExecInput i) {
+        return
+                i == EXEC_INPUT_TTY ||
+                i == EXEC_INPUT_TTY_FORCE ||
+                i == EXEC_INPUT_TTY_FAIL;
+}
+
+static int fixup_input(const ExecContext *context, int socket_fd) {
+        assert(context);
+
+        if (socket_fd < 0 && context->std_input == EXEC_INPUT_SOCKET)
+                return EXEC_INPUT_NULL;
+
+        return context->std_input;
+}
+
+static int fixup_output(const ExecContext *context, int socket_fd) {
+        assert(context);
+
+        if (socket_fd < 0 && context->std_output == EXEC_OUTPUT_SOCKET)
+                return EXEC_OUTPUT_INHERIT;
+
+        return context->std_output;
+}
+
+static int fixup_error(const ExecContext *context, int socket_fd) {
+        assert(context);
+
+        if (socket_fd < 0 && context->std_error == EXEC_OUTPUT_SOCKET)
+                return EXEC_OUTPUT_INHERIT;
+
+        return context->std_error;
+}
+
+static int setup_input(const ExecContext *context, int socket_fd) {
+        ExecInput i;
+
+        assert(context);
+
+        i = fixup_input(context, socket_fd);
+
+        switch (i) {
+
+        case EXEC_INPUT_NULL:
+                return open_null_as(O_RDONLY, STDIN_FILENO);
+
+        case EXEC_INPUT_TTY:
+        case EXEC_INPUT_TTY_FORCE:
+        case EXEC_INPUT_TTY_FAIL: {
+                int fd, r;
+
+                if ((fd = acquire_terminal(
+                                     tty_path(context),
+                                     i == EXEC_INPUT_TTY_FAIL,
+                                     i == EXEC_INPUT_TTY_FORCE)) < 0)
+                        return fd;
+
+                if (fd != STDIN_FILENO) {
+                        r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
+                        close_nointr_nofail(fd);
+                } else
+                        r = STDIN_FILENO;
+
+                return r;
+        }
+
+        case EXEC_INPUT_SOCKET:
+                return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
+
+        default:
+                assert_not_reached("Unknown input type");
+        }
+}
+
+static int setup_output(const ExecContext *context, int socket_fd, const char *ident) {
+        ExecOutput o;
+        ExecInput i;
+
+        assert(context);
+        assert(ident);
+
+        i = fixup_input(context, socket_fd);
+        o = fixup_output(context, socket_fd);
+
+        /* This expects the input is already set up */
+
+        switch (o) {
+
+        case EXEC_OUTPUT_INHERIT:
+
+                /* If the input is connected to a terminal, inherit that... */
+                if (is_terminal_input(i) || i == EXEC_INPUT_SOCKET)
+                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
+
+                return STDIN_FILENO;
+
+        case EXEC_OUTPUT_NULL:
+                return open_null_as(O_WRONLY, STDOUT_FILENO);
+
+        case EXEC_OUTPUT_TTY:
+                if (is_terminal_input(i))
+                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
+
+                /* We don't reset the terminal if this is just about output */
+                return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
+
+        case EXEC_OUTPUT_SYSLOG:
+        case EXEC_OUTPUT_KERNEL:
+                return connect_logger_as(context, o, ident, STDOUT_FILENO);
+
+        case EXEC_OUTPUT_SOCKET:
+                assert(socket_fd >= 0);
+                return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
+
+        default:
+                assert_not_reached("Unknown output type");
+        }
+}
+
+static int setup_error(const ExecContext *context, int socket_fd, const char *ident) {
+        ExecOutput o, e;
+        ExecInput i;
+
+        assert(context);
+        assert(ident);
+
+        i = fixup_input(context, socket_fd);
+        o = fixup_output(context, socket_fd);
+        e = fixup_error(context, socket_fd);
+
+        /* This expects the input and output are already set up */
+
+        /* Don't change the stderr file descriptor if we inherit all
+         * the way and are not on a tty */
+        if (e == EXEC_OUTPUT_INHERIT &&
+            o == EXEC_OUTPUT_INHERIT &&
+            !is_terminal_input(i))
+                return STDERR_FILENO;
+
+        /* Duplicate form stdout if possible */
+        if (e == o || e == EXEC_OUTPUT_INHERIT)
+                return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
+
+        switch (e) {
+
+        case EXEC_OUTPUT_NULL:
+                return open_null_as(O_WRONLY, STDERR_FILENO);
+
+        case EXEC_OUTPUT_TTY:
+                if (is_terminal_input(i))
+                        return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
+
+                /* We don't reset the terminal if this is just about output */
+                return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);
+
+        case EXEC_OUTPUT_SYSLOG:
+        case EXEC_OUTPUT_KERNEL:
+                return connect_logger_as(context, e, ident, STDERR_FILENO);
+
+        case EXEC_OUTPUT_SOCKET:
+                assert(socket_fd >= 0);
+                return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
+
+        default:
+                assert_not_reached("Unknown error type");
+        }
+}
+
+static int chown_terminal(int fd, uid_t uid) {
+        struct stat st;
+
+        assert(fd >= 0);
+
+        /* This might fail. What matters are the results. */
+        (void) fchown(fd, uid, -1);
+        (void) fchmod(fd, TTY_MODE);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
+                return -EPERM;
+
+        return 0;
+}
+
+static int setup_confirm_stdio(const ExecContext *context,
+                               int *_saved_stdin,
+                               int *_saved_stdout) {
+        int fd = -1, saved_stdin, saved_stdout = -1, r;
+
+        assert(context);
+        assert(_saved_stdin);
+        assert(_saved_stdout);
+
+        /* This returns positive EXIT_xxx return values instead of
+         * negative errno style values! */
+
+        if ((saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3)) < 0)
+                return EXIT_STDIN;
+
+        if ((saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3)) < 0) {
+                r = EXIT_STDOUT;
+                goto fail;
+        }
+
+        if ((fd = acquire_terminal(
+                             tty_path(context),
+                             context->std_input == EXEC_INPUT_TTY_FAIL,
+                             context->std_input == EXEC_INPUT_TTY_FORCE)) < 0) {
+                r = EXIT_STDIN;
+                goto fail;
+        }
+
+        if (chown_terminal(fd, getuid()) < 0) {
+                r = EXIT_STDIN;
+                goto fail;
+        }
+
+        if (dup2(fd, STDIN_FILENO) < 0) {
+                r = EXIT_STDIN;
+                goto fail;
+        }
+
+        if (dup2(fd, STDOUT_FILENO) < 0) {
+                r = EXIT_STDOUT;
+                goto fail;
+        }
+
+        if (fd >= 2)
+                close_nointr_nofail(fd);
+
+        *_saved_stdin = saved_stdin;
+        *_saved_stdout = saved_stdout;
+
+        return 0;
+
+fail:
+        if (saved_stdout >= 0)
+                close_nointr_nofail(saved_stdout);
+
+        if (saved_stdin >= 0)
+                close_nointr_nofail(saved_stdin);
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
+
+static int restore_confirm_stdio(const ExecContext *context,
+                                 int *saved_stdin,
+                                 int *saved_stdout,
+                                 bool *keep_stdin,
+                                 bool *keep_stdout) {
+
+        assert(context);
+        assert(saved_stdin);
+        assert(*saved_stdin >= 0);
+        assert(saved_stdout);
+        assert(*saved_stdout >= 0);
+
+        /* This returns positive EXIT_xxx return values instead of
+         * negative errno style values! */
+
+        if (is_terminal_input(context->std_input)) {
+
+                /* The service wants terminal input. */
+
+                *keep_stdin = true;
+                *keep_stdout =
+                        context->std_output == EXEC_OUTPUT_INHERIT ||
+                        context->std_output == EXEC_OUTPUT_TTY;
+
+        } else {
+                /* If the service doesn't want a controlling terminal,
+                 * then we need to get rid entirely of what we have
+                 * already. */
+
+                if (release_terminal() < 0)
+                        return EXIT_STDIN;
+
+                if (dup2(*saved_stdin, STDIN_FILENO) < 0)
+                        return EXIT_STDIN;
+
+                if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
+                        return EXIT_STDOUT;
+
+                *keep_stdout = *keep_stdin = false;
+        }
+
+        return 0;
+}
+
+static int get_group_creds(const char *groupname, gid_t *gid) {
+        struct group *g;
+        unsigned long lu;
+
+        assert(groupname);
+        assert(gid);
+
+        /* We enforce some special rules for gid=0: in order to avoid
+         * NSS lookups for root we hardcode its data. */
+
+        if (streq(groupname, "root") || streq(groupname, "0")) {
+                *gid = 0;
+                return 0;
+        }
+
+        if (safe_atolu(groupname, &lu) >= 0) {
+                errno = 0;
+                g = getgrgid((gid_t) lu);
+        } else {
+                errno = 0;
+                g = getgrnam(groupname);
+        }
+
+        if (!g)
+                return errno != 0 ? -errno : -ESRCH;
+
+        *gid = g->gr_gid;
+        return 0;
+}
+
+static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
+        struct passwd *p;
+        unsigned long lu;
+
+        assert(username);
+        assert(*username);
+        assert(uid);
+        assert(gid);
+        assert(home);
+
+        /* We enforce some special rules for uid=0: in order to avoid
+         * NSS lookups for root we hardcode its data. */
+
+        if (streq(*username, "root") || streq(*username, "0")) {
+                *username = "root";
+                *uid = 0;
+                *gid = 0;
+                *home = "/root";
+                return 0;
+        }
+
+        if (safe_atolu(*username, &lu) >= 0) {
+                errno = 0;
+                p = getpwuid((uid_t) lu);
+
+                /* If there are multiple users with the same id, make
+                 * sure to leave $USER to the configured value instead
+                 * of the first occurence in the database. However if
+                 * the uid was configured by a numeric uid, then let's
+                 * pick the real username from /etc/passwd. */
+                if (*username && p)
+                        *username = p->pw_name;
+        } else {
+                errno = 0;
+                p = getpwnam(*username);
+        }
+
+        if (!p)
+                return errno != 0 ? -errno : -ESRCH;
+
+        *uid = p->pw_uid;
+        *gid = p->pw_gid;
+        *home = p->pw_dir;
+        return 0;
+}
+
+static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
+        bool keep_groups = false;
+        int r;
+
+        assert(context);
+
+        /* Lookup and ser GID and supplementary group list. Here too
+         * we avoid NSS lookups for gid=0. */
+
+        if (context->group || username) {
+
+                if (context->group)
+                        if ((r = get_group_creds(context->group, &gid)) < 0)
+                                return r;
+
+                /* First step, initialize groups from /etc/groups */
+                if (username && gid != 0) {
+                        if (initgroups(username, gid) < 0)
+                                return -errno;
+
+                        keep_groups = true;
+                }
+
+                /* Second step, set our gids */
+                if (setresgid(gid, gid, gid) < 0)
+                        return -errno;
+        }
+
+        if (context->supplementary_groups) {
+                int ngroups_max, k;
+                gid_t *gids;
+                char **i;
+
+                /* Final step, initialize any manually set supplementary groups */
+                ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);
+
+                if (!(gids = new(gid_t, ngroups_max)))
+                        return -ENOMEM;
+
+                if (keep_groups) {
+                        if ((k = getgroups(ngroups_max, gids)) < 0) {
+                                free(gids);
+                                return -errno;
+                        }
+                } else
+                        k = 0;
+
+                STRV_FOREACH(i, context->supplementary_groups) {
+
+                        if (k >= ngroups_max) {
+                                free(gids);
+                                return -E2BIG;
+                        }
+
+                        if ((r = get_group_creds(*i, gids+k)) < 0) {
+                                free(gids);
+                                return r;
+                        }
+
+                        k++;
+                }
+
+                if (setgroups(k, gids) < 0) {
+                        free(gids);
+                        return -errno;
+                }
+
+                free(gids);
+        }
+
+        return 0;
+}
+
+static int enforce_user(const ExecContext *context, uid_t uid) {
+        int r;
+        assert(context);
+
+        /* Sets (but doesn't lookup) the uid and make sure we keep the
+         * capabilities while doing so. */
+
+        if (context->capabilities) {
+                cap_t d;
+                static const cap_value_t bits[] = {
+                        CAP_SETUID,   /* Necessary so that we can run setresuid() below */
+                        CAP_SETPCAP   /* Necessary so that we can set PR_SET_SECUREBITS later on */
+                };
+
+                /* First step: If we need to keep capabilities but
+                 * drop privileges we need to make sure we keep our
+                 * caps, whiel we drop priviliges. */
+                if (uid != 0) {
+                        int sb = context->secure_bits|SECURE_KEEP_CAPS;
+
+                        if (prctl(PR_GET_SECUREBITS) != sb)
+                                if (prctl(PR_SET_SECUREBITS, sb) < 0)
+                                        return -errno;
+                }
+
+                /* Second step: set the capabilites. This will reduce
+                 * the capabilities to the minimum we need. */
+
+                if (!(d = cap_dup(context->capabilities)))
+                        return -errno;
+
+                if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
+                    cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) {
+                        r = -errno;
+                        cap_free(d);
+                        return r;
+                }
+
+                if (cap_set_proc(d) < 0) {
+                        r = -errno;
+                        cap_free(d);
+                        return r;
+                }
+
+                cap_free(d);
+        }
+
+        /* Third step: actually set the uids */
+        if (setresuid(uid, uid, uid) < 0)
+                return -errno;
+
+        /* At this point we should have all necessary capabilities but
+           are otherwise a normal user. However, the caps might got
+           corrupted due to the setresuid() so we need clean them up
+           later. This is done outside of this call. */
+
+        return 0;
+}
+
+int exec_spawn(ExecCommand *command,
+               char **argv,
+               const ExecContext *context,
+               int fds[], unsigned n_fds,
+               char **environment,
+               bool apply_permissions,
+               bool apply_chroot,
+               bool confirm_spawn,
+               CGroupBonding *cgroup_bondings,
+               pid_t *ret) {
+
+        pid_t pid;
+        int r;
+        char *line;
+        int socket_fd;
+
+        assert(command);
+        assert(context);
+        assert(ret);
+        assert(fds || n_fds <= 0);
+
+        if (context->std_input == EXEC_INPUT_SOCKET ||
+            context->std_output == EXEC_OUTPUT_SOCKET ||
+            context->std_error == EXEC_OUTPUT_SOCKET) {
+
+                if (n_fds != 1)
+                        return -EINVAL;
+
+                socket_fd = fds[0];
+
+                fds = NULL;
+                n_fds = 0;
+        } else
+                socket_fd = -1;
+
+        if (!argv)
+                argv = command->argv;
+
+        if (!(line = exec_command_line(argv)))
+                return -ENOMEM;
+
+        log_debug("About to execute: %s", line);
+        free(line);
+
+        if (cgroup_bondings)
+                if ((r = cgroup_bonding_realize_list(cgroup_bondings)))
+                        return r;
+
+        if ((pid = fork()) < 0)
+                return -errno;
+
+        if (pid == 0) {
+                int i;
+                sigset_t ss;
+                const char *username = NULL, *home = NULL;
+                uid_t uid = (uid_t) -1;
+                gid_t gid = (gid_t) -1;
+                char **our_env = NULL, **final_env = NULL;
+                unsigned n_env = 0;
+                int saved_stdout = -1, saved_stdin = -1;
+                bool keep_stdout = false, keep_stdin = false;
+
+                /* child */
+
+                reset_all_signal_handlers();
+
+                if (sigemptyset(&ss) < 0 ||
+                    sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
+                        r = EXIT_SIGNAL_MASK;
+                        goto fail;
+                }
+
+                if (!context->no_setsid)
+                        if (setsid() < 0) {
+                                r = EXIT_SETSID;
+                                goto fail;
+                        }
+
+                if (confirm_spawn) {
+                        char response;
+
+                        /* Set up terminal for the question */
+                        if ((r = setup_confirm_stdio(context,
+                                                     &saved_stdin, &saved_stdout)))
+                                goto fail;
+
+                        /* Now ask the question. */
+                        if (!(line = exec_command_line(argv))) {
+                                r = EXIT_MEMORY;
+                                goto fail;
+                        }
+
+                        r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line);
+                        free(line);
+
+                        if (r < 0 || response == 'n') {
+                                r = EXIT_CONFIRM;
+                                goto fail;
+                        } else if (response == 's') {
+                                r = 0;
+                                goto fail;
+                        }
+
+                        /* Release terminal for the question */
+                        if ((r = restore_confirm_stdio(context,
+                                                       &saved_stdin, &saved_stdout,
+                                                       &keep_stdin, &keep_stdout)))
+                                goto fail;
+                }
+
+                if (!keep_stdin)
+                        if (setup_input(context, socket_fd) < 0) {
+                                r = EXIT_STDIN;
+                                goto fail;
+                        }
+
+                if (!keep_stdout)
+                        if (setup_output(context, socket_fd, file_name_from_path(command->path)) < 0) {
+                                r = EXIT_STDOUT;
+                                goto fail;
+                        }
+
+                if (setup_error(context, socket_fd, file_name_from_path(command->path)) < 0) {
+                        r = EXIT_STDERR;
+                        goto fail;
+                }
+
+                if (cgroup_bondings)
+                        if ((r = cgroup_bonding_install_list(cgroup_bondings, 0)) < 0) {
+                                r = EXIT_CGROUP;
+                                goto fail;
+                        }
+
+                if (context->oom_adjust_set) {
+                        char t[16];
+
+                        snprintf(t, sizeof(t), "%i", context->oom_adjust);
+                        char_array_0(t);
+
+                        if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
+                                r = EXIT_OOM_ADJUST;
+                                goto fail;
+                        }
+                }
+
+                if (context->nice_set)
+                        if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
+                                r = EXIT_NICE;
+                                goto fail;
+                        }
+
+                if (context->cpu_sched_set) {
+                        struct sched_param param;
+
+                        zero(param);
+                        param.sched_priority = context->cpu_sched_priority;
+
+                        if (sched_setscheduler(0, context->cpu_sched_policy |
+                                               (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), &param) < 0) {
+                                r = EXIT_SETSCHEDULER;
+                                goto fail;
+                        }
+                }
+
+                if (context->cpu_affinity_set)
+                        if (sched_setaffinity(0, sizeof(context->cpu_affinity), &context->cpu_affinity) < 0) {
+                                r = EXIT_CPUAFFINITY;
+                                goto fail;
+                        }
+
+                if (context->ioprio_set)
+                        if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
+                                r = EXIT_IOPRIO;
+                                goto fail;
+                        }
+
+                if (context->timer_slack_ns_set)
+                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_ns_set) < 0) {
+                                r = EXIT_TIMERSLACK;
+                                goto fail;
+                        }
+
+                if (strv_length(context->read_write_dirs) > 0 ||
+                    strv_length(context->read_only_dirs) > 0 ||
+                    strv_length(context->inaccessible_dirs) > 0 ||
+                    context->mount_flags != MS_SHARED ||
+                    context->private_tmp)
+                        if ((r = setup_namespace(
+                                             context->read_write_dirs,
+                                             context->read_only_dirs,
+                                             context->inaccessible_dirs,
+                                             context->private_tmp,
+                                             context->mount_flags)) < 0)
+                                goto fail;
+
+                if (context->user) {
+                        username = context->user;
+                        if (get_user_creds(&username, &uid, &gid, &home) < 0) {
+                                r = EXIT_USER;
+                                goto fail;
+                        }
+
+                        if (is_terminal_input(context->std_input))
+                                if (chown_terminal(STDIN_FILENO, uid) < 0) {
+                                        r = EXIT_STDIN;
+                                        goto fail;
+                                }
+                }
+
+                if (apply_permissions)
+                        if (enforce_groups(context, username, uid) < 0) {
+                                r = EXIT_GROUP;
+                                goto fail;
+                        }
+
+                umask(context->umask);
+
+                if (apply_chroot) {
+                        if (context->root_directory)
+                                if (chroot(context->root_directory) < 0) {
+                                        r = EXIT_CHROOT;
+                                        goto fail;
+                                }
+
+                        if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
+                                r = EXIT_CHDIR;
+                                goto fail;
+                        }
+                } else {
+
+                        char *d;
+
+                        if (asprintf(&d, "%s/%s",
+                                     context->root_directory ? context->root_directory : "",
+                                     context->working_directory ? context->working_directory : "") < 0) {
+                                r = EXIT_MEMORY;
+                                goto fail;
+                        }
+
+                        if (chdir(d) < 0) {
+                                free(d);
+                                r = EXIT_CHDIR;
+                                goto fail;
+                        }
+
+                        free(d);
+                }
+
+                if (close_all_fds(fds, n_fds) < 0 ||
+                    shift_fds(fds, n_fds) < 0 ||
+                    flags_fds(fds, n_fds, context->non_blocking) < 0) {
+                        r = EXIT_FDS;
+                        goto fail;
+                }
+
+                if (apply_permissions) {
+
+                        for (i = 0; i < RLIMIT_NLIMITS; i++) {
+                                if (!context->rlimit[i])
+                                        continue;
+
+                                if (setrlimit(i, context->rlimit[i]) < 0) {
+                                        r = EXIT_LIMITS;
+                                        goto fail;
+                                }
+                        }
+
+                        if (context->user)
+                                if (enforce_user(context, uid) < 0) {
+                                        r = EXIT_USER;
+                                        goto fail;
+                                }
+
+                        /* PR_GET_SECUREBITS is not priviliged, while
+                         * PR_SET_SECUREBITS is. So to suppress
+                         * potential EPERMs we'll try not to call
+                         * PR_SET_SECUREBITS unless necessary. */
+                        if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
+                                if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
+                                        r = EXIT_SECUREBITS;
+                                        goto fail;
+                                }
+
+                        if (context->capabilities)
+                                if (cap_set_proc(context->capabilities) < 0) {
+                                        r = EXIT_CAPABILITIES;
+                                        goto fail;
+                                }
+                }
+
+                if (!(our_env = new0(char*, 6))) {
+                        r = EXIT_MEMORY;
+                        goto fail;
+                }
+
+                if (n_fds > 0)
+                        if (asprintf(our_env + n_env++, "LISTEN_PID=%llu", (unsigned long long) getpid()) < 0 ||
+                            asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
+                                r = EXIT_MEMORY;
+                                goto fail;
+                        }
+
+                if (home)
+                        if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
+                                r = EXIT_MEMORY;
+                                goto fail;
+                        }
+
+                if (username)
+                        if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
+                            asprintf(our_env + n_env++, "USER=%s", username) < 0) {
+                                r = EXIT_MEMORY;
+                                goto fail;
+                        }
+
+                assert(n_env <= 6);
+
+                if (!(final_env = strv_env_merge(environment, our_env, context->environment, NULL))) {
+                        r = EXIT_MEMORY;
+                        goto fail;
+                }
+
+                execve(command->path, argv, final_env);
+                r = EXIT_EXEC;
+
+        fail:
+                strv_free(our_env);
+                strv_free(final_env);
+
+                if (saved_stdin >= 0)
+                        close_nointr_nofail(saved_stdin);
+
+                if (saved_stdout >= 0)
+                        close_nointr_nofail(saved_stdout);
+
+                _exit(r);
+        }
+
+        /* We add the new process to the cgroup both in the child (so
+         * that we can be sure that no user code is ever executed
+         * outside of the cgroup) and in the parent (so that we can be
+         * sure that when we kill the cgroup the process will be
+         * killed too). */
+        if (cgroup_bondings)
+                cgroup_bonding_install_list(cgroup_bondings, pid);
+
+        log_debug("Forked %s as %llu", command->path, (unsigned long long) pid);
+
+        command->exec_status.pid = pid;
+        command->exec_status.start_timestamp = now(CLOCK_REALTIME);
+
+        *ret = pid;
+        return 0;
+}
+
+void exec_context_init(ExecContext *c) {
+        assert(c);
+
+        c->umask = 0002;
+        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
+        c->cpu_sched_policy = SCHED_OTHER;
+        c->syslog_priority = LOG_DAEMON|LOG_INFO;
+        c->mount_flags = MS_SHARED;
+}
+
+void exec_context_done(ExecContext *c) {
+        unsigned l;
+
+        assert(c);
+
+        strv_free(c->environment);
+        c->environment = NULL;
+
+        for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
+                free(c->rlimit[l]);
+                c->rlimit[l] = NULL;
+        }
+
+        free(c->working_directory);
+        c->working_directory = NULL;
+        free(c->root_directory);
+        c->root_directory = NULL;
+
+        free(c->tty_path);
+        c->tty_path = NULL;
+
+        free(c->syslog_identifier);
+        c->syslog_identifier = NULL;
+
+        free(c->user);
+        c->user = NULL;
+
+        free(c->group);
+        c->group = NULL;
+
+        strv_free(c->supplementary_groups);
+        c->supplementary_groups = NULL;
+
+        if (c->capabilities) {
+                cap_free(c->capabilities);
+                c->capabilities = NULL;
+        }
+
+        strv_free(c->read_only_dirs);
+        c->read_only_dirs = NULL;
+
+        strv_free(c->read_write_dirs);
+        c->read_write_dirs = NULL;
+
+        strv_free(c->inaccessible_dirs);
+        c->inaccessible_dirs = NULL;
+}
+
+void exec_command_done(ExecCommand *c) {
+        assert(c);
+
+        free(c->path);
+        c->path = NULL;
+
+        strv_free(c->argv);
+        c->argv = NULL;
+}
+
+void exec_command_done_array(ExecCommand *c, unsigned n) {
+        unsigned i;
+
+        for (i = 0; i < n; i++)
+                exec_command_done(c+i);
+}
+
+void exec_command_free_list(ExecCommand *c) {
+        ExecCommand *i;
+
+        while ((i = c)) {
+                LIST_REMOVE(ExecCommand, command, c, i);
+                exec_command_done(i);
+                free(i);
+        }
+}
+
+void exec_command_free_array(ExecCommand **c, unsigned n) {
+        unsigned i;
+
+        for (i = 0; i < n; i++) {
+                exec_command_free_list(c[i]);
+                c[i] = NULL;
+        }
+}
+
+static void strv_fprintf(FILE *f, char **l) {
+        char **g;
+
+        assert(f);
+
+        STRV_FOREACH(g, l)
+                fprintf(f, " %s", *g);
+}
+
+void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
+        char ** e;
+        unsigned i;
+
+        assert(c);
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        fprintf(f,
+                "%sUMask: %04o\n"
+                "%sWorkingDirectory: %s\n"
+                "%sRootDirectory: %s\n"
+                "%sNonBlocking: %s\n"
+                "%sPrivateTmp: %s\n",
+                prefix, c->umask,
+                prefix, c->working_directory ? c->working_directory : "/",
+                prefix, c->root_directory ? c->root_directory : "/",
+                prefix, yes_no(c->non_blocking),
+                prefix, yes_no(c->private_tmp));
+
+        if (c->environment)
+                for (e = c->environment; *e; e++)
+                        fprintf(f, "%sEnvironment: %s\n", prefix, *e);
+
+        if (c->nice_set)
+                fprintf(f,
+                        "%sNice: %i\n",
+                        prefix, c->nice);
+
+        if (c->oom_adjust_set)
+                fprintf(f,
+                        "%sOOMAdjust: %i\n",
+                        prefix, c->oom_adjust);
+
+        for (i = 0; i < RLIM_NLIMITS; i++)
+                if (c->rlimit[i])
+                        fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
+
+        if (c->ioprio_set)
+                fprintf(f,
+                        "%sIOSchedulingClass: %s\n"
+                        "%sIOPriority: %i\n",
+                        prefix, ioprio_class_to_string(IOPRIO_PRIO_CLASS(c->ioprio)),
+                        prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
+
+        if (c->cpu_sched_set)
+                fprintf(f,
+                        "%sCPUSchedulingPolicy: %s\n"
+                        "%sCPUSchedulingPriority: %i\n"
+                        "%sCPUSchedulingResetOnFork: %s\n",
+                        prefix, sched_policy_to_string(c->cpu_sched_policy),
+                        prefix, c->cpu_sched_priority,
+                        prefix, yes_no(c->cpu_sched_reset_on_fork));
+
+        if (c->cpu_affinity_set) {
+                fprintf(f, "%sCPUAffinity:", prefix);
+                for (i = 0; i < CPU_SETSIZE; i++)
+                        if (CPU_ISSET(i, &c->cpu_affinity))
+                                fprintf(f, " %i", i);
+                fputs("\n", f);
+        }
+
+        if (c->timer_slack_ns_set)
+                fprintf(f, "%sTimerSlackNS: %lu\n", prefix, c->timer_slack_ns);
+
+        fprintf(f,
+                "%sStandardInput: %s\n"
+                "%sStandardOutput: %s\n"
+                "%sStandardError: %s\n",
+                prefix, exec_input_to_string(c->std_input),
+                prefix, exec_output_to_string(c->std_output),
+                prefix, exec_output_to_string(c->std_error));
+
+        if (c->tty_path)
+                fprintf(f,
+                        "%sTTYPath: %s\n",
+                        prefix, c->tty_path);
+
+        if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KERNEL ||
+            c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KERNEL)
+                fprintf(f,
+                        "%sSyslogFacility: %s\n"
+                        "%sSyslogLevel: %s\n",
+                        prefix, log_facility_to_string(LOG_FAC(c->syslog_priority)),
+                        prefix, log_level_to_string(LOG_PRI(c->syslog_priority)));
+
+        if (c->capabilities) {
+                char *t;
+                if ((t = cap_to_text(c->capabilities, NULL))) {
+                        fprintf(f, "%sCapabilities: %s\n",
+                                prefix, t);
+                        cap_free(t);
+                }
+        }
+
+        if (c->secure_bits)
+                fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
+                        prefix,
+                        (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "",
+                        (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
+                        (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
+                        (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
+                        (c->secure_bits & SECURE_NOROOT) ? " noroot" : "",
+                        (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
+
+        if (c->capability_bounding_set_drop) {
+                fprintf(f, "%sCapabilityBoundingSetDrop:", prefix);
+
+                for (i = 0; i <= CAP_LAST_CAP; i++)
+                        if (c->capability_bounding_set_drop & (1 << i)) {
+                                char *t;
+
+                                if ((t = cap_to_name(i))) {
+                                        fprintf(f, " %s", t);
+                                        free(t);
+                                }
+                        }
+
+                fputs("\n", f);
+        }
+
+        if (c->user)
+                fprintf(f, "%sUser: %s", prefix, c->user);
+        if (c->group)
+                fprintf(f, "%sGroup: %s", prefix, c->group);
+
+        if (strv_length(c->supplementary_groups) > 0) {
+                fprintf(f, "%sSupplementaryGroups:", prefix);
+                strv_fprintf(f, c->supplementary_groups);
+                fputs("\n", f);
+        }
+
+        if (strv_length(c->read_write_dirs) > 0) {
+                fprintf(f, "%sReadWriteDirs:", prefix);
+                strv_fprintf(f, c->read_write_dirs);
+                fputs("\n", f);
+        }
+
+        if (strv_length(c->read_only_dirs) > 0) {
+                fprintf(f, "%sReadOnlyDirs:", prefix);
+                strv_fprintf(f, c->read_only_dirs);
+                fputs("\n", f);
+        }
+
+        if (strv_length(c->inaccessible_dirs) > 0) {
+                fprintf(f, "%sInaccessibleDirs:", prefix);
+                strv_fprintf(f, c->inaccessible_dirs);
+                fputs("\n", f);
+        }
+}
+
+void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
+        assert(s);
+
+        s->pid = pid;
+        s->exit_timestamp = now(CLOCK_REALTIME);
+
+        s->code = code;
+        s->status = status;
+}
+
+void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
+        char buf[FORMAT_TIMESTAMP_MAX];
+
+        assert(s);
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        if (s->pid <= 0)
+                return;
+
+        fprintf(f,
+                "%sPID: %llu\n",
+                prefix, (unsigned long long) s->pid);
+
+        if (s->start_timestamp > 0)
+                fprintf(f,
+                        "%sStart Timestamp: %s\n",
+                        prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp));
+
+        if (s->exit_timestamp > 0)
+                fprintf(f,
+                        "%sExit Timestamp: %s\n"
+                        "%sExit Code: %s\n"
+                        "%sExit Status: %i\n",
+                        prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp),
+                        prefix, sigchld_code_to_string(s->code),
+                        prefix, s->status);
+}
+
+char *exec_command_line(char **argv) {
+        size_t k;
+        char *n, *p, **a;
+        bool first = true;
+
+        assert(argv);
+
+        k = 1;
+        STRV_FOREACH(a, argv)
+                k += strlen(*a)+3;
+
+        if (!(n = new(char, k)))
+                return NULL;
+
+        p = n;
+        STRV_FOREACH(a, argv) {
+
+                if (!first)
+                        *(p++) = ' ';
+                else
+                        first = false;
+
+                if (strpbrk(*a, WHITESPACE)) {
+                        *(p++) = '\'';
+                        p = stpcpy(p, *a);
+                        *(p++) = '\'';
+                } else
+                        p = stpcpy(p, *a);
+
+        }
+
+        *p = 0;
+
+        /* FIXME: this doesn't really handle arguments that have
+         * spaces and ticks in them */
+
+        return n;
+}
+
+void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
+        char *p2;
+        const char *prefix2;
+
+        char *cmd;
+
+        assert(c);
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+        p2 = strappend(prefix, "\t");
+        prefix2 = p2 ? p2 : prefix;
+
+        cmd = exec_command_line(c->argv);
+
+        fprintf(f,
+                "%sCommand Line: %s\n",
+                prefix, cmd ? cmd : strerror(ENOMEM));
+
+        free(cmd);
+
+        exec_status_dump(&c->exec_status, f, prefix2);
+
+        free(p2);
+}
+
+void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        LIST_FOREACH(command, c, c)
+                exec_command_dump(c, f, prefix);
+}
+
+void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
+        ExecCommand *end;
+
+        assert(l);
+        assert(e);
+
+        if (*l) {
+                /* It's kinda important that we keep the order here */
+                LIST_FIND_TAIL(ExecCommand, command, *l, end);
+                LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
+        } else
+              *l = e;
+}
+
+int exec_command_set(ExecCommand *c, const char *path, ...) {
+        va_list ap;
+        char **l, *p;
+
+        assert(c);
+        assert(path);
+
+        va_start(ap, path);
+        l = strv_new_ap(path, ap);
+        va_end(ap);
+
+        if (!l)
+                return -ENOMEM;
+
+        if (!(p = strdup(path))) {
+                strv_free(l);
+                return -ENOMEM;
+        }
+
+        free(c->path);
+        c->path = p;
+
+        strv_free(c->argv);
+        c->argv = l;
+
+        return 0;
+}
+
+const char* exit_status_to_string(ExitStatus status) {
+
+        /* We cast to int here, so that -Wenum doesn't complain that
+         * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */
+
+        switch ((int) status) {
+
+        case EXIT_SUCCESS:
+                return "SUCCESS";
+
+        case EXIT_FAILURE:
+                return "FAILURE";
+
+        case EXIT_INVALIDARGUMENT:
+                return "INVALIDARGUMENT";
+
+        case EXIT_NOTIMPLEMENTED:
+                return "NOTIMPLEMENTED";
+
+        case EXIT_NOPERMISSION:
+                return "NOPERMISSION";
+
+        case EXIT_NOTINSTALLED:
+                return "NOTINSSTALLED";
+
+        case EXIT_NOTCONFIGURED:
+                return "NOTCONFIGURED";
+
+        case EXIT_NOTRUNNING:
+                return "NOTRUNNING";
+
+        case EXIT_CHDIR:
+                return "CHDIR";
+
+        case EXIT_NICE:
+                return "NICE";
+
+        case EXIT_FDS:
+                return "FDS";
+
+        case EXIT_EXEC:
+                return "EXEC";
+
+        case EXIT_MEMORY:
+                return "MEMORY";
+
+        case EXIT_LIMITS:
+                return "LIMITS";
+
+        case EXIT_OOM_ADJUST:
+                return "OOM_ADJUST";
+
+        case EXIT_SIGNAL_MASK:
+                return "SIGNAL_MASK";
+
+        case EXIT_STDIN:
+                return "STDIN";
+
+        case EXIT_STDOUT:
+                return "STDOUT";
+
+        case EXIT_CHROOT:
+                return "CHROOT";
+
+        case EXIT_IOPRIO:
+                return "IOPRIO";
+
+        case EXIT_TIMERSLACK:
+                return "TIMERSLACK";
+
+        case EXIT_SECUREBITS:
+                return "SECUREBITS";
+
+        case EXIT_SETSCHEDULER:
+                return "SETSCHEDULER";
+
+        case EXIT_CPUAFFINITY:
+                return "CPUAFFINITY";
+
+        case EXIT_GROUP:
+                return "GROUP";
+
+        case EXIT_USER:
+                return "USER";
+
+        case EXIT_CAPABILITIES:
+                return "CAPABILITIES";
+
+        case EXIT_CGROUP:
+                return "CGROUP";
+
+        case EXIT_SETSID:
+                return "SETSID";
+
+        case EXIT_CONFIRM:
+                return "CONFIRM";
+
+        case EXIT_STDERR:
+                return "STDERR";
+
+        default:
+                return NULL;
+        }
+}
+
+static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
+        [EXEC_INPUT_NULL] = "null",
+        [EXEC_INPUT_TTY] = "tty",
+        [EXEC_INPUT_TTY_FORCE] = "tty-force",
+        [EXEC_INPUT_TTY_FAIL] = "tty-fail",
+        [EXEC_INPUT_SOCKET] = "socket"
+};
+
+static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
+        [EXEC_OUTPUT_INHERIT] = "inherit",
+        [EXEC_OUTPUT_NULL] = "null",
+        [EXEC_OUTPUT_TTY] = "tty",
+        [EXEC_OUTPUT_SYSLOG] = "syslog",
+        [EXEC_OUTPUT_KERNEL] = "kernel",
+        [EXEC_OUTPUT_SOCKET] = "socket"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
+
+DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
diff --git a/src/execute.h b/src/execute.h
new file mode 100644
index 0000000..be73542
--- /dev/null
+++ b/src/execute.h
@@ -0,0 +1,221 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooexecutehfoo
+#define fooexecutehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct ExecStatus ExecStatus;
+typedef struct ExecCommand ExecCommand;
+typedef struct ExecContext ExecContext;
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/capability.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct CGroupBonding;
+
+#include "list.h"
+#include "util.h"
+
+/* Abstract namespace! */
+#define LOGGER_SOCKET "/org/freedesktop/systemd1/logger"
+
+typedef enum ExecInput {
+        EXEC_INPUT_NULL,
+        EXEC_INPUT_TTY,
+        EXEC_INPUT_TTY_FORCE,
+        EXEC_INPUT_TTY_FAIL,
+        EXEC_INPUT_SOCKET,
+        _EXEC_INPUT_MAX,
+        _EXEC_INPUT_INVALID = -1
+} ExecInput;
+
+typedef enum ExecOutput {
+        EXEC_OUTPUT_INHERIT,
+        EXEC_OUTPUT_NULL,
+        EXEC_OUTPUT_TTY,
+        EXEC_OUTPUT_SYSLOG,
+        EXEC_OUTPUT_KERNEL,
+        EXEC_OUTPUT_SOCKET,
+        _EXEC_OUTPUT_MAX,
+        _EXEC_OUTPUT_INVALID = -1
+} ExecOutput;
+
+struct ExecStatus {
+        usec_t start_timestamp;
+        usec_t exit_timestamp;
+        pid_t pid;
+        int code;     /* as in siginfo_t::si_code */
+        int status;   /* as in sigingo_t::si_status */
+};
+
+struct ExecCommand {
+        char *path;
+        char **argv;
+        ExecStatus exec_status;
+        LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
+};
+
+struct ExecContext {
+        char **environment;
+        struct rlimit *rlimit[RLIMIT_NLIMITS];
+        char *working_directory, *root_directory;
+
+        mode_t umask;
+        int oom_adjust;
+        int nice;
+        int ioprio;
+        int cpu_sched_policy;
+        int cpu_sched_priority;
+
+        cpu_set_t cpu_affinity;
+        unsigned long timer_slack_ns;
+
+        ExecInput std_input;
+        ExecOutput std_output;
+        ExecOutput std_error;
+
+        int syslog_priority;
+        char *syslog_identifier;
+        bool syslog_no_prefix;
+
+        char *tty_path;
+
+        /* Since resolving these names might might involve socket
+         * connections and we don't want to deadlock ourselves these
+         * names are resolved on execution only and in the child
+         * process. */
+        char *user;
+        char *group;
+        char **supplementary_groups;
+
+        char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
+        unsigned long mount_flags;
+
+        uint64_t capability_bounding_set_drop;
+
+        cap_t capabilities;
+        int secure_bits;
+
+        bool cpu_sched_reset_on_fork;
+        bool non_blocking;
+        bool private_tmp;
+
+        bool oom_adjust_set:1;
+        bool nice_set:1;
+        bool ioprio_set:1;
+        bool cpu_sched_set:1;
+        bool cpu_affinity_set:1;
+        bool timer_slack_ns_set:1;
+
+        /* This is not exposed to the user but available
+         * internally. We need it to make sure that whenever we spawn
+         * /bin/mount it is run in the same process group as us so
+         * that the autofs logic detects that it belongs to us and we
+         * don't enter a trigger loop. */
+        bool no_setsid:1;
+};
+
+typedef enum ExitStatus {
+        /* EXIT_SUCCESS defined by libc */
+        /* EXIT_FAILURE defined by libc */
+        EXIT_INVALIDARGUMENT = 2,
+        EXIT_NOTIMPLEMENTED = 3,
+        EXIT_NOPERMISSION = 4,
+        EXIT_NOTINSTALLED = 5,
+        EXIT_NOTCONFIGURED = 6,
+        EXIT_NOTRUNNING = 7,
+
+        /* The LSB suggests that error codes >= 200 are "reserved". We
+         * use them here under the assumption that they hence are
+         * unused by init scripts.
+         *
+         * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */
+
+        EXIT_CHDIR = 200,
+        EXIT_NICE,
+        EXIT_FDS,
+        EXIT_EXEC,
+        EXIT_MEMORY,
+        EXIT_LIMITS,
+        EXIT_OOM_ADJUST,
+        EXIT_SIGNAL_MASK,
+        EXIT_STDIN,
+        EXIT_STDOUT,
+        EXIT_CHROOT,   /* 210 */
+        EXIT_IOPRIO,
+        EXIT_TIMERSLACK,
+        EXIT_SECUREBITS,
+        EXIT_SETSCHEDULER,
+        EXIT_CPUAFFINITY,
+        EXIT_GROUP,
+        EXIT_USER,
+        EXIT_CAPABILITIES,
+        EXIT_CGROUP,
+        EXIT_SETSID,   /* 220 */
+        EXIT_CONFIRM,
+        EXIT_STDERR
+
+} ExitStatus;
+
+int exec_spawn(ExecCommand *command,
+               char **argv,
+               const ExecContext *context,
+               int fds[], unsigned n_fds,
+               char **environment,
+               bool apply_permissions,
+               bool apply_chroot,
+               bool confirm_spawn,
+               struct CGroupBonding *cgroup_bondings,
+               pid_t *ret);
+
+void exec_command_done(ExecCommand *c);
+void exec_command_done_array(ExecCommand *c, unsigned n);
+
+void exec_command_free_list(ExecCommand *c);
+void exec_command_free_array(ExecCommand **c, unsigned n);
+
+char *exec_command_line(char **argv);
+
+void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix);
+void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix);
+void exec_command_append_list(ExecCommand **l, ExecCommand *e);
+int exec_command_set(ExecCommand *c, const char *path, ...);
+
+void exec_context_init(ExecContext *c);
+void exec_context_done(ExecContext *c);
+void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
+
+void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status);
+void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
+
+const char* exec_output_to_string(ExecOutput i);
+int exec_output_from_string(const char *s);
+
+const char* exec_input_to_string(ExecInput i);
+int exec_input_from_string(const char *s);
+
+const char* exit_status_to_string(ExitStatus status);
+
+#endif
diff --git a/src/fdset.c b/src/fdset.c
new file mode 100644
index 0000000..b6d5286
--- /dev/null
+++ b/src/fdset.c
@@ -0,0 +1,162 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "set.h"
+#include "util.h"
+#include "macro.h"
+#include "fdset.h"
+
+#define MAKE_SET(s) ((Set*) s)
+#define MAKE_FDSET(s) ((FDSet*) s)
+
+/* Make sure we can distuingish fd 0 and NULL */
+#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
+#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
+
+FDSet *fdset_new(void) {
+        return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func));
+}
+
+void fdset_free(FDSet *s) {
+        void *p;
+
+        while ((p = set_steal_first(MAKE_SET(s)))) {
+                /* Valgrind's fd might have ended up in this set here,
+                 * due to fdset_new_fill(). We'll ignore all failures
+                 * here, so that the EBADFD that valgrind will return
+                 * us on close() doesn't influence us */
+
+                log_warning("Closing left-over fd %i", PTR_TO_FD(p));
+                close_nointr(PTR_TO_FD(p));
+        }
+
+        set_free(MAKE_SET(s));
+}
+
+int fdset_put(FDSet *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        return set_put(MAKE_SET(s), FD_TO_PTR(fd));
+}
+
+int fdset_put_dup(FDSet *s, int fd) {
+        int copy, r;
+
+        assert(s);
+        assert(fd >= 0);
+
+        if ((copy = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0)
+                return -errno;
+
+        if ((r = fdset_put(s, copy)) < 0) {
+                close_nointr_nofail(copy);
+                return r;
+        }
+
+        return copy;
+}
+
+bool fdset_contains(FDSet *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
+}
+
+int fdset_remove(FDSet *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
+}
+
+int fdset_new_fill(FDSet **_s) {
+        DIR *d;
+        struct dirent *de;
+        int r = 0;
+        FDSet *s;
+
+        assert(_s);
+
+        /* Creates an fdsets and fills in all currently open file
+         * descriptors. */
+
+        if (!(d = opendir("/proc/self/fd")))
+                return -errno;
+
+        if (!(s = fdset_new())) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        while ((de = readdir(d))) {
+                int fd = -1;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                if ((r = safe_atoi(de->d_name, &fd)) < 0)
+                        goto finish;
+
+                if (fd < 3)
+                        continue;
+
+                if (fd == dirfd(d))
+                        continue;
+
+                if ((r = fdset_put(s, fd)) < 0)
+                        goto finish;
+        }
+
+        r = 0;
+        *_s = s;
+        s = NULL;
+
+finish:
+        closedir(d);
+
+        /* We won't close the fds here! */
+        if (s)
+                set_free(MAKE_SET(s));
+
+        return r;
+
+}
+
+int fdset_cloexec(FDSet *fds, bool b) {
+        Iterator i;
+        void *p;
+        int r;
+
+        assert(fds);
+
+        SET_FOREACH(p, MAKE_SET(fds), i)
+                if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
+                        return r;
+
+        return 0;
+}
diff --git a/src/fdset.h b/src/fdset.h
new file mode 100644
index 0000000..3483fc8
--- /dev/null
+++ b/src/fdset.h
@@ -0,0 +1,40 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foofdsethfoo
+#define foofdsethfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct FDSet FDSet;
+
+FDSet* fdset_new(void);
+void fdset_free(FDSet *s);
+
+int fdset_put(FDSet *s, int fd);
+int fdset_put_dup(FDSet *s, int fd);
+
+bool fdset_contains(FDSet *s, int fd);
+int fdset_remove(FDSet *s, int fd);
+
+int fdset_new_fill(FDSet **_s);
+
+int fdset_cloexec(FDSet *fds, bool b);
+
+#endif
diff --git a/src/hashmap.c b/src/hashmap.c
new file mode 100644
index 0000000..5a993b6
--- /dev/null
+++ b/src/hashmap.c
@@ -0,0 +1,543 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "hashmap.h"
+#include "macro.h"
+
+#define NBUCKETS 127
+
+struct hashmap_entry {
+        const void *key;
+        void *value;
+        struct hashmap_entry *bucket_next, *bucket_previous;
+        struct hashmap_entry *iterate_next, *iterate_previous;
+};
+
+struct Hashmap {
+        hash_func_t hash_func;
+        compare_func_t compare_func;
+
+        struct hashmap_entry *iterate_list_head, *iterate_list_tail;
+        unsigned n_entries;
+};
+
+#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap))))
+
+unsigned string_hash_func(const void *p) {
+        unsigned hash = 0;
+        const char *c;
+
+        for (c = p; *c; c++)
+                hash = 31 * hash + (unsigned) *c;
+
+        return hash;
+}
+
+int string_compare_func(const void *a, const void *b) {
+        return strcmp(a, b);
+}
+
+unsigned trivial_hash_func(const void *p) {
+        return PTR_TO_UINT(p);
+}
+
+int trivial_compare_func(const void *a, const void *b) {
+        return a < b ? -1 : (a > b ? 1 : 0);
+}
+
+Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) {
+        Hashmap *h;
+
+        if (!(h = malloc0(ALIGN(sizeof(Hashmap)) + NBUCKETS * ALIGN(sizeof(struct hashmap_entry*)))))
+                return NULL;
+
+        h->hash_func = hash_func ? hash_func : trivial_hash_func;
+        h->compare_func = compare_func ? compare_func : trivial_compare_func;
+
+        h->n_entries = 0;
+        h->iterate_list_head = h->iterate_list_tail = NULL;
+
+        return h;
+}
+
+int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) {
+        assert(h);
+
+        if (*h)
+                return 0;
+
+        if (!(*h = hashmap_new(hash_func, compare_func)))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
+        assert(h);
+        assert(e);
+
+        /* Insert into hash table */
+        e->bucket_next = BY_HASH(h)[hash];
+        e->bucket_previous = NULL;
+        if (BY_HASH(h)[hash])
+                BY_HASH(h)[hash]->bucket_previous = e;
+        BY_HASH(h)[hash] = e;
+
+        /* Insert into iteration list */
+        e->iterate_previous = h->iterate_list_tail;
+        e->iterate_next = NULL;
+        if (h->iterate_list_tail) {
+                assert(h->iterate_list_head);
+                h->iterate_list_tail->iterate_next = e;
+        } else {
+                assert(!h->iterate_list_head);
+                h->iterate_list_head = e;
+        }
+        h->iterate_list_tail = e;
+
+        h->n_entries++;
+        assert(h->n_entries >= 1);
+}
+
+static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
+        assert(h);
+        assert(e);
+
+        /* Remove from iteration list */
+        if (e->iterate_next)
+                e->iterate_next->iterate_previous = e->iterate_previous;
+        else
+                h->iterate_list_tail = e->iterate_previous;
+
+        if (e->iterate_previous)
+                e->iterate_previous->iterate_next = e->iterate_next;
+        else
+                h->iterate_list_head = e->iterate_next;
+
+        /* Remove from hash table bucket list */
+        if (e->bucket_next)
+                e->bucket_next->bucket_previous = e->bucket_previous;
+
+        if (e->bucket_previous)
+                e->bucket_previous->bucket_next = e->bucket_next;
+        else
+                BY_HASH(h)[hash] = e->bucket_next;
+
+        assert(h->n_entries >= 1);
+        h->n_entries--;
+}
+
+static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
+        unsigned hash;
+
+        assert(h);
+        assert(e);
+
+        hash = h->hash_func(e->key) % NBUCKETS;
+
+        unlink_entry(h, e, hash);
+        free(e);
+}
+
+void hashmap_free(Hashmap*h) {
+
+        if (!h)
+                return;
+
+        hashmap_clear(h);
+
+        free(h);
+}
+
+void hashmap_clear(Hashmap *h) {
+        if (!h)
+                return;
+
+        while (h->iterate_list_head)
+                remove_entry(h, h->iterate_list_head);
+}
+
+static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
+        struct hashmap_entry *e;
+        assert(h);
+        assert(hash < NBUCKETS);
+
+        for (e = BY_HASH(h)[hash]; e; e = e->bucket_next)
+                if (h->compare_func(e->key, key) == 0)
+                        return e;
+
+        return NULL;
+}
+
+int hashmap_put(Hashmap *h, const void *key, void *value) {
+        struct hashmap_entry *e;
+        unsigned hash;
+
+        assert(h);
+
+        hash = h->hash_func(key) % NBUCKETS;
+
+        if ((e = hash_scan(h, hash, key))) {
+
+                if (e->value == value)
+                        return 0;
+
+                return -EEXIST;
+        }
+
+        if (!(e = new(struct hashmap_entry, 1)))
+                return -ENOMEM;
+
+        e->key = key;
+        e->value = value;
+
+        link_entry(h, e, hash);
+
+        return 1;
+}
+
+int hashmap_replace(Hashmap *h, const void *key, void *value) {
+        struct hashmap_entry *e;
+        unsigned hash;
+
+        assert(h);
+
+        hash = h->hash_func(key) % NBUCKETS;
+
+        if ((e = hash_scan(h, hash, key))) {
+                e->key = key;
+                e->value = value;
+                return 0;
+        }
+
+        return hashmap_put(h, key, value);
+}
+
+void* hashmap_get(Hashmap *h, const void *key) {
+        unsigned hash;
+        struct hashmap_entry *e;
+
+        if (!h)
+                return NULL;
+
+        hash = h->hash_func(key) % NBUCKETS;
+
+        if (!(e = hash_scan(h, hash, key)))
+                return NULL;
+
+        return e->value;
+}
+
+void* hashmap_remove(Hashmap *h, const void *key) {
+        struct hashmap_entry *e;
+        unsigned hash;
+        void *data;
+
+        if (!h)
+                return NULL;
+
+        hash = h->hash_func(key) % NBUCKETS;
+
+        if (!(e = hash_scan(h, hash, key)))
+                return NULL;
+
+        data = e->value;
+        remove_entry(h, e);
+
+        return data;
+}
+
+int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
+        struct hashmap_entry *e;
+        unsigned old_hash, new_hash;
+
+        if (!h)
+                return -ENOENT;
+
+        old_hash = h->hash_func(old_key) % NBUCKETS;
+        if (!(e = hash_scan(h, old_hash, old_key)))
+                return -ENOENT;
+
+        new_hash = h->hash_func(new_key) % NBUCKETS;
+        if (hash_scan(h, new_hash, new_key))
+                return -EEXIST;
+
+        unlink_entry(h, e, old_hash);
+
+        e->key = new_key;
+        e->value = value;
+
+        link_entry(h, e, new_hash);
+
+        return 0;
+}
+
+void* hashmap_remove_value(Hashmap *h, const void *key, void *value) {
+        struct hashmap_entry *e;
+        unsigned hash;
+
+        if (!h)
+                return NULL;
+
+        hash = h->hash_func(key) % NBUCKETS;
+
+        if (!(e = hash_scan(h, hash, key)))
+                return NULL;
+
+        if (e->value != value)
+                return NULL;
+
+        remove_entry(h, e);
+
+        return value;
+}
+
+void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
+        struct hashmap_entry *e;
+
+        assert(i);
+
+        if (!h)
+                goto at_end;
+
+        if (*i == ITERATOR_LAST)
+                goto at_end;
+
+        if (*i == ITERATOR_FIRST && !h->iterate_list_head)
+                goto at_end;
+
+        e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i;
+
+        if (e->iterate_next)
+                *i = (Iterator) e->iterate_next;
+        else
+                *i = ITERATOR_LAST;
+
+        if (key)
+                *key = e->key;
+
+        return e->value;
+
+at_end:
+        *i = ITERATOR_LAST;
+
+        if (key)
+                *key = NULL;
+
+        return NULL;
+}
+
+void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) {
+        struct hashmap_entry *e;
+
+        assert(i);
+
+        if (!h)
+                goto at_beginning;
+
+        if (*i == ITERATOR_FIRST)
+                goto at_beginning;
+
+        if (*i == ITERATOR_LAST && !h->iterate_list_tail)
+                goto at_beginning;
+
+        e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i;
+
+        if (e->iterate_previous)
+                *i = (Iterator) e->iterate_previous;
+        else
+                *i = ITERATOR_FIRST;
+
+        if (key)
+                *key = e->key;
+
+        return e->value;
+
+at_beginning:
+        *i = ITERATOR_FIRST;
+
+        if (key)
+                *key = NULL;
+
+        return NULL;
+}
+
+void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) {
+        unsigned hash;
+        struct hashmap_entry *e;
+
+        if (!h)
+                return NULL;
+
+        hash = h->hash_func(key) % NBUCKETS;
+
+        if (!(e = hash_scan(h, hash, key)))
+                return NULL;
+
+        *i = (Iterator) e;
+
+        return e->value;
+}
+
+void* hashmap_first(Hashmap *h) {
+
+        if (!h)
+                return NULL;
+
+        if (!h->iterate_list_head)
+                return NULL;
+
+        return h->iterate_list_head->value;
+}
+
+void* hashmap_last(Hashmap *h) {
+
+        if (!h)
+                return NULL;
+
+        if (!h->iterate_list_tail)
+                return NULL;
+
+        return h->iterate_list_tail->value;
+}
+
+void* hashmap_steal_first(Hashmap *h) {
+        void *data;
+
+        if (!h)
+                return NULL;
+
+        if (!h->iterate_list_head)
+                return NULL;
+
+        data = h->iterate_list_head->value;
+        remove_entry(h, h->iterate_list_head);
+
+        return data;
+}
+
+unsigned hashmap_size(Hashmap *h) {
+
+        if (!h)
+                return 0;
+
+        return h->n_entries;
+}
+
+bool hashmap_isempty(Hashmap *h) {
+
+        if (!h)
+                return true;
+
+        return h->n_entries == 0;
+}
+
+int hashmap_merge(Hashmap *h, Hashmap *other) {
+        struct hashmap_entry *e;
+
+        assert(h);
+
+        if (!other)
+                return 0;
+
+        for (e = other->iterate_list_head; e; e = e->iterate_next) {
+                int r;
+
+                if ((r = hashmap_put(h, e->key, e->value)) < 0)
+                        if (r != -EEXIST)
+                                return r;
+        }
+
+        return 0;
+}
+
+void hashmap_move(Hashmap *h, Hashmap *other) {
+        struct hashmap_entry *e, *n;
+
+        assert(h);
+
+        /* The same as hashmap_merge(), but every new item from other
+         * is moved to h. This function is guaranteed to succeed. */
+
+        if (!other)
+                return;
+
+        for (e = other->iterate_list_head; e; e = n) {
+                unsigned h_hash, other_hash;
+
+                n = e->iterate_next;
+
+                h_hash = h->hash_func(e->key) % NBUCKETS;
+
+                if (hash_scan(h, h_hash, e->key))
+                        continue;
+
+                other_hash = other->hash_func(e->key) % NBUCKETS;
+
+                unlink_entry(other, e, other_hash);
+                link_entry(h, e, h_hash);
+        }
+}
+
+int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
+        unsigned h_hash, other_hash;
+        struct hashmap_entry *e;
+
+        if (!other)
+                return 0;
+
+        assert(h);
+
+        h_hash = h->hash_func(key) % NBUCKETS;
+        if (hash_scan(h, h_hash, key))
+                return -EEXIST;
+
+        other_hash = other->hash_func(key) % NBUCKETS;
+        if (!(e = hash_scan(other, other_hash, key)))
+                return -ENOENT;
+
+        unlink_entry(other, e, other_hash);
+        link_entry(h, e, h_hash);
+
+        return 0;
+}
+
+Hashmap *hashmap_copy(Hashmap *h) {
+        Hashmap *copy;
+
+        assert(h);
+
+        if (!(copy = hashmap_new(h->hash_func, h->compare_func)))
+                return NULL;
+
+        if (hashmap_merge(copy, h) < 0) {
+                hashmap_free(copy);
+                return NULL;
+        }
+
+        return copy;
+}
diff --git a/src/hashmap.h b/src/hashmap.h
new file mode 100644
index 0000000..3ff3efe
--- /dev/null
+++ b/src/hashmap.h
@@ -0,0 +1,85 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foohashmaphfoo
+#define foohashmaphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+/* Pretty straightforward hash table implementation. As a minor
+ * optimization a NULL hashmap object will be treated as empty hashmap
+ * for all read operations. That way it is not necessary to
+ * instantiate an object for each Hashmap use. */
+
+typedef struct Hashmap Hashmap;
+typedef struct _IteratorStruct _IteratorStruct;
+typedef _IteratorStruct* Iterator;
+
+#define ITERATOR_FIRST ((Iterator) 0)
+#define ITERATOR_LAST ((Iterator) -1)
+
+typedef unsigned (*hash_func_t)(const void *p);
+typedef int (*compare_func_t)(const void *a, const void *b);
+
+unsigned string_hash_func(const void *p);
+int string_compare_func(const void *a, const void *b);
+
+unsigned trivial_hash_func(const void *p);
+int trivial_compare_func(const void *a, const void *b);
+
+Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
+void hashmap_free(Hashmap *h);
+Hashmap *hashmap_copy(Hashmap *h);
+int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
+
+int hashmap_put(Hashmap *h, const void *key, void *value);
+int hashmap_replace(Hashmap *h, const void *key, void *value);
+void* hashmap_get(Hashmap *h, const void *key);
+void* hashmap_remove(Hashmap *h, const void *key);
+void* hashmap_remove_value(Hashmap *h, const void *key, void *value);
+int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
+
+int hashmap_merge(Hashmap *h, Hashmap *other);
+void hashmap_move(Hashmap *h, Hashmap *other);
+int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key);
+
+unsigned hashmap_size(Hashmap *h);
+bool hashmap_isempty(Hashmap *h);
+
+void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key);
+void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key);
+void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i);
+
+void hashmap_clear(Hashmap *h);
+void *hashmap_steal_first(Hashmap *h);
+void* hashmap_first(Hashmap *h);
+void* hashmap_last(Hashmap *h);
+
+#define HASHMAP_FOREACH(e, h, i) \
+        for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL))
+
+#define HASHMAP_FOREACH_KEY(e, k, h, i) \
+        for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k)))
+
+#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \
+        for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL))
+
+#endif
diff --git a/src/hostname-setup.c b/src/hostname-setup.c
new file mode 100644
index 0000000..3b988d4
--- /dev/null
+++ b/src/hostname-setup.c
@@ -0,0 +1,168 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "hostname-setup.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+
+#define LINE_MAX 4096
+
+#if defined(TARGET_FEDORA)
+#define FILENAME "/etc/sysconfig/network"
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
+#define FILENAME "/etc/HOSTNAME"
+#elif defined(TARGET_DEBIAN)
+#define FILENAME "/etc/hostname"
+#elif defined(TARGET_ARCH)
+#define FILENAME "/etc/rc.conf"
+#elif defined(TARGET_GENTOO)
+#define FILENAME "/etc/conf.d/hostname"
+#endif
+
+static char* strip_bad_chars(char *s) {
+        char *p, *d;
+
+        for (p = s, d = s; *p; p++)
+                if ((*p >= 'a' && *p <= 'z') ||
+                    (*p >= 'A' && *p <= 'Z') ||
+                    (*p >= '0' && *p <= '9') ||
+                    *p == '-' ||
+                    *p == '_')
+                        *(d++) = *p;
+
+        *d = 0;
+
+        return s;
+}
+
+static int read_hostname(char **hn) {
+
+#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO)
+        int r;
+        FILE *f;
+
+        assert(hn);
+
+        if (!(f = fopen(FILENAME, "re")))
+                return -errno;
+
+        for (;;) {
+                char line[LINE_MAX];
+                char *s, *k;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                break;
+
+                        r = -errno;
+                        goto finish;
+                }
+
+                s = strstrip(line);
+
+                if (!startswith_no_case(s, "HOSTNAME="))
+                        continue;
+
+                if (!(k = strdup(s+9))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                strip_bad_chars(k);
+
+                if (k[0] == 0) {
+                        free(k);
+                        r = -ENOENT;
+                        goto finish;
+                }
+
+                *hn = k;
+                break;
+        }
+
+        r = 0;
+
+finish:
+        fclose(f);
+        return r;
+
+#elif defined(TARGET_SUSE) || defined(TARGET_DEBIAN) || defined(TARGET_SLACKWARE)
+        int r;
+        char *s, *k;
+
+        assert(hn);
+
+        if ((r = read_one_line_file(FILENAME, &s)) < 0)
+                return r;
+
+        k = strdup(strstrip(s));
+        free(s);
+
+        if (!k)
+                return -ENOMEM;
+
+        strip_bad_chars(k);
+
+        if (k[0] == 0) {
+                free(k);
+                return -ENOENT;
+        }
+
+        *hn = k;
+
+#else
+#warning "Don't know how to read the hostname"
+
+        return -ENOENT;
+#endif
+
+        return 0;
+}
+
+int hostname_setup(void) {
+        int r;
+        char *hn;
+
+        if ((r = read_hostname(&hn)) < 0) {
+                if (r != -ENOENT)
+                        log_warning("Failed to read configured hostname: %s", strerror(-r));
+
+                return r;
+        }
+
+        r = sethostname(hn, strlen(hn)) < 0 ? -errno : 0;
+
+        if (r < 0)
+                log_warning("Failed to set hostname to <%s>: %s", hn, strerror(-r));
+        else
+                log_info("Set hostname to <%s>.", hn);
+
+        free(hn);
+
+        return r;
+}
diff --git a/src/hostname-setup.h b/src/hostname-setup.h
new file mode 100644
index 0000000..18a406a
--- /dev/null
+++ b/src/hostname-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foohostnamesetuphfoo
+#define foohostnamesetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int hostname_setup(void);
+
+#endif
diff --git a/src/initctl.c b/src/initctl.c
new file mode 100644
index 0000000..9d8ecee
--- /dev/null
+++ b/src/initctl.c
@@ -0,0 +1,397 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include <dbus/dbus.h>
+
+#include "util.h"
+#include "log.h"
+#include "list.h"
+#include "initreq.h"
+#include "manager.h"
+#include "sd-daemon.h"
+
+#define SERVER_FD_MAX 16
+#define TIMEOUT ((int) (10*MSEC_PER_SEC))
+
+typedef struct Fifo Fifo;
+
+typedef struct Server {
+        int epoll_fd;
+
+        LIST_HEAD(Fifo, fifos);
+        unsigned n_fifos;
+
+        DBusConnection *bus;
+} Server;
+
+struct Fifo {
+        Server *server;
+
+        int fd;
+
+        struct init_request buffer;
+        size_t bytes_read;
+
+        LIST_FIELDS(Fifo, fifo);
+};
+
+static const char *translate_runlevel(int runlevel) {
+        static const struct {
+                const int runlevel;
+                const char *special;
+        } table[] = {
+                { '0', SPECIAL_RUNLEVEL0_TARGET },
+                { '1', SPECIAL_RUNLEVEL1_TARGET },
+                { 's', SPECIAL_RUNLEVEL1_TARGET },
+                { 'S', SPECIAL_RUNLEVEL1_TARGET },
+                { '2', SPECIAL_RUNLEVEL2_TARGET },
+                { '3', SPECIAL_RUNLEVEL3_TARGET },
+                { '4', SPECIAL_RUNLEVEL4_TARGET },
+                { '5', SPECIAL_RUNLEVEL5_TARGET },
+                { '6', SPECIAL_RUNLEVEL6_TARGET },
+        };
+
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (table[i].runlevel == runlevel)
+                        return table[i].special;
+
+        return NULL;
+}
+
+static void change_runlevel(Server *s, int runlevel) {
+        const char *target;
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        const char *path, *replace = "isolate";
+
+        assert(s);
+
+        dbus_error_init(&error);
+
+        if (!(target = translate_runlevel(runlevel))) {
+                log_warning("Got request for unknown runlevel %c, ignoring.", runlevel);
+                goto finish;
+        }
+
+        log_debug("Running request %s", target);
+
+        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "LoadUnit"))) {
+                log_error("Could not allocate message.");
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &target,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not attach group information to signal message.");
+                goto finish;
+        }
+
+        if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
+                log_error("Failed to get unit path: %s", error.message);
+                goto finish;
+        }
+
+        if (!dbus_message_get_args(reply, &error,
+                                   DBUS_TYPE_OBJECT_PATH, &path,
+                                   DBUS_TYPE_INVALID)) {
+                log_error("Failed to parse unit path: %s", error.message);
+                goto finish;
+        }
+
+        dbus_message_unref(m);
+        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Unit", "Start"))) {
+                log_error("Could not allocate message.");
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &replace,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not attach group information to signal message.");
+                goto finish;
+        }
+
+        dbus_message_unref(reply);
+        if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
+                log_error("Failed to start unit: %s", error.message);
+                goto finish;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+}
+
+static void request_process(Server *s, const struct init_request *req) {
+        assert(s);
+        assert(req);
+
+        if (req->magic != INIT_MAGIC) {
+                log_error("Got initctl request with invalid magic. Ignoring.");
+                return;
+        }
+
+        switch (req->cmd) {
+
+        case INIT_CMD_RUNLVL:
+                if (!isprint(req->runlevel))
+                        log_error("Got invalid runlevel. Ignoring.");
+                else
+                        change_runlevel(s, req->runlevel);
+                return;
+
+        case INIT_CMD_POWERFAIL:
+        case INIT_CMD_POWERFAILNOW:
+        case INIT_CMD_POWEROK:
+                log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!");
+                return;
+
+        case INIT_CMD_CHANGECONS:
+                log_warning("Received console change initctl request. This is not implemented in systemd.");
+                return;
+
+        case INIT_CMD_SETENV:
+        case INIT_CMD_UNSETENV:
+                log_warning("Received environment initctl request. This is not implemented in systemd.");
+                return;
+
+        default:
+                log_warning("Received unknown initctl request. Ignoring.");
+                return;
+        }
+}
+
+static int fifo_process(Fifo *f) {
+        ssize_t l;
+
+        assert(f);
+
+        errno = EIO;
+        if ((l = read(f->fd, ((uint8_t*) &f->buffer) + f->bytes_read, sizeof(f->buffer) - f->bytes_read)) <= 0) {
+
+                if (errno == EAGAIN)
+                        return 0;
+
+                log_warning("Failed to read from fifo: %s", strerror(errno));
+                return -1;
+        }
+
+        f->bytes_read += l;
+        assert(f->bytes_read <= sizeof(f->buffer));
+
+        if (f->bytes_read == sizeof(f->buffer)) {
+                request_process(f->server, &f->buffer);
+                f->bytes_read = 0;
+        }
+
+        return 0;
+}
+
+static void fifo_free(Fifo *f) {
+        assert(f);
+
+        if (f->server) {
+                assert(f->server->n_fifos > 0);
+                f->server->n_fifos--;
+                LIST_REMOVE(Fifo, fifo, f->server->fifos, f);
+        }
+
+        if (f->fd >= 0) {
+                if (f->server)
+                        epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL);
+
+                close_nointr_nofail(f->fd);
+        }
+
+        free(f);
+}
+
+static void server_done(Server *s) {
+        assert(s);
+
+        while (s->fifos)
+                fifo_free(s->fifos);
+
+        if (s->epoll_fd >= 0)
+                close_nointr_nofail(s->epoll_fd);
+
+        if (s->bus)
+                dbus_connection_unref(s->bus);
+}
+
+static int server_init(Server *s, unsigned n_sockets) {
+        int r;
+        unsigned i;
+        DBusError error;
+
+        assert(s);
+        assert(n_sockets > 0);
+
+        dbus_error_init(&error);
+
+        zero(*s);
+
+        if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
+                r = -errno;
+                log_error("Failed to create epoll object: %s", strerror(errno));
+                goto fail;
+        }
+
+        for (i = 0; i < n_sockets; i++) {
+                struct epoll_event ev;
+                Fifo *f;
+
+                if (!(f = new0(Fifo, 1))) {
+                        r = -ENOMEM;
+                        log_error("Failed to create fifo object: %s", strerror(errno));
+                        goto fail;
+                }
+
+                f->fd = -1;
+
+                zero(ev);
+                ev.events = EPOLLIN;
+                ev.data.ptr = f;
+                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) {
+                        r = -errno;
+                        fifo_free(f);
+                        log_error("Failed to add fifo fd to epoll object: %s", strerror(errno));
+                        goto fail;
+                }
+
+                f->fd = SD_LISTEN_FDS_START+i;
+                LIST_PREPEND(Fifo, fifo, s->fifos, f);
+                f->server = s;
+                s->n_fifos ++;
+        }
+
+        if (!(s->bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+                log_error("Failed to get D-Bus connection: %s", error.message);
+                goto fail;
+        }
+
+        return 0;
+
+fail:
+        server_done(s);
+
+        dbus_error_free(&error);
+        return r;
+}
+
+static int process_event(Server *s, struct epoll_event *ev) {
+        int r;
+        Fifo *f;
+
+        assert(s);
+
+        if (!(ev->events & EPOLLIN)) {
+                log_info("Got invalid event from epoll. (3)");
+                return -EIO;
+        }
+
+        f = (Fifo*) ev->data.ptr;
+
+        if ((r = fifo_process(f)) < 0) {
+                log_info("Got error on fifo: %s", strerror(-r));
+                fifo_free(f);
+                return r;
+        }
+
+        return 0;
+}
+
+int main(int argc, char *argv[]) {
+        Server server;
+        int r = 3, n;
+
+        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        log_parse_environment();
+
+        log_info("systemd-initctl running as pid %llu", (unsigned long long) getpid());
+
+        if ((n = sd_listen_fds(true)) < 0) {
+                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
+                return 1;
+        }
+
+        if (n <= 0 || n > SERVER_FD_MAX) {
+                log_error("No or too many file descriptors passed.");
+                return 2;
+        }
+
+        if (server_init(&server, (unsigned) n) < 0)
+                return 2;
+
+        for (;;) {
+                struct epoll_event event;
+                int k;
+
+                if ((k = epoll_wait(server.epoll_fd,
+                                    &event, 1,
+                                    TIMEOUT)) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        log_error("epoll_wait() failed: %s", strerror(errno));
+                        goto fail;
+                }
+
+                if (k <= 0)
+                        break;
+
+                if ((k = process_event(&server, &event)) < 0)
+                        goto fail;
+        }
+        r = 0;
+
+fail:
+        server_done(&server);
+
+        log_info("systemd-initctl stopped as pid %llu", (unsigned long long) getpid());
+
+        dbus_shutdown();
+
+        return r;
+}
diff --git a/src/initreq.h b/src/initreq.h
new file mode 100644
index 0000000..6f6547b
--- /dev/null
+++ b/src/initreq.h
@@ -0,0 +1,77 @@
+/*
+ * initreq.h	Interface to talk to init through /dev/initctl.
+ *
+ *		Copyright (C) 1995-2004 Miquel van Smoorenburg
+ *
+ *		This library 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 of the License, or (at your option) any later version.
+ *
+ * Version:     @(#)initreq.h  1.28  31-Mar-2004 MvS
+ *
+ */
+#ifndef _INITREQ_H
+#define _INITREQ_H
+
+#include <sys/param.h>
+
+#if defined(__FreeBSD_kernel__)
+#  define INIT_FIFO  "/etc/.initctl"
+#else
+#  define INIT_FIFO  "/dev/initctl"
+#endif
+
+#define INIT_MAGIC 0x03091969
+#define INIT_CMD_START		0
+#define INIT_CMD_RUNLVL		1
+#define INIT_CMD_POWERFAIL	2
+#define INIT_CMD_POWERFAILNOW	3
+#define INIT_CMD_POWEROK	4
+#define INIT_CMD_BSD		5
+#define INIT_CMD_SETENV		6
+#define INIT_CMD_UNSETENV	7
+
+#define INIT_CMD_CHANGECONS	12345
+
+#ifdef MAXHOSTNAMELEN
+#  define INITRQ_HLEN	MAXHOSTNAMELEN
+#else
+#  define INITRQ_HLEN	64
+#endif
+
+/*
+ *	This is what BSD 4.4 uses when talking to init.
+ *	Linux doesn't use this right now.
+ */
+struct init_request_bsd {
+	char	gen_id[8];		/* Beats me.. telnetd uses "fe" */
+	char	tty_id[16];		/* Tty name minus /dev/tty      */
+	char	host[INITRQ_HLEN];	/* Hostname                     */
+	char	term_type[16];		/* Terminal type                */
+	int	signal;			/* Signal to send               */
+	int	pid;			/* Process to send to           */
+	char	exec_name[128];	        /* Program to execute           */
+	char	reserved[128];		/* For future expansion.        */
+};
+
+
+/*
+ *	Because of legacy interfaces, "runlevel" and "sleeptime"
+ *	aren't in a seperate struct in the union.
+ *
+ *	The weird sizes are because init expects the whole
+ *	struct to be 384 bytes.
+ */
+struct init_request {
+	int	magic;			/* Magic number                 */
+	int	cmd;			/* What kind of request         */
+	int	runlevel;		/* Runlevel to change to        */
+	int	sleeptime;		/* Time between TERM and KILL   */
+	union {
+		struct init_request_bsd	bsd;
+		char			data[368];
+	} i;
+};
+
+#endif
diff --git a/src/ioprio.h b/src/ioprio.h
new file mode 100644
index 0000000..9800fc2
--- /dev/null
+++ b/src/ioprio.h
@@ -0,0 +1,57 @@
+#ifndef IOPRIO_H
+#define IOPRIO_H
+
+/* This is minimal version of Linux' linux/ioprio.h header file, which
+ * is licensed GPL2 */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+/*
+ * Gives us 8 prio classes with 13-bits of data for each class
+ */
+#define IOPRIO_BITS             (16)
+#define IOPRIO_CLASS_SHIFT      (13)
+#define IOPRIO_PRIO_MASK        ((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask)  ((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data)  (((class) << IOPRIO_CLASS_SHIFT) | data)
+
+#define ioprio_valid(mask)      (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE)
+
+/*
+ * These are the io priority groups as implemented by CFQ. RT is the realtime
+ * class, it always gets premium service. BE is the best-effort scheduling
+ * class, the default for any process. IDLE is the idle scheduling class, it
+ * is only served when no one else is using the disk.
+ */
+enum {
+        IOPRIO_CLASS_NONE,
+        IOPRIO_CLASS_RT,
+        IOPRIO_CLASS_BE,
+        IOPRIO_CLASS_IDLE,
+};
+
+/*
+ * 8 best effort priority levels are supported
+ */
+#define IOPRIO_BE_NR    (8)
+
+enum {
+        IOPRIO_WHO_PROCESS = 1,
+        IOPRIO_WHO_PGRP,
+        IOPRIO_WHO_USER,
+};
+
+static inline int ioprio_set(int which, int who, int ioprio)
+{
+        return syscall(__NR_ioprio_set, which, who, ioprio);
+}
+
+static inline int ioprio_get(int which, int who)
+{
+        return syscall(__NR_ioprio_get, which, who);
+}
+
+#endif
diff --git a/src/job.c b/src/job.c
new file mode 100644
index 0000000..887de92
--- /dev/null
+++ b/src/job.c
@@ -0,0 +1,589 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <errno.h>
+
+#include "set.h"
+#include "unit.h"
+#include "macro.h"
+#include "strv.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "log.h"
+#include "dbus-job.h"
+
+Job* job_new(Manager *m, JobType type, Unit *unit) {
+        Job *j;
+
+        assert(m);
+        assert(type < _JOB_TYPE_MAX);
+        assert(unit);
+
+        if (!(j = new0(Job, 1)))
+                return NULL;
+
+        j->manager = m;
+        j->id = m->current_job_id++;
+        j->type = type;
+        j->unit = unit;
+
+        /* We don't link it here, that's what job_dependency() is for */
+
+        return j;
+}
+
+void job_free(Job *j) {
+        assert(j);
+
+        /* Detach from next 'bigger' objects */
+        if (j->installed) {
+                bus_job_send_removed_signal(j);
+
+                if (j->unit->meta.job == j) {
+                        j->unit->meta.job = NULL;
+                        unit_add_to_gc_queue(j->unit);
+                }
+
+                hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
+                j->installed = false;
+        }
+
+        /* Detach from next 'smaller' objects */
+        manager_transaction_unlink_job(j->manager, j, true);
+
+        if (j->in_run_queue)
+                LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
+
+        if (j->in_dbus_queue)
+                LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
+
+        free(j);
+}
+
+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
+        JobDependency *l;
+
+        assert(object);
+
+        /* Adds a new job link, which encodes that the 'subject' job
+         * needs the 'object' job in some way. If 'subject' is NULL
+         * this means the 'anchor' job (i.e. the one the user
+         * explcitily asked for) is the requester. */
+
+        if (!(l = new0(JobDependency, 1)))
+                return NULL;
+
+        l->subject = subject;
+        l->object = object;
+        l->matters = matters;
+
+        if (subject)
+                LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
+        else
+                LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l);
+
+        LIST_PREPEND(JobDependency, object, object->object_list, l);
+
+        return l;
+}
+
+void job_dependency_free(JobDependency *l) {
+        assert(l);
+
+        if (l->subject)
+                LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
+        else
+                LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l);
+
+        LIST_REMOVE(JobDependency, object, l->object->object_list, l);
+
+        free(l);
+}
+
+void job_dependency_delete(Job *subject, Job *object, bool *matters) {
+        JobDependency *l;
+
+        assert(object);
+
+        LIST_FOREACH(object, l, object->object_list) {
+                assert(l->object == object);
+
+                if (l->subject == subject)
+                        break;
+        }
+
+        if (!l) {
+                if (matters)
+                        *matters = false;
+                return;
+        }
+
+        if (matters)
+                *matters = l->matters;
+
+        job_dependency_free(l);
+}
+
+void job_dump(Job *j, FILE*f, const char *prefix) {
+
+
+        assert(j);
+        assert(f);
+
+        fprintf(f,
+                "%s-> Job %u:\n"
+                "%s\tAction: %s -> %s\n"
+                "%s\tState: %s\n"
+                "%s\tForced: %s\n",
+                prefix, j->id,
+                prefix, j->unit->meta.id, job_type_to_string(j->type),
+                prefix, job_state_to_string(j->state),
+                prefix, yes_no(j->override));
+}
+
+bool job_is_anchor(Job *j) {
+        JobDependency *l;
+
+        assert(j);
+
+        LIST_FOREACH(object, l, j->object_list)
+                if (!l->subject)
+                        return true;
+
+        return false;
+}
+
+static bool types_match(JobType a, JobType b, JobType c, JobType d) {
+        return
+                (a == c && b == d) ||
+                (a == d && b == c);
+}
+
+int job_type_merge(JobType *a, JobType b) {
+        if (*a == b)
+                return 0;
+
+        /* Merging is associative! a merged with b merged with c is
+         * the same as a merged with c merged with b. */
+
+        /* Mergeability is transitive! if a can be merged with b and b
+         * with c then a also with c */
+
+        /* Also, if a merged with b cannot be merged with c, then
+         * either a or b cannot be merged with c either */
+
+        if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE))
+                *a = JOB_START;
+        else if (types_match(*a, b, JOB_START, JOB_RELOAD) ||
+                 types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) ||
+                 types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) ||
+                 types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START))
+                *a = JOB_RELOAD_OR_START;
+        else if (types_match(*a, b, JOB_START, JOB_RESTART) ||
+                 types_match(*a, b, JOB_START, JOB_TRY_RESTART) ||
+                 types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) ||
+                 types_match(*a, b, JOB_RELOAD, JOB_RESTART) ||
+                 types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) ||
+                 types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) ||
+                 types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART))
+                *a = JOB_RESTART;
+        else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD))
+                *a = JOB_RELOAD;
+        else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) ||
+                 types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART))
+                *a = JOB_TRY_RESTART;
+        else
+                return -EEXIST;
+
+        return 0;
+}
+
+bool job_type_is_mergeable(JobType a, JobType b) {
+        return job_type_merge(&a, b) >= 0;
+}
+
+bool job_type_is_superset(JobType a, JobType b) {
+
+        /* Checks whether operation a is a "superset" of b in its
+         * actions */
+
+        if (a == b)
+                return true;
+
+        switch (a) {
+                case JOB_START:
+                        return b == JOB_VERIFY_ACTIVE;
+
+                case JOB_RELOAD:
+                        return
+                                b == JOB_VERIFY_ACTIVE;
+
+                case JOB_RELOAD_OR_START:
+                        return
+                                b == JOB_RELOAD ||
+                                b == JOB_START ||
+                                b == JOB_VERIFY_ACTIVE;
+
+                case JOB_RESTART:
+                        return
+                                b == JOB_START ||
+                                b == JOB_VERIFY_ACTIVE ||
+                                b == JOB_RELOAD ||
+                                b == JOB_RELOAD_OR_START ||
+                                b == JOB_TRY_RESTART;
+
+                case JOB_TRY_RESTART:
+                        return
+                                b == JOB_VERIFY_ACTIVE ||
+                                b == JOB_RELOAD;
+                default:
+                        return false;
+
+        }
+}
+
+bool job_type_is_conflicting(JobType a, JobType b) {
+        assert(a >= 0 && a < _JOB_TYPE_MAX);
+        assert(b >= 0 && b < _JOB_TYPE_MAX);
+
+        return (a == JOB_STOP) != (b == JOB_STOP);
+}
+
+bool job_type_is_redundant(JobType a, UnitActiveState b) {
+        switch (a) {
+
+        case JOB_START:
+                return
+                        b == UNIT_ACTIVE ||
+                        b == UNIT_ACTIVE_RELOADING;
+
+        case JOB_STOP:
+                return
+                        b == UNIT_INACTIVE;
+
+        case JOB_VERIFY_ACTIVE:
+                return
+                        b == UNIT_ACTIVE ||
+                        b == UNIT_ACTIVE_RELOADING;
+
+        case JOB_RELOAD:
+                return
+                        b == UNIT_ACTIVE_RELOADING;
+
+        case JOB_RELOAD_OR_START:
+                return
+                        b == UNIT_ACTIVATING ||
+                        b == UNIT_ACTIVE_RELOADING;
+
+        case JOB_RESTART:
+                return
+                        b == UNIT_ACTIVATING;
+
+        case JOB_TRY_RESTART:
+                return
+                        b == UNIT_ACTIVATING;
+
+        default:
+                assert_not_reached("Invalid job type");
+        }
+}
+
+bool job_is_runnable(Job *j) {
+        Iterator i;
+        Unit *other;
+
+        assert(j);
+        assert(j->installed);
+
+        /* Checks whether there is any job running for the units this
+         * job needs to be running after (in the case of a 'positive'
+         * job type) or before (in the case of a 'negative' job type
+         * . */
+
+        if (j->type == JOB_START ||
+            j->type == JOB_VERIFY_ACTIVE ||
+            j->type == JOB_RELOAD ||
+            j->type == JOB_RELOAD_OR_START) {
+
+                /* Immediate result is that the job is or might be
+                 * started. In this case lets wait for the
+                 * dependencies, regardless whether they are
+                 * starting or stopping something. */
+
+                SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i)
+                        if (other->meta.job)
+                                return false;
+        }
+
+        /* Also, if something else is being stopped and we should
+         * change state after it, then lets wait. */
+
+        SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i)
+                if (other->meta.job &&
+                    (other->meta.job->type == JOB_STOP ||
+                     other->meta.job->type == JOB_RESTART ||
+                     other->meta.job->type == JOB_TRY_RESTART))
+                        return false;
+
+        /* This means that for a service a and a service b where b
+         * shall be started after a:
+         *
+         *  start a + start b → 1st step start a, 2nd step start b
+         *  start a + stop b  → 1st step stop b,  2nd step start a
+         *  stop a  + start b → 1st step stop a,  2nd step start b
+         *  stop a  + stop b  → 1st step stop b,  2nd step stop a
+         *
+         *  This has the side effect that restarts are properly
+         *  synchronized too. */
+
+        return true;
+}
+
+int job_run_and_invalidate(Job *j) {
+        int r;
+
+        assert(j);
+        assert(j->installed);
+
+        if (j->in_run_queue) {
+                LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
+                j->in_run_queue = false;
+        }
+
+        if (j->state != JOB_WAITING)
+                return 0;
+
+        if (!job_is_runnable(j))
+                return -EAGAIN;
+
+        j->state = JOB_RUNNING;
+        job_add_to_dbus_queue(j);
+
+        switch (j->type) {
+
+                case JOB_START:
+                        r = unit_start(j->unit);
+                        if (r == -EBADR)
+                                r = 0;
+                        break;
+
+                case JOB_VERIFY_ACTIVE: {
+                        UnitActiveState t = unit_active_state(j->unit);
+                        if (UNIT_IS_ACTIVE_OR_RELOADING(t))
+                                r = -EALREADY;
+                        else if (t == UNIT_ACTIVATING)
+                                r = -EAGAIN;
+                        else
+                                r = -ENOEXEC;
+                        break;
+                }
+
+                case JOB_STOP:
+                        r = unit_stop(j->unit);
+                        break;
+
+                case JOB_RELOAD:
+                        r = unit_reload(j->unit);
+                        break;
+
+                case JOB_RELOAD_OR_START:
+                        if (unit_active_state(j->unit) == UNIT_ACTIVE)
+                                r = unit_reload(j->unit);
+                        else
+                                r = unit_start(j->unit);
+                        break;
+
+                case JOB_RESTART: {
+                        UnitActiveState t = unit_active_state(j->unit);
+                        if (t == UNIT_INACTIVE || t == UNIT_ACTIVATING) {
+                                j->type = JOB_START;
+                                r = unit_start(j->unit);
+                        } else
+                                r = unit_stop(j->unit);
+                        break;
+                }
+
+                case JOB_TRY_RESTART: {
+                        UnitActiveState t = unit_active_state(j->unit);
+                        if (t == UNIT_INACTIVE || t == UNIT_DEACTIVATING)
+                                r = -ENOEXEC;
+                        else if (t == UNIT_ACTIVATING) {
+                                j->type = JOB_START;
+                                r = unit_start(j->unit);
+                        } else
+                                r = unit_stop(j->unit);
+                        break;
+                }
+
+                default:
+                        assert_not_reached("Unknown job type");
+        }
+
+        if (r == -EALREADY)
+                r = job_finish_and_invalidate(j, true);
+        else if (r == -EAGAIN) {
+                j->state = JOB_WAITING;
+                return -EAGAIN;
+        } else if (r < 0)
+                r = job_finish_and_invalidate(j, false);
+
+        return r;
+}
+
+int job_finish_and_invalidate(Job *j, bool success) {
+        Unit *u;
+        Unit *other;
+        JobType t;
+        Iterator i;
+
+        assert(j);
+        assert(j->installed);
+
+        log_debug("Job %s/%s finished, success=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(success));
+        job_add_to_dbus_queue(j);
+
+        /* Patch restart jobs so that they become normal start jobs */
+        if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
+
+                log_debug("Converting job %s/%s -> %s/%s",
+                          j->unit->meta.id, job_type_to_string(j->type),
+                          j->unit->meta.id, job_type_to_string(JOB_START));
+
+                j->state = JOB_RUNNING;
+                j->type = JOB_START;
+
+                job_add_to_run_queue(j);
+                return 0;
+        }
+
+        u = j->unit;
+        t = j->type;
+        job_free(j);
+
+        /* Fail depending jobs on failure */
+        if (!success) {
+
+                if (t == JOB_START ||
+                    t == JOB_VERIFY_ACTIVE ||
+                    t == JOB_RELOAD_OR_START) {
+
+                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
+                                if (other->meta.job &&
+                                    (other->meta.job->type == JOB_START ||
+                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
+                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                        job_finish_and_invalidate(other->meta.job, false);
+
+                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
+                                if (other->meta.job &&
+                                    !other->meta.job->override &&
+                                    (other->meta.job->type == JOB_START ||
+                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
+                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                        job_finish_and_invalidate(other->meta.job, false);
+
+                } else if (t == JOB_STOP) {
+
+                        SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
+                                if (other->meta.job &&
+                                    (other->meta.job->type == JOB_START ||
+                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
+                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                        job_finish_and_invalidate(other->meta.job, false);
+                }
+        }
+
+        /* Try to start the next jobs that can be started */
+        SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
+                if (other->meta.job)
+                        job_add_to_run_queue(other->meta.job);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i)
+                if (other->meta.job)
+                        job_add_to_run_queue(other->meta.job);
+
+        return 0;
+}
+
+void job_add_to_run_queue(Job *j) {
+        assert(j);
+        assert(j->installed);
+
+        if (j->in_run_queue)
+                return;
+
+        LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
+        j->in_run_queue = true;
+}
+
+void job_add_to_dbus_queue(Job *j) {
+        assert(j);
+        assert(j->installed);
+
+        if (j->in_dbus_queue)
+                return;
+
+        if (set_isempty(j->manager->subscribed)) {
+                j->sent_dbus_new_signal = true;
+                return;
+        }
+
+        LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
+        j->in_dbus_queue = true;
+}
+
+char *job_dbus_path(Job *j) {
+        char *p;
+
+        assert(j);
+
+        if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
+                return NULL;
+
+        return p;
+}
+
+static const char* const job_state_table[_JOB_STATE_MAX] = {
+        [JOB_WAITING] = "waiting",
+        [JOB_RUNNING] = "running"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
+
+static const char* const job_type_table[_JOB_TYPE_MAX] = {
+        [JOB_START] = "start",
+        [JOB_VERIFY_ACTIVE] = "verify-active",
+        [JOB_STOP] = "stop",
+        [JOB_RELOAD] = "reload",
+        [JOB_RELOAD_OR_START] = "reload-or-start",
+        [JOB_RESTART] = "restart",
+        [JOB_TRY_RESTART] = "try-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
+
+static const char* const job_mode_table[_JOB_MODE_MAX] = {
+        [JOB_FAIL] = "fail",
+        [JOB_REPLACE] = "replace",
+        [JOB_ISOLATE] = "isolate"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
diff --git a/src/job.h b/src/job.h
new file mode 100644
index 0000000..1ae97b7
--- /dev/null
+++ b/src/job.h
@@ -0,0 +1,150 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foojobhfoo
+#define foojobhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+typedef struct Job Job;
+typedef struct JobDependency JobDependency;
+typedef enum JobType JobType;
+typedef enum JobState JobState;
+typedef enum JobMode JobMode;
+
+#include "manager.h"
+#include "unit.h"
+#include "hashmap.h"
+#include "list.h"
+
+enum JobType {
+        JOB_START,                  /* if a unit does not support being started, we'll just wait until it becomes active */
+        JOB_VERIFY_ACTIVE,
+
+        JOB_STOP,
+
+        JOB_RELOAD,                 /* if running reload */
+        JOB_RELOAD_OR_START,        /* if running reload, if not running start */
+
+        /* Note that restarts are first treated like JOB_STOP, but
+         * then instead of finishing are patched to become
+         * JOB_START. */
+        JOB_RESTART,                /* if running stop, then start unconditionally */
+        JOB_TRY_RESTART,            /* if running stop and then start */
+
+        _JOB_TYPE_MAX,
+        _JOB_TYPE_INVALID = -1
+};
+
+enum JobState {
+        JOB_WAITING,
+        JOB_RUNNING,
+        _JOB_STATE_MAX,
+        _JOB_STATE_INVALID = -1
+};
+
+enum JobMode {
+        JOB_FAIL,
+        JOB_REPLACE,
+        JOB_ISOLATE,
+        _JOB_MODE_MAX,
+        _JOB_MODE_INVALID = -1
+};
+
+struct JobDependency {
+        /* Encodes that the 'subject' job needs the 'object' job in
+         * some way. This structure is used only while building a transaction. */
+        Job *subject;
+        Job *object;
+
+        LIST_FIELDS(JobDependency, subject);
+        LIST_FIELDS(JobDependency, object);
+
+        bool matters;
+};
+
+struct Job {
+        Manager *manager;
+        Unit *unit;
+
+        LIST_FIELDS(Job, transaction);
+        LIST_FIELDS(Job, run_queue);
+        LIST_FIELDS(Job, dbus_queue);
+
+        LIST_HEAD(JobDependency, subject_list);
+        LIST_HEAD(JobDependency, object_list);
+
+        /* Used for graph algs as a "I have been here" marker */
+        Job* marker;
+        unsigned generation;
+
+        uint32_t id;
+
+        JobType type;
+        JobState state;
+
+        bool installed:1;
+        bool in_run_queue:1;
+        bool matters_to_anchor:1;
+        bool override:1;
+        bool in_dbus_queue:1;
+        bool sent_dbus_new_signal:1;
+};
+
+Job* job_new(Manager *m, JobType type, Unit *unit);
+void job_free(Job *job);
+void job_dump(Job *j, FILE*f, const char *prefix);
+
+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters);
+void job_dependency_free(JobDependency *l);
+void job_dependency_delete(Job *subject, Job *object, bool *matters);
+
+bool job_is_anchor(Job *j);
+
+int job_merge(Job *j, Job *other);
+
+int job_type_merge(JobType *a, JobType b);
+bool job_type_is_mergeable(JobType a, JobType b);
+bool job_type_is_superset(JobType a, JobType b);
+bool job_type_is_conflicting(JobType a, JobType b);
+bool job_type_is_redundant(JobType a, UnitActiveState b);
+
+bool job_is_runnable(Job *j);
+
+void job_add_to_run_queue(Job *j);
+void job_add_to_dbus_queue(Job *j);
+
+int job_run_and_invalidate(Job *j);
+int job_finish_and_invalidate(Job *j, bool success);
+
+const char* job_type_to_string(JobType t);
+JobType job_type_from_string(const char *s);
+
+const char* job_state_to_string(JobState t);
+JobState job_state_from_string(const char *s);
+
+const char* job_mode_to_string(JobMode t);
+JobMode job_mode_from_string(const char *s);
+
+char *job_dbus_path(Job *j);
+
+#endif
diff --git a/src/linux/auto_dev-ioctl.h b/src/linux/auto_dev-ioctl.h
new file mode 100644
index 0000000..850f39b
--- /dev/null
+++ b/src/linux/auto_dev-ioctl.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven at themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#ifndef _LINUX_AUTO_DEV_IOCTL_H
+#define _LINUX_AUTO_DEV_IOCTL_H
+
+#include <linux/auto_fs.h>
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif /* __KERNEL__ */
+
+#define AUTOFS_DEVICE_NAME		"autofs"
+
+#define AUTOFS_DEV_IOCTL_VERSION_MAJOR	1
+#define AUTOFS_DEV_IOCTL_VERSION_MINOR	0
+
+#define AUTOFS_DEVID_LEN		16
+
+#define AUTOFS_DEV_IOCTL_SIZE		sizeof(struct autofs_dev_ioctl)
+
+/*
+ * An ioctl interface for autofs mount point control.
+ */
+
+struct args_protover {
+	__u32	version;
+};
+
+struct args_protosubver {
+	__u32	sub_version;
+};
+
+struct args_openmount {
+	__u32	devid;
+};
+
+struct args_ready {
+	__u32	token;
+};
+
+struct args_fail {
+	__u32	token;
+	__s32	status;
+};
+
+struct args_setpipefd {
+	__s32	pipefd;
+};
+
+struct args_timeout {
+	__u64	timeout;
+};
+
+struct args_requester {
+	__u32	uid;
+	__u32	gid;
+};
+
+struct args_expire {
+	__u32	how;
+};
+
+struct args_askumount {
+	__u32	may_umount;
+};
+
+struct args_ismountpoint {
+	union {
+		struct args_in {
+			__u32	type;
+		} in;
+		struct args_out {
+			__u32	devid;
+			__u32	magic;
+		} out;
+	};
+};
+
+/*
+ * All the ioctls use this structure.
+ * When sending a path size must account for the total length
+ * of the chunk of memory otherwise is is the size of the
+ * structure.
+ */
+
+struct autofs_dev_ioctl {
+	__u32 ver_major;
+	__u32 ver_minor;
+	__u32 size;		/* total size of data passed in
+				 * including this struct */
+	__s32 ioctlfd;		/* automount command fd */
+
+	/* Command parameters */
+
+	union {
+		struct args_protover		protover;
+		struct args_protosubver		protosubver;
+		struct args_openmount		openmount;
+		struct args_ready		ready;
+		struct args_fail		fail;
+		struct args_setpipefd		setpipefd;
+		struct args_timeout		timeout;
+		struct args_requester		requester;
+		struct args_expire		expire;
+		struct args_askumount		askumount;
+		struct args_ismountpoint	ismountpoint;
+	};
+
+	char path[0];
+};
+
+static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
+{
+	memset(in, 0, sizeof(struct autofs_dev_ioctl));
+	in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+	in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+	in->size = sizeof(struct autofs_dev_ioctl);
+	in->ioctlfd = -1;
+	return;
+}
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to autofs-dev-ioctl.c:lookup_ioctl()
+ */
+enum {
+	/* Get various version info */
+	AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71,
+	AUTOFS_DEV_IOCTL_PROTOVER_CMD,
+	AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD,
+
+	/* Open mount ioctl fd */
+	AUTOFS_DEV_IOCTL_OPENMOUNT_CMD,
+
+	/* Close mount ioctl fd */
+	AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD,
+
+	/* Mount/expire status returns */
+	AUTOFS_DEV_IOCTL_READY_CMD,
+	AUTOFS_DEV_IOCTL_FAIL_CMD,
+
+	/* Activate/deactivate autofs mount */
+	AUTOFS_DEV_IOCTL_SETPIPEFD_CMD,
+	AUTOFS_DEV_IOCTL_CATATONIC_CMD,
+
+	/* Expiry timeout */
+	AUTOFS_DEV_IOCTL_TIMEOUT_CMD,
+
+	/* Get mount last requesting uid and gid */
+	AUTOFS_DEV_IOCTL_REQUESTER_CMD,
+
+	/* Check for eligible expire candidates */
+	AUTOFS_DEV_IOCTL_EXPIRE_CMD,
+
+	/* Request busy status */
+	AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD,
+
+	/* Check if path is a mountpoint */
+	AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD,
+};
+
+#define AUTOFS_IOCTL 0x93
+
+#define AUTOFS_DEV_IOCTL_VERSION \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOVER \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOSUBVER \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_OPENMOUNT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_READY \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_FAIL \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_SETPIPEFD \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CATATONIC \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_TIMEOUT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_REQUESTER \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_EXPIRE \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ASKUMOUNT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl)
+
+#endif	/* _LINUX_AUTO_DEV_IOCTL_H */
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..012dd12
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,119 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foolisthfoo
+#define foolisthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+/* The head of the linked list. Use this in the structure that shall
+ * contain the head of the linked list */
+#define LIST_HEAD(t,name)                                               \
+        t *name
+
+/* The pointers in the linked list's items. Use this in the item structure */
+#define LIST_FIELDS(t,name)                                             \
+        t *name##_next, *name##_prev
+
+/* Initialize the list's head */
+#define LIST_HEAD_INIT(t,head)                                          \
+        do {                                                            \
+                (head) = NULL; }                                        \
+        while(false)
+
+/* Initialize a list item */
+#define LIST_INIT(t,name,item)                                          \
+        do {                                                            \
+                t *_item = (item);                                      \
+                assert(_item);                                          \
+                _item->name##_prev = _item->name##_next = NULL;         \
+        } while(false)
+
+/* Prepend an item to the list */
+#define LIST_PREPEND(t,name,head,item)                                  \
+        do {                                                            \
+                t **_head = &(head), *_item = (item);                   \
+                assert(_item);                                          \
+                if ((_item->name##_next = *_head))                      \
+                        _item->name##_next->name##_prev = _item;        \
+                _item->name##_prev = NULL;                              \
+                *_head = _item;                                         \
+        } while(false)
+
+/* Remove an item from the list */
+#define LIST_REMOVE(t,name,head,item)                                   \
+        do {                                                            \
+                t **_head = &(head), *_item = (item);                   \
+                assert(_item);                                          \
+                if (_item->name##_next)                                 \
+                        _item->name##_next->name##_prev = _item->name##_prev; \
+                if (_item->name##_prev)                                 \
+                        _item->name##_prev->name##_next = _item->name##_next; \
+                else {                                                  \
+                        assert(*_head == _item);                        \
+                        *_head = _item->name##_next;                    \
+                }                                                       \
+                _item->name##_next = _item->name##_prev = NULL;         \
+        } while(false)
+
+/* Find the head of the list */
+#define LIST_FIND_HEAD(t,name,item,head)                                \
+        do {                                                            \
+                t *_item = (item);                                      \
+                assert(_item);                                          \
+                while ((_item->name##_prev)                             \
+                       _item = _item->name##_prev;                      \
+                (head) = _item;                                         \
+        } while (false)
+
+/* Find the head of the list */
+#define LIST_FIND_TAIL(t,name,item,tail)                                \
+        do {                                                            \
+                t *_item = (item);                                      \
+                assert(_item);                                          \
+                while (_item->name##_next)                              \
+                        _item = _item->name##_next;                     \
+                (tail) = _item;                                         \
+        } while (false)
+
+/* Insert an item after another one (a = where, b = what) */
+#define LIST_INSERT_AFTER(t,name,head,a,b)                              \
+        do {                                                            \
+                t **_head = &(head), *_a = (a), *_b = (b);              \
+                assert(_b);                                             \
+                if (!_a) {                                              \
+                        if ((_b->name##_next = *_head))                 \
+                                _b->name##_next->name##_prev = _b;      \
+                        _b->name##_prev = NULL;                         \
+                        *_head = _b;                                    \
+                } else {                                                \
+                        if ((_b->name##_next = _a->name##_next))        \
+                                _b->name##_next->name##_prev = _b;      \
+                        _b->name##_prev = _a;                           \
+                        _a->name##_next = _b;                           \
+                }                                                       \
+        } while(false)
+
+#define LIST_FOREACH(name,i,head)                                       \
+        for ((i) = (head); (i); (i) = (i)->name##_next)
+
+#define LIST_FOREACH_SAFE(name,i,n,head)                                \
+        for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
+
+#endif
diff --git a/src/load-dropin.c b/src/load-dropin.c
new file mode 100644
index 0000000..2101e33
--- /dev/null
+++ b/src/load-dropin.c
@@ -0,0 +1,117 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dirent.h>
+#include <errno.h>
+
+#include "unit.h"
+#include "load-dropin.h"
+#include "log.h"
+#include "strv.h"
+#include "unit-name.h"
+
+static int iterate_dir(Unit *u, const char *path) {
+        DIR *d;
+        struct dirent *de;
+        int r;
+
+        if (!(d = opendir(path))) {
+
+                if (errno == ENOENT)
+                        return 0;
+
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                char *f;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                if (asprintf(&f, "%s/%s", path, de->d_name) < 0) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                r = unit_add_dependency_by_name(u, UNIT_WANTS, de->d_name, f, true);
+                free(f);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        closedir(d);
+        return r;
+}
+
+int unit_load_dropin(Unit *u) {
+        Iterator i;
+        int r;
+        char *t;
+
+        assert(u);
+
+        /* Load dependencies from supplementary drop-in directories */
+
+        SET_FOREACH(t, u->meta.names, i) {
+                char *path;
+                char **p;
+
+                STRV_FOREACH(p, u->meta.manager->unit_path) {
+
+                        if (asprintf(&path, "%s/%s.wants", *p, t) < 0)
+                                return -ENOMEM;
+
+                        r = iterate_dir(u, path);
+                        free(path);
+
+                        if (r < 0)
+                                return r;
+
+                        if (u->meta.instance) {
+                                char *template;
+                                /* Also try the template dir */
+
+                                if (!(template = unit_name_template(t)))
+                                        return -ENOMEM;
+
+                                r = asprintf(&path, "%s/%s.wants", *p, template);
+                                free(template);
+
+                                if (r < 0)
+                                        return -ENOMEM;
+
+                                r = iterate_dir(u, path);
+                                free(path);
+
+                                if (r < 0)
+                                        return r;
+                        }
+
+                }
+        }
+
+        return 0;
+}
diff --git a/src/load-dropin.h b/src/load-dropin.h
new file mode 100644
index 0000000..b39580b
--- /dev/null
+++ b/src/load-dropin.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooloaddropinhfoo
+#define fooloaddropinhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "unit.h"
+
+/* Read service data supplementary drop-in directories */
+
+int unit_load_dropin(Unit *u);
+
+#endif
diff --git a/src/load-fragment.c b/src/load-fragment.c
new file mode 100644
index 0000000..148a579
--- /dev/null
+++ b/src/load-fragment.c
@@ -0,0 +1,1483 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <linux/oom.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include "unit.h"
+#include "strv.h"
+#include "conf-parser.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "ioprio.h"
+#include "securebits.h"
+#include "missing.h"
+#include "unit-name.h"
+
+#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg)                \
+        static int function(                                            \
+                        const char *filename,                           \
+                        unsigned line,                                  \
+                        const char *section,                            \
+                        const char *lvalue,                             \
+                        const char *rvalue,                             \
+                        void *data,                                     \
+                        void *userdata) {                               \
+                                                                        \
+                type *i = data, x;                                      \
+                                                                        \
+                assert(filename);                                       \
+                assert(lvalue);                                         \
+                assert(rvalue);                                         \
+                assert(data);                                           \
+                                                                        \
+                if ((x = name##_from_string(rvalue)) < 0) {             \
+                        log_error("[%s:%u] " msg ": %s", filename, line, rvalue); \
+                        return -EBADMSG;                                \
+                }                                                       \
+                                                                        \
+                *i = x;                                                 \
+                                                                        \
+                return 0;                                               \
+        }
+
+static int config_parse_deps(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        UnitDependency d = PTR_TO_UINT(data);
+        Unit *u = userdata;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                char *t, *k;
+                int r;
+
+                if (!(t = strndup(w, l)))
+                        return -ENOMEM;
+
+                k = unit_name_printf(u, t);
+                free(t);
+
+                if (!k)
+                        return -ENOMEM;
+
+                r = unit_add_dependency_by_name(u, d, k, NULL, true);
+                free(k);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int config_parse_names(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                char *t, *k;
+                int r;
+
+                if (!(t = strndup(w, l)))
+                        return -ENOMEM;
+
+                k = unit_name_printf(u, t);
+                free(t);
+
+                if (!k)
+                        return -ENOMEM;
+
+                r = unit_merge_by_name(u, k);
+                free(k);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int config_parse_description(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *k;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (!(k = unit_full_printf(u, rvalue)))
+                return -ENOMEM;
+
+        free(u->meta.description);
+
+        if (*k)
+                u->meta.description = k;
+        else {
+                free(k);
+                u->meta.description = NULL;
+        }
+
+        return 0;
+}
+
+static int config_parse_listen(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int r;
+        SocketPort *p;
+        Socket *s;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        s = (Socket*) data;
+
+        if (!(p = new0(SocketPort, 1)))
+                return -ENOMEM;
+
+        if (streq(lvalue, "ListenFIFO")) {
+                p->type = SOCKET_FIFO;
+
+                if (!(p->path = strdup(rvalue))) {
+                        free(p);
+                        return -ENOMEM;
+                }
+        } else {
+                p->type = SOCKET_SOCKET;
+
+                if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
+                        log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
+                        free(p);
+                        return r;
+                }
+
+                if (streq(lvalue, "ListenStream"))
+                        p->address.type = SOCK_STREAM;
+                else if (streq(lvalue, "ListenDatagram"))
+                        p->address.type = SOCK_DGRAM;
+                else {
+                        assert(streq(lvalue, "ListenSequentialPacket"));
+                        p->address.type = SOCK_SEQPACKET;
+                }
+
+                if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
+                        free(p);
+                        return -EPROTONOSUPPORT;
+                }
+        }
+
+        p->fd = -1;
+        LIST_PREPEND(SocketPort, port, s->ports, p);
+
+        return 0;
+}
+
+static int config_parse_socket_bind(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int r;
+        Socket *s;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        s = (Socket*) data;
+
+        if ((r = parse_boolean(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
+
+        return 0;
+}
+
+static int config_parse_nice(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int priority, r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atoi(rvalue, &priority)) < 0) {
+                log_error("[%s:%u] Failed to parse nice priority: %s", filename, line, rvalue);
+                return r;
+        }
+
+        if (priority < PRIO_MIN || priority >= PRIO_MAX) {
+                log_error("[%s:%u] Nice priority out of range: %s", filename, line, rvalue);
+                return -ERANGE;
+        }
+
+        c->nice = priority;
+        c->nice_set = false;
+
+        return 0;
+}
+
+static int config_parse_oom_adjust(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int oa, r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atoi(rvalue, &oa)) < 0) {
+                log_error("[%s:%u] Failed to parse OOM adjust value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        if (oa < OOM_DISABLE || oa > OOM_ADJUST_MAX) {
+                log_error("[%s:%u] OOM adjust value out of range: %s", filename, line, rvalue);
+                return -ERANGE;
+        }
+
+        c->oom_adjust = oa;
+        c->oom_adjust_set = true;
+
+        return 0;
+}
+
+static int config_parse_mode(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        mode_t *m = data;
+        long l;
+        char *x = NULL;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        errno = 0;
+        l = strtol(rvalue, &x, 8);
+        if (!x || *x || errno) {
+                log_error("[%s:%u] Failed to parse mode value: %s", filename, line, rvalue);
+                return errno ? -errno : -EINVAL;
+        }
+
+        if (l < 0000 || l > 07777) {
+                log_error("[%s:%u] mode value out of range: %s", filename, line, rvalue);
+                return -ERANGE;
+        }
+
+        *m = (mode_t) l;
+        return 0;
+}
+
+static int config_parse_exec(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecCommand **e = data, *nce = NULL;
+        char **n;
+        char *w;
+        unsigned k;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        k = 0;
+        FOREACH_WORD_QUOTED(w, l, rvalue, state)
+                k++;
+
+        if (!(n = new(char*, k+1)))
+                return -ENOMEM;
+
+        k = 0;
+        FOREACH_WORD_QUOTED(w, l, rvalue, state)
+                if (!(n[k++] = strndup(w, l)))
+                        goto fail;
+
+        n[k] = NULL;
+
+        if (!n[0] || !path_is_absolute(n[0])) {
+                log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
+                strv_free(n);
+                return -EINVAL;
+        }
+
+        if (!(nce = new0(ExecCommand, 1)))
+                goto fail;
+
+        nce->argv = n;
+        if (!(nce->path = strdup(n[0])))
+                goto fail;
+
+        exec_command_append_list(e, nce);
+
+        return 0;
+
+fail:
+        for (; k > 0; k--)
+                free(n[k-1]);
+        free(n);
+
+        free(nce);
+
+        return -ENOMEM;
+}
+
+static int config_parse_usec(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        usec_t *usec = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = parse_usec(rvalue, usec)) < 0) {
+                log_error("[%s:%u] Failed to parse time value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
+
+static int config_parse_bindtodevice(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Socket *s = data;
+        char *n;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (rvalue[0] && !streq(rvalue, "*")) {
+                if (!(n = strdup(rvalue)))
+                        return -ENOMEM;
+        } else
+                n = NULL;
+
+        free(s->bind_to_device);
+        s->bind_to_device = n;
+
+        return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
+
+static int config_parse_facility(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+
+        int *o = data, x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((x = log_facility_from_string(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse log facility: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        *o = LOG_MAKEPRI(x, LOG_PRI(*o));
+
+        return 0;
+}
+
+static int config_parse_level(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+
+        int *o = data, x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((x = log_level_from_string(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse log level: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        *o = LOG_MAKEPRI(LOG_FAC(*o), x);
+        return 0;
+}
+
+static int config_parse_io_class(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((x = ioprio_class_from_string(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse IO scheduling class: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
+        c->ioprio_set = true;
+
+        return 0;
+}
+
+static int config_parse_io_priority(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int i;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
+                log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
+        c->ioprio_set = true;
+
+        return 0;
+}
+
+static int config_parse_cpu_sched_policy(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+
+        ExecContext *c = data;
+        int x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((x = sched_policy_from_string(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse CPU scheduling policy: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        c->cpu_sched_policy = x;
+        c->cpu_sched_set = true;
+
+        return 0;
+}
+
+static int config_parse_cpu_sched_prio(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int i;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        /* On Linux RR/FIFO have the same range */
+        if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
+                log_error("[%s:%u] Failed to parse CPU scheduling priority: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        c->cpu_sched_priority = i;
+        c->cpu_sched_set = true;
+
+        return 0;
+}
+
+static int config_parse_cpu_affinity(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                char *t;
+                int r;
+                unsigned cpu;
+
+                if (!(t = strndup(w, l)))
+                        return -ENOMEM;
+
+                r = safe_atou(t, &cpu);
+                free(t);
+
+                if (r < 0 || cpu >= CPU_SETSIZE) {
+                        log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
+                        return -EBADMSG;
+                }
+
+                CPU_SET(cpu, &c->cpu_affinity);
+        }
+
+        c->cpu_affinity_set = true;
+
+        return 0;
+}
+
+static int config_parse_capabilities(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        cap_t cap;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (!(cap = cap_from_text(rvalue))) {
+                if (errno == ENOMEM)
+                        return -ENOMEM;
+
+                log_error("[%s:%u] Failed to parse capabilities: %s", filename, line, rvalue);
+                return -EBADMSG;
+        }
+
+        if (c->capabilities)
+                cap_free(c->capabilities);
+        c->capabilities = cap;
+
+        return 0;
+}
+
+static int config_parse_secure_bits(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                if (first_word(w, "keep-caps"))
+                        c->secure_bits |= SECURE_KEEP_CAPS;
+                else if (first_word(w, "keep-caps-locked"))
+                        c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
+                else if (first_word(w, "no-setuid-fixup"))
+                        c->secure_bits |= SECURE_NO_SETUID_FIXUP;
+                else if (first_word(w, "no-setuid-fixup-locked"))
+                        c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
+                else if (first_word(w, "noroot"))
+                        c->secure_bits |= SECURE_NOROOT;
+                else if (first_word(w, "noroot-locked"))
+                        c->secure_bits |= SECURE_NOROOT_LOCKED;
+                else {
+                        log_error("[%s:%u] Failed to parse secure bits: %s", filename, line, rvalue);
+                        return -EBADMSG;
+                }
+        }
+
+        return 0;
+}
+
+static int config_parse_bounding_set(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                char *t;
+                int r;
+                cap_value_t cap;
+
+                if (!(t = strndup(w, l)))
+                        return -ENOMEM;
+
+                r = cap_from_name(t, &cap);
+                free(t);
+
+                if (r < 0) {
+                        log_error("[%s:%u] Failed to parse capability bounding set: %s", filename, line, rvalue);
+                        return -EBADMSG;
+                }
+
+                c->capability_bounding_set_drop |= 1 << cap;
+        }
+
+        return 0;
+}
+
+static int config_parse_timer_slack_ns(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        unsigned long u;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atolu(rvalue, &u)) < 0) {
+                log_error("[%s:%u] Failed to parse time slack value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        c->timer_slack_ns = u;
+
+        return 0;
+}
+
+static int config_parse_limit(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        struct rlimit **rl = data;
+        unsigned long long u;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atollu(rvalue, &u)) < 0) {
+                log_error("[%s:%u] Failed to parse resource value: %s", filename, line, rvalue);
+                return r;
+        }
+
+        if (!*rl)
+                if (!(*rl = new(struct rlimit, 1)))
+                        return -ENOMEM;
+
+        (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
+        return 0;
+}
+
+static int config_parse_cgroup(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *w;
+        size_t l;
+        char *state;
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                char *t;
+                int r;
+
+                if (!(t = strndup(w, l)))
+                        return -ENOMEM;
+
+                r = unit_add_cgroup_from_text(u, t);
+                free(t);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int config_parse_sysv_priority(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *priority = data;
+        int r, i;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((r = safe_atoi(rvalue, &i)) < 0 || i < 0) {
+                log_error("[%s:%u] Failed to parse SysV start priority: %s", filename, line, rvalue);
+                return r;
+        }
+
+        *priority = (int) i;
+        return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
+
+static int config_parse_mount_flags(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        char *w;
+        size_t l;
+        char *state;
+        unsigned long flags = 0;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                if (strncmp(w, "shared", l) == 0)
+                        flags |= MS_SHARED;
+                else if (strncmp(w, "slave", l) == 0)
+                        flags |= MS_SLAVE;
+                else if (strncmp(w, "private", l) == 0)
+                        flags |= MS_PRIVATE;
+                else {
+                        log_error("[%s:%u] Failed to parse mount flags: %s", filename, line, rvalue);
+                        return -EINVAL;
+                }
+        }
+
+        c->mount_flags = flags;
+        return 0;
+}
+
+#define FOLLOW_MAX 8
+
+static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
+        unsigned c = 0;
+        int fd, r;
+        FILE *f;
+        char *id = NULL;
+
+        assert(filename);
+        assert(*filename);
+        assert(_f);
+        assert(names);
+
+        /* This will update the filename pointer if the loaded file is
+         * reached by a symlink. The old string will be freed. */
+
+        for (;;) {
+                char *target, *k, *name;
+
+                if (c++ >= FOLLOW_MAX)
+                        return -ELOOP;
+
+                path_kill_slashes(*filename);
+
+                /* Add the file name we are currently looking at to
+                 * the names of this unit */
+                name = file_name_from_path(*filename);
+                if (!(id = set_get(names, name))) {
+
+                        if (!(id = strdup(name)))
+                                return -ENOMEM;
+
+                        if ((r = set_put(names, id)) < 0) {
+                                free(id);
+                                return r;
+                        }
+                }
+
+                /* Try to open the file name, but don't if its a symlink */
+                if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
+                        break;
+
+                if (errno != ELOOP)
+                        return -errno;
+
+                /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
+                if ((r = readlink_malloc(*filename, &target)) < 0)
+                        return r;
+
+                k = file_in_same_dir(*filename, target);
+                free(target);
+
+                if (!k)
+                        return -ENOMEM;
+
+                free(*filename);
+                *filename = k;
+        }
+
+        if (!(f = fdopen(fd, "r"))) {
+                r = -errno;
+                close_nointr_nofail(fd);
+                return r;
+        }
+
+        *_f = f;
+        *_final = id;
+        return 0;
+}
+
+static int merge_by_names(Unit **u, Set *names, const char *id) {
+        char *k;
+        int r;
+
+        assert(u);
+        assert(*u);
+        assert(names);
+
+        /* Let's try to add in all symlink names we found */
+        while ((k = set_steal_first(names))) {
+
+                /* First try to merge in the other name into our
+                 * unit */
+                if ((r = unit_merge_by_name(*u, k)) < 0) {
+                        Unit *other;
+
+                        /* Hmm, we couldn't merge the other unit into
+                         * ours? Then let's try it the other way
+                         * round */
+
+                        other = manager_get_unit((*u)->meta.manager, k);
+                        free(k);
+
+                        if (other)
+                                if ((r = unit_merge(other, *u)) >= 0) {
+                                        *u = other;
+                                        return merge_by_names(u, names, NULL);
+                                }
+
+                        return r;
+                }
+
+                if (id == k)
+                        unit_choose_id(*u, id);
+
+                free(k);
+        }
+
+        return 0;
+}
+
+static void dump_items(FILE *f, const ConfigItem *items) {
+        const ConfigItem *i;
+        const char *prev_section = NULL;
+        bool not_first = false;
+
+        struct {
+                ConfigParserCallback callback;
+                const char *rvalue;
+        } table[] = {
+                { config_parse_int,              "INTEGER" },
+                { config_parse_unsigned,         "UNSIGNED" },
+                { config_parse_size,             "SIZE" },
+                { config_parse_bool,             "BOOLEAN" },
+                { config_parse_string,           "STRING" },
+                { config_parse_path,             "PATH" },
+                { config_parse_strv,             "STRING [...]" },
+                { config_parse_nice,             "NICE" },
+                { config_parse_oom_adjust,       "OOMADJUST" },
+                { config_parse_io_class,         "IOCLASS" },
+                { config_parse_io_priority,      "IOPRIORITY" },
+                { config_parse_cpu_sched_policy, "CPUSCHEDPOLICY" },
+                { config_parse_cpu_sched_prio,   "CPUSCHEDPRIO" },
+                { config_parse_cpu_affinity,     "CPUAFFINITY" },
+                { config_parse_mode,             "MODE" },
+                { config_parse_output,           "OUTPUT" },
+                { config_parse_input,            "INPUT" },
+                { config_parse_facility,         "FACILITY" },
+                { config_parse_level,            "LEVEL" },
+                { config_parse_capabilities,     "CAPABILITIES" },
+                { config_parse_secure_bits,      "SECUREBITS" },
+                { config_parse_bounding_set,     "BOUNDINGSET" },
+                { config_parse_timer_slack_ns,   "TIMERSLACK" },
+                { config_parse_limit,            "LIMIT" },
+                { config_parse_cgroup,           "CGROUP [...]" },
+                { config_parse_deps,             "UNIT [...]" },
+                { config_parse_names,            "UNIT [...]" },
+                { config_parse_exec,             "PATH [ARGUMENT [...]]" },
+                { config_parse_service_type,     "SERVICETYPE" },
+                { config_parse_service_restart,  "SERVICERESTART" },
+                { config_parse_sysv_priority,    "SYSVPRIORITY" },
+                { config_parse_kill_mode,        "KILLMODE" },
+                { config_parse_listen,           "SOCKET [...]" },
+                { config_parse_socket_bind,      "SOCKETBIND" },
+                { config_parse_bindtodevice,     "NETWORKINTERFACE" },
+                { config_parse_usec,             "SECONDS" },
+                { config_parse_path_strv,        "PATH [...]" },
+                { config_parse_mount_flags,      "MOUNTFLAG [...]" },
+                { config_parse_description,      "DESCRIPTION" },
+        };
+
+        assert(f);
+        assert(items);
+
+        for (i = items; i->lvalue; i++) {
+                unsigned j;
+                const char *rvalue = "OTHER";
+
+                if (!streq_ptr(i->section, prev_section)) {
+                        if (!not_first)
+                                not_first = true;
+                        else
+                                fputc('\n', f);
+
+                        fprintf(f, "[%s]\n", i->section);
+                        prev_section = i->section;
+                }
+
+                for (j = 0; j < ELEMENTSOF(table); j++)
+                        if (i->parse == table[j].callback) {
+                                rvalue = table[j].rvalue;
+                                break;
+                        }
+
+                fprintf(f, "%s=%s\n", i->lvalue, rvalue);
+        }
+}
+
+static int load_from_path(Unit *u, const char *path) {
+
+        static const char* const section_table[_UNIT_TYPE_MAX] = {
+                [UNIT_SERVICE]   = "Service",
+                [UNIT_TIMER]     = "Timer",
+                [UNIT_SOCKET]    = "Socket",
+                [UNIT_TARGET]    = "Target",
+                [UNIT_DEVICE]    = "Device",
+                [UNIT_MOUNT]     = "Mount",
+                [UNIT_AUTOMOUNT] = "Automount",
+                [UNIT_SNAPSHOT]  = "Snapshot",
+                [UNIT_SWAP]      = "Swap"
+        };
+
+#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
+                { "WorkingDirectory",       config_parse_path,            &(context).working_directory,                    section   }, \
+                { "RootDirectory",          config_parse_path,            &(context).root_directory,                       section   }, \
+                { "User",                   config_parse_string,          &(context).user,                                 section   }, \
+                { "Group",                  config_parse_string,          &(context).group,                                section   }, \
+                { "SupplementaryGroups",    config_parse_strv,            &(context).supplementary_groups,                 section   }, \
+                { "Nice",                   config_parse_nice,            &(context),                                      section   }, \
+                { "OOMAdjust",              config_parse_oom_adjust,      &(context),                                      section   }, \
+                { "IOSchedulingClass",      config_parse_io_class,        &(context),                                      section   }, \
+                { "IOSchedulingPriority",   config_parse_io_priority,     &(context),                                      section   }, \
+                { "CPUSchedulingPolicy",    config_parse_cpu_sched_policy,&(context),                                      section   }, \
+                { "CPUSchedulingPriority",  config_parse_cpu_sched_prio,  &(context),                                      section   }, \
+                { "CPUSchedulingResetOnFork", config_parse_bool,          &(context).cpu_sched_reset_on_fork,              section   }, \
+                { "CPUAffinity",            config_parse_cpu_affinity,    &(context),                                      section   }, \
+                { "UMask",                  config_parse_mode,            &(context).umask,                                section   }, \
+                { "Environment",            config_parse_strv,            &(context).environment,                          section   }, \
+                { "StandardInput",          config_parse_input,           &(context).std_input,                            section   }, \
+                { "StandardOutput",         config_parse_output,          &(context).std_output,                           section   }, \
+                { "StandardError",          config_parse_output,          &(context).std_output,                           section   }, \
+                { "TTYPath",                config_parse_path,            &(context).tty_path,                             section   }, \
+                { "SyslogIdentifier",       config_parse_string,          &(context).syslog_identifier,                    section   }, \
+                { "SyslogFacility",         config_parse_facility,        &(context).syslog_priority,                      section   }, \
+                { "SyslogLevel",            config_parse_level,           &(context).syslog_priority,                      section   }, \
+                { "SyslogNoPrefix",         config_parse_bool,            &(context).syslog_no_prefix,                     section   }, \
+                { "Capabilities",           config_parse_capabilities,    &(context),                                      section   }, \
+                { "SecureBits",             config_parse_secure_bits,     &(context),                                      section   }, \
+                { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context),                                      section   }, \
+                { "TimerSlackNS",           config_parse_timer_slack_ns,  &(context),                                      section   }, \
+                { "LimitCPU",               config_parse_limit,           &(context).rlimit[RLIMIT_CPU],                   section   }, \
+                { "LimitFSIZE",             config_parse_limit,           &(context).rlimit[RLIMIT_FSIZE],                 section   }, \
+                { "LimitDATA",              config_parse_limit,           &(context).rlimit[RLIMIT_DATA],                  section   }, \
+                { "LimitSTACK",             config_parse_limit,           &(context).rlimit[RLIMIT_STACK],                 section   }, \
+                { "LimitCORE",              config_parse_limit,           &(context).rlimit[RLIMIT_CORE],                  section   }, \
+                { "LimitRSS",               config_parse_limit,           &(context).rlimit[RLIMIT_RSS],                   section   }, \
+                { "LimitNOFILE",            config_parse_limit,           &(context).rlimit[RLIMIT_NOFILE],                section   }, \
+                { "LimitAS",                config_parse_limit,           &(context).rlimit[RLIMIT_AS],                    section   }, \
+                { "LimitNPROC",             config_parse_limit,           &(context).rlimit[RLIMIT_NPROC],                 section   }, \
+                { "LimitMEMLOCK",           config_parse_limit,           &(context).rlimit[RLIMIT_MEMLOCK],               section   }, \
+                { "LimitLOCKS",             config_parse_limit,           &(context).rlimit[RLIMIT_LOCKS],                 section   }, \
+                { "LimitSIGPENDING",        config_parse_limit,           &(context).rlimit[RLIMIT_SIGPENDING],            section   }, \
+                { "LimitMSGQUEUE",          config_parse_limit,           &(context).rlimit[RLIMIT_MSGQUEUE],              section   }, \
+                { "LimitNICE",              config_parse_limit,           &(context).rlimit[RLIMIT_NICE],                  section   }, \
+                { "LimitRTPRIO",            config_parse_limit,           &(context).rlimit[RLIMIT_RTPRIO],                section   }, \
+                { "LimitRTTIME",            config_parse_limit,           &(context).rlimit[RLIMIT_RTTIME],                section   }, \
+                { "ControlGroup",           config_parse_cgroup,          u,                                               section   }, \
+                { "ReadWriteDirectories",   config_parse_path_strv,       &(context).read_write_dirs,                      section   }, \
+                { "ReadOnlyDirectories",    config_parse_path_strv,       &(context).read_only_dirs,                       section   }, \
+                { "InaccessibleDirectories",config_parse_path_strv,       &(context).inaccessible_dirs,                    section   }, \
+                { "PrivateTmp",             config_parse_bool,            &(context).private_tmp,                          section   }, \
+                { "MountFlags",             config_parse_mount_flags,     &(context),                                      section   }
+
+        const ConfigItem items[] = {
+                { "Names",                  config_parse_names,           u,                                               "Unit"    },
+                { "Description",            config_parse_description,     u,                                               "Unit"    },
+                { "Requires",               config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES),                      "Unit"    },
+                { "RequiresOverridable",    config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES_OVERRIDABLE),          "Unit"    },
+                { "Requisite",              config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE),                     "Unit"    },
+                { "RequisiteOverridable",   config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE),         "Unit"    },
+                { "Wants",                  config_parse_deps,            UINT_TO_PTR(UNIT_WANTS),                         "Unit"    },
+                { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Unit"    },
+                { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Unit"    },
+                { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Unit"    },
+                { "RecursiveStop",          config_parse_bool,            &u->meta.recursive_stop,                         "Unit"    },
+                { "StopWhenUnneeded",       config_parse_bool,            &u->meta.stop_when_unneeded,                     "Unit"    },
+
+                { "PIDFile",                config_parse_path,            &u->service.pid_file,                            "Service" },
+                { "ExecStartPre",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
+                { "ExecStart",              config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START,      "Service" },
+                { "ExecStartPost",          config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
+                { "ExecReload",             config_parse_exec,            u->service.exec_command+SERVICE_EXEC_RELOAD,     "Service" },
+                { "ExecStop",               config_parse_exec,            u->service.exec_command+SERVICE_EXEC_STOP,       "Service" },
+                { "ExecStopPost",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_STOP_POST,  "Service" },
+                { "RestartSec",             config_parse_usec,            &u->service.restart_usec,                        "Service" },
+                { "TimeoutSec",             config_parse_usec,            &u->service.timeout_usec,                        "Service" },
+                { "Type",                   config_parse_service_type,    &u->service.type,                                "Service" },
+                { "Restart",                config_parse_service_restart, &u->service.restart,                             "Service" },
+                { "PermissionsStartOnly",   config_parse_bool,            &u->service.permissions_start_only,              "Service" },
+                { "RootDirectoryStartOnly", config_parse_bool,            &u->service.root_directory_start_only,           "Service" },
+                { "ValidNoProcess",         config_parse_bool,            &u->service.valid_no_process,                    "Service" },
+                { "SysVStartPriority",      config_parse_sysv_priority,   &u->service.sysv_start_priority,                 "Service" },
+                { "KillMode",               config_parse_kill_mode,       &u->service.kill_mode,                           "Service" },
+                { "NonBlocking",            config_parse_bool,            &u->service.exec_context.non_blocking,           "Service" },
+                { "BusName",                config_parse_string,          &u->service.bus_name,                            "Service" },
+                EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
+
+                { "ListenStream",           config_parse_listen,          &u->socket,                                      "Socket"  },
+                { "ListenDatagram",         config_parse_listen,          &u->socket,                                      "Socket"  },
+                { "ListenSequentialPacket", config_parse_listen,          &u->socket,                                      "Socket"  },
+                { "ListenFIFO",             config_parse_listen,          &u->socket,                                      "Socket"  },
+                { "BindIPv6Only",           config_parse_socket_bind,     &u->socket,                                      "Socket"  },
+                { "Backlog",                config_parse_unsigned,        &u->socket.backlog,                              "Socket"  },
+                { "BindToDevice",           config_parse_bindtodevice,    &u->socket,                                      "Socket"  },
+                { "ExecStartPre",           config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_START_PRE,    "Socket"  },
+                { "ExecStartPost",          config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_START_POST,   "Socket"  },
+                { "ExecStopPre",            config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_STOP_PRE,     "Socket"  },
+                { "ExecStopPost",           config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_STOP_POST,    "Socket"  },
+                { "TimeoutSec",             config_parse_usec,            &u->socket.timeout_usec,                         "Socket"  },
+                { "DirectoryMode",          config_parse_mode,            &u->socket.directory_mode,                       "Socket"  },
+                { "SocketMode",             config_parse_mode,            &u->socket.socket_mode,                          "Socket"  },
+                { "KillMode",               config_parse_kill_mode,       &u->socket.kill_mode,                            "Socket"  },
+                { "Accept",                 config_parse_bool,            &u->socket.accept,                               "Socket"  },
+                EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
+
+                { "What",                   config_parse_string,          &u->mount.parameters_fragment.what,              "Mount"   },
+                { "Where",                  config_parse_path,            &u->mount.where,                                 "Mount"   },
+                { "Options",                config_parse_string,          &u->mount.parameters_fragment.options,           "Mount"   },
+                { "Type",                   config_parse_string,          &u->mount.parameters_fragment.fstype,            "Mount"   },
+                { "TimeoutSec",             config_parse_usec,            &u->mount.timeout_usec,                          "Mount"   },
+                { "KillMode",               config_parse_kill_mode,       &u->mount.kill_mode,                             "Mount"   },
+                EXEC_CONTEXT_CONFIG_ITEMS(u->mount.exec_context, "Mount"),
+
+                { "Where",                  config_parse_path,            &u->automount.where,                             "Automount" },
+
+                { "What",                   config_parse_path,            &u->swap.parameters_fragment.what,               "Swap" },
+                { "Priority",               config_parse_int,             &u->swap.parameters_fragment.priority,           "Swap" },
+
+                { NULL, NULL, NULL, NULL }
+        };
+
+#undef EXEC_CONTEXT_CONFIG_ITEMS
+
+        const char *sections[3];
+        char *k;
+        int r;
+        Set *symlink_names;
+        FILE *f = NULL;
+        char *filename = NULL, *id = NULL;
+        Unit *merged;
+
+        if (!u) {
+                /* Dirty dirty hack. */
+                dump_items((FILE*) path, items);
+                return 0;
+        }
+
+        assert(u);
+        assert(path);
+
+        sections[0] = "Unit";
+        sections[1] = section_table[u->meta.type];
+        sections[2] = NULL;
+
+        if (!(symlink_names = set_new(string_hash_func, string_compare_func)))
+                return -ENOMEM;
+
+        if (path_is_absolute(path)) {
+
+                if (!(filename = strdup(path))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
+                        free(filename);
+                        filename = NULL;
+
+                        if (r != -ENOENT)
+                                goto finish;
+                }
+
+        } else  {
+                char **p;
+
+                STRV_FOREACH(p, u->meta.manager->unit_path) {
+
+                        /* Instead of opening the path right away, we manually
+                         * follow all symlinks and add their name to our unit
+                         * name set while doing so */
+                        if (!(filename = path_make_absolute(path, *p))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
+                                char *sn;
+
+                                free(filename);
+                                filename = NULL;
+
+                                if (r != -ENOENT)
+                                        goto finish;
+
+                                /* Empty the symlink names for the next run */
+                                while ((sn = set_steal_first(symlink_names)))
+                                        free(sn);
+
+                                continue;
+                        }
+
+                        break;
+                }
+        }
+
+        if (!filename) {
+                r = 0;
+                goto finish;
+        }
+
+        merged = u;
+        if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
+                goto finish;
+
+        if (merged != u) {
+                u->meta.load_state = UNIT_MERGED;
+                r = 0;
+                goto finish;
+        }
+
+        /* Now, parse the file contents */
+        if ((r = config_parse(filename, f, sections, items, u)) < 0)
+                goto finish;
+
+        free(u->meta.fragment_path);
+        u->meta.fragment_path = filename;
+        filename = NULL;
+
+        u->meta.load_state = UNIT_LOADED;
+        r = 0;
+
+finish:
+        while ((k = set_steal_first(symlink_names)))
+                free(k);
+
+        set_free(symlink_names);
+        free(filename);
+
+        if (f)
+                fclose(f);
+
+        return r;
+}
+
+int unit_load_fragment(Unit *u) {
+        int r;
+
+        assert(u);
+
+        if (u->meta.fragment_path) {
+
+                if ((r = load_from_path(u, u->meta.fragment_path)) < 0)
+                        return r;
+
+        } else {
+                Iterator i;
+                const char *t;
+
+                /* Try to find the unit under its id */
+                if ((r = load_from_path(u, u->meta.id)) < 0)
+                        return r;
+
+                /* Try to find an alias we can load this with */
+                if (u->meta.load_state == UNIT_STUB)
+                        SET_FOREACH(t, u->meta.names, i) {
+
+                                if (t == u->meta.id)
+                                        continue;
+
+                                if ((r = load_from_path(u, t)) < 0)
+                                        return r;
+
+                                if (u->meta.load_state != UNIT_STUB)
+                                        break;
+                        }
+
+                /* Now, follow the same logic, but look for a template */
+                if (u->meta.load_state == UNIT_STUB && u->meta.instance) {
+                        char *k;
+
+                        if (!(k = unit_name_template(u->meta.id)))
+                                return -ENOMEM;
+
+                        r = load_from_path(u, k);
+                        free(k);
+
+                        if (r < 0)
+                                return r;
+
+                        if (u->meta.load_state == UNIT_STUB)
+                                SET_FOREACH(t, u->meta.names, i) {
+
+                                        if (t == u->meta.id)
+                                                continue;
+
+                                        if (!(k = unit_name_template(t)))
+                                                return -ENOMEM;
+
+                                        r = load_from_path(u, k);
+                                        free(k);
+
+                                        if (r < 0)
+                                                return r;
+
+                                        if (u->meta.load_state != UNIT_STUB)
+                                                break;
+                                }
+                }
+        }
+
+        return 0;
+}
+
+void unit_dump_config_items(FILE *f) {
+        /* OK, this wins a prize for extreme ugliness. */
+
+        load_from_path(NULL, (const void*) f);
+}
diff --git a/src/load-fragment.h b/src/load-fragment.h
new file mode 100644
index 0000000..beba87c
--- /dev/null
+++ b/src/load-fragment.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooloadfragmenthfoo
+#define fooloadfragmenthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "unit.h"
+
+/* Read service data from .desktop file style configuration fragments */
+
+int unit_load_fragment(Unit *u);
+
+void unit_dump_config_items(FILE *f);
+
+#endif
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..5d17955
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,439 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+
+#define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC)
+#define LOG_BUFFER_MAX 1024
+
+static LogTarget log_target = LOG_TARGET_CONSOLE;
+static int log_max_level = LOG_DEBUG;
+
+static int console_fd = STDERR_FILENO;
+static int syslog_fd = -1;
+static int kmsg_fd = -1;
+
+/* Akin to glibc's __abort_msg; which is private and we hance cannot
+ * use here. */
+static char *log_abort_msg = NULL;
+
+void log_close_console(void) {
+
+        if (console_fd < 0)
+                return;
+
+        if (getpid() == 1 || console_fd != STDERR_FILENO) {
+                close_nointr_nofail(console_fd);
+                console_fd = -1;
+        }
+}
+
+static int log_open_console(void) {
+
+        if (console_fd >= 0)
+                return 0;
+
+        if (getpid() == 1) {
+
+                if ((console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
+                        log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
+                        return console_fd;
+                }
+
+                log_info("Succesfully opened /dev/console for logging.");
+        } else
+                console_fd = STDERR_FILENO;
+
+        return 0;
+}
+
+void log_close_kmsg(void) {
+
+        if (kmsg_fd < 0)
+                return;
+
+        close_nointr_nofail(kmsg_fd);
+        kmsg_fd = -1;
+}
+
+static int log_open_kmsg(void) {
+
+        if (kmsg_fd >= 0)
+                return 0;
+
+        if ((kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
+                log_info("Failed to open /dev/kmsg for logging: %s", strerror(errno));
+                return -errno;
+        }
+
+        log_info("Succesfully opened /dev/kmsg for logging.");
+
+        return 0;
+}
+
+void log_close_syslog(void) {
+
+        if (syslog_fd < 0)
+                return;
+
+        close_nointr_nofail(syslog_fd);
+        syslog_fd = -1;
+}
+
+static int log_open_syslog(void) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_un un;
+        } sa;
+        struct timeval tv;
+        int r;
+
+        if (syslog_fd >= 0)
+                return 0;
+
+        if ((syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* Make sure we don't block for more than 5s when talking to
+         * syslog */
+        timeval_store(&tv, SYSLOG_TIMEOUT_USEC);
+        if (setsockopt(syslog_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        zero(sa);
+        sa.un.sun_family = AF_UNIX;
+        strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
+
+        if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        log_info("Succesfully opened syslog for logging.");
+
+        return 0;
+
+fail:
+        log_close_syslog();
+        log_info("Failed to open syslog for logging: %s", strerror(-r));
+        return r;
+}
+
+int log_open(void) {
+        int r;
+
+        /* If we don't use the console we close it here, to not get
+         * killed by SAK. If we don't use syslog we close it here so
+         * that we are not confused by somebody deleting the socket in
+         * the fs. If we don't use /dev/kmsg we still keep it open,
+         * because there is no reason to close it. */
+
+        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
+            log_target == LOG_TARGET_SYSLOG)
+                if ((r = log_open_syslog()) >= 0) {
+                        log_close_console();
+                        return r;
+                }
+
+        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
+            log_target == LOG_TARGET_KMSG)
+                if ((r = log_open_kmsg()) >= 0) {
+                        log_close_syslog();
+                        log_close_console();
+                        return r;
+                }
+
+        log_close_syslog();
+        return log_open_console();
+}
+
+void log_set_target(LogTarget target) {
+        assert(target >= 0);
+        assert(target < _LOG_TARGET_MAX);
+
+        log_target = target;
+}
+
+void log_set_max_level(int level) {
+        assert((level & LOG_PRIMASK) == level);
+
+        log_max_level = level;
+}
+
+static int write_to_console(
+        int level,
+        const char*file,
+        int line,
+        const char *func,
+        const char *buffer) {
+
+        char location[64];
+        struct iovec iovec[5];
+        unsigned n = 0;
+        bool highlight;
+
+        if (console_fd < 0)
+                return 0;
+
+        snprintf(location, sizeof(location), "(%s:%u) ", file, line);
+        char_array_0(location);
+
+        highlight = LOG_PRI(level) <= LOG_ERR;
+
+        zero(iovec);
+        IOVEC_SET_STRING(iovec[n++], location);
+        if (highlight)
+                IOVEC_SET_STRING(iovec[n++], "\x1B[1;31m");
+        IOVEC_SET_STRING(iovec[n++], buffer);
+        if (highlight)
+                IOVEC_SET_STRING(iovec[n++], "\x1B[0m");
+        IOVEC_SET_STRING(iovec[n++], "\n");
+
+        if (writev(console_fd, iovec, n) < 0)
+                return -errno;
+
+        return 1;
+}
+
+static int write_to_syslog(
+        int level,
+        const char*file,
+        int line,
+        const char *func,
+        const char *buffer) {
+
+        char header_priority[16], header_time[64], header_pid[16];
+        struct iovec iovec[5];
+        struct msghdr msghdr;
+        time_t t;
+        struct tm *tm;
+
+        if (syslog_fd < 0)
+                return 0;
+
+        snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(level)));
+        char_array_0(header_priority);
+
+        t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
+        if (!(tm = localtime(&t)))
+                return -EINVAL;
+
+        if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
+                return -EINVAL;
+
+        snprintf(header_pid, sizeof(header_pid), "[%llu]: ", (unsigned long long) getpid());
+        char_array_0(header_pid);
+
+        zero(iovec);
+        IOVEC_SET_STRING(iovec[0], header_priority);
+        IOVEC_SET_STRING(iovec[1], header_time);
+        IOVEC_SET_STRING(iovec[2], __progname);
+        IOVEC_SET_STRING(iovec[3], header_pid);
+        IOVEC_SET_STRING(iovec[4], buffer);
+
+        zero(msghdr);
+        msghdr.msg_iov = iovec;
+        msghdr.msg_iovlen = ELEMENTSOF(iovec);
+
+        if (sendmsg(syslog_fd, &msghdr, 0) < 0)
+                return -errno;
+
+        return 1;
+}
+
+static int write_to_kmsg(
+        int level,
+        const char*file,
+        int line,
+        const char *func,
+        const char *buffer) {
+
+        char header_priority[16], header_pid[16];
+        struct iovec iovec[5];
+
+        if (kmsg_fd < 0)
+                return 0;
+
+        snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_PRI(level));
+        char_array_0(header_priority);
+
+        snprintf(header_pid, sizeof(header_pid), "[%llu]: ", (unsigned long long) getpid());
+        char_array_0(header_pid);
+
+        zero(iovec);
+        IOVEC_SET_STRING(iovec[0], header_priority);
+        IOVEC_SET_STRING(iovec[1], __progname);
+        IOVEC_SET_STRING(iovec[2], header_pid);
+        IOVEC_SET_STRING(iovec[3], buffer);
+        IOVEC_SET_STRING(iovec[4], "\n");
+
+        if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
+                return -errno;
+
+        return 1;
+}
+
+static int log_dispatch(
+        int level,
+        const char*file,
+        int line,
+        const char *func,
+        const char *buffer) {
+
+        int r;
+
+        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
+            log_target == LOG_TARGET_SYSLOG) {
+
+                if ((r = write_to_syslog(level, file, line, func, buffer)) < 0) {
+                        log_close_syslog();
+                        log_open_kmsg();
+                } else if (r > 0)
+                        return r;
+        }
+
+        if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
+            log_target == LOG_TARGET_KMSG) {
+
+                if ((r = write_to_kmsg(level, file, line, func, buffer)) < 0) {
+                        log_close_kmsg();
+                        log_open_console();
+                } else if (r > 0)
+                        return r;
+        }
+
+        return write_to_console(level, file, line, func, buffer);
+}
+
+int log_meta(
+        int level,
+        const char*file,
+        int line,
+        const char *func,
+        const char *format, ...) {
+
+        char buffer[LOG_BUFFER_MAX];
+        int saved_errno, r;
+        va_list ap;
+
+        if (_likely(LOG_PRI(level) > log_max_level))
+                return 0;
+
+        saved_errno = errno;
+
+        va_start(ap, format);
+        vsnprintf(buffer, sizeof(buffer), format, ap);
+        va_end(ap);
+
+        char_array_0(buffer);
+
+        r = log_dispatch(level, file, line, func, buffer);
+        errno = saved_errno;
+
+        return r;
+}
+
+void log_assert(
+        const char*file,
+        int line,
+        const char *func,
+        const char *format, ...) {
+
+        static char buffer[LOG_BUFFER_MAX];
+        int saved_errno = errno;
+        va_list ap;
+
+        va_start(ap, format);
+        vsnprintf(buffer, sizeof(buffer), format, ap);
+        va_end(ap);
+
+        char_array_0(buffer);
+        log_abort_msg = buffer;
+
+        log_dispatch(LOG_CRIT, file, line, func, buffer);
+        abort();
+
+        /* If the user chose to ignore this SIGABRT, we are happy to go on, as if nothing happened. */
+        errno = saved_errno;
+}
+
+int log_set_target_from_string(const char *e) {
+        LogTarget t;
+
+        if ((t = log_target_from_string(e)) < 0)
+                return -EINVAL;
+
+        log_set_target(t);
+        return 0;
+}
+
+int log_set_max_level_from_string(const char *e) {
+        int t;
+
+        if ((t = log_level_from_string(e)) < 0)
+                return -EINVAL;
+
+        log_set_max_level(t);
+        return 0;
+}
+
+void log_parse_environment(void) {
+        const char *e;
+
+        if ((e = getenv("SYSTEMD_LOG_TARGET")))
+                if (log_set_target_from_string(e) < 0)
+                        log_warning("Failed to parse log target %s. Ignoring.", e);
+
+        if ((e = getenv("SYSTEMD_LOG_LEVEL")))
+                if (log_set_max_level_from_string(e) < 0)
+                        log_warning("Failed to parse log level %s. Ignoring.", e);
+}
+
+LogTarget log_get_target(void) {
+        return log_target;
+}
+
+int log_get_max_level(void) {
+        return log_max_level;
+}
+
+static const char *const log_target_table[] = {
+        [LOG_TARGET_CONSOLE] = "console",
+        [LOG_TARGET_SYSLOG] = "syslog",
+        [LOG_TARGET_KMSG] = "kmsg",
+        [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..6df1d59
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,79 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foologhfoo
+#define foologhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <syslog.h>
+
+#include "macro.h"
+
+/* If set to SYSLOG and /dev/log can not be opened we fall back to
+ * KSMG. If KMSG fails, we fall back to CONSOLE */
+typedef enum LogTarget{
+        LOG_TARGET_CONSOLE,
+        LOG_TARGET_KMSG,
+        LOG_TARGET_SYSLOG,
+        LOG_TARGET_SYSLOG_OR_KMSG,
+        _LOG_TARGET_MAX,
+        _LOG_TARGET_INVALID = -1
+}  LogTarget;
+
+void log_set_target(LogTarget target);
+void log_set_max_level(int level);
+
+int log_set_target_from_string(const char *e);
+int log_set_max_level_from_string(const char *e);
+
+LogTarget log_get_target(void);
+int log_get_max_level(void);
+
+int log_open(void);
+
+void log_close_syslog(void);
+void log_close_kmsg(void);
+void log_close_console(void);
+
+void log_parse_environment(void);
+
+int log_meta(
+        int level,
+        const char*file,
+        int line,
+        const char *func,
+        const char *format, ...) _printf_attr(5,6);
+
+_noreturn void log_assert(
+        const char*file,
+        int line,
+        const char *func,
+        const char *format, ...) _printf_attr(4,5);
+
+#define log_debug(...)   log_meta(LOG_DEBUG,   __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_info(...)    log_meta(LOG_INFO,    __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_notice(...)  log_meta(LOG_NOTICE,  __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_error(...)   log_meta(LOG_ERR,     __FILE__, __LINE__, __func__, __VA_ARGS__)
+
+const char *log_target_to_string(LogTarget target);
+LogTarget log_target_from_string(const char *s);
+
+#endif
diff --git a/src/logger.c b/src/logger.c
new file mode 100644
index 0000000..f81d2c5
--- /dev/null
+++ b/src/logger.c
@@ -0,0 +1,565 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "log.h"
+#include "list.h"
+#include "sd-daemon.h"
+
+#define STREAM_BUFFER 2048
+#define STREAMS_MAX 256
+#define SERVER_FD_MAX 16
+#define TIMEOUT ((int) (10*MSEC_PER_SEC))
+
+typedef struct Stream Stream;
+
+typedef struct Server {
+        int syslog_fd;
+        int kmsg_fd;
+        int epoll_fd;
+
+        unsigned n_server_fd;
+
+        LIST_HEAD(Stream, streams);
+        unsigned n_streams;
+} Server;
+
+typedef enum StreamTarget {
+        STREAM_SYSLOG,
+        STREAM_KMSG
+} StreamTarget;
+
+typedef enum StreamState {
+        STREAM_TARGET,
+        STREAM_PRIORITY,
+        STREAM_PROCESS,
+        STREAM_PREFIX,
+        STREAM_RUNNING
+} StreamState;
+
+struct Stream {
+        Server *server;
+
+        StreamState state;
+
+        int fd;
+
+        LogTarget target;
+        int priority;
+        char *process;
+        pid_t pid;
+        uid_t uid;
+
+        bool prefix;
+
+        char buffer[STREAM_BUFFER];
+        size_t length;
+
+        LIST_FIELDS(Stream, stream);
+};
+
+static int stream_log(Stream *s, char *p, usec_t timestamp) {
+
+        char header_priority[16], header_time[64], header_pid[16];
+        struct iovec iovec[5];
+        int priority;
+
+        assert(s);
+        assert(p);
+
+        priority = s->priority;
+
+        if (s->prefix &&
+            p[0] == '<' &&
+            p[1] >= '0' && p[1] <= '7' &&
+            p[2] == '>') {
+
+                /* Detected priority prefix */
+                priority = LOG_MAKEPRI(LOG_FAC(priority), (p[1] - '0'));
+
+                p += 3;
+        }
+
+        if (*p == 0)
+                return 0;
+
+        /*
+         * The format glibc uses to talk to the syslog daemon is:
+         *
+         *     <priority>time process[pid]: msg
+         *
+         * The format the kernel uses is:
+         *
+         *     <priority>msg\n
+         *
+         *  We extend the latter to include the process name and pid.
+         */
+
+        snprintf(header_priority, sizeof(header_priority), "<%i>",
+                 s->target == STREAM_SYSLOG ? priority : LOG_PRI(priority));
+        char_array_0(header_priority);
+
+        if (s->target == STREAM_SYSLOG) {
+                time_t t;
+                struct tm *tm;
+
+                t = (time_t) (timestamp / USEC_PER_SEC);
+                if (!(tm = localtime(&t)))
+                        return -EINVAL;
+
+                if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
+                        return -EINVAL;
+        }
+
+        snprintf(header_pid, sizeof(header_pid), "[%llu]: ", (unsigned long long) s->pid);
+        char_array_0(header_pid);
+
+        zero(iovec);
+        IOVEC_SET_STRING(iovec[0], header_priority);
+
+        if (s->target == STREAM_SYSLOG) {
+                struct msghdr msghdr;
+
+                IOVEC_SET_STRING(iovec[1], header_time);
+                IOVEC_SET_STRING(iovec[2], s->process);
+                IOVEC_SET_STRING(iovec[3], header_pid);
+                IOVEC_SET_STRING(iovec[4], p);
+
+                zero(msghdr);
+                msghdr.msg_iov = iovec;
+                msghdr.msg_iovlen = ELEMENTSOF(iovec);
+
+                if (sendmsg(s->server->syslog_fd, &msghdr, MSG_NOSIGNAL) < 0)
+                        return -errno;
+
+        } else if (s->target == STREAM_KMSG) {
+                IOVEC_SET_STRING(iovec[1], s->process);
+                IOVEC_SET_STRING(iovec[2], header_pid);
+                IOVEC_SET_STRING(iovec[3], p);
+                IOVEC_SET_STRING(iovec[4], (char*) "\n");
+
+                if (writev(s->server->kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
+                        return -errno;
+        } else
+                assert_not_reached("Unknown log target");
+
+        return 0;
+}
+
+static int stream_line(Stream *s, char *p, usec_t timestamp) {
+        int r;
+
+        assert(s);
+        assert(p);
+
+        p = strstrip(p);
+
+        switch (s->state) {
+
+        case STREAM_TARGET:
+                if (streq(p, "syslog"))
+                        s->target = STREAM_SYSLOG;
+                else if (streq(p, "kmsg")) {
+
+                        if (s->server->kmsg_fd >= 0 && s->uid == 0)
+                                s->target = STREAM_KMSG;
+                        else {
+                                log_warning("/dev/kmsg logging not available.");
+                                return -EPERM;
+                        }
+                } else {
+                        log_warning("Failed to parse log target line.");
+                        return -EBADMSG;
+                }
+                s->state = STREAM_PRIORITY;
+                return 0;
+
+        case STREAM_PRIORITY:
+                if ((r = safe_atoi(p, &s->priority)) < 0) {
+                        log_warning("Failed to parse log priority line: %s", strerror(errno));
+                        return r;
+                }
+
+                if (s->priority < 0) {
+                        log_warning("Log priority negative: %s", strerror(errno));
+                        return -ERANGE;
+                }
+
+                s->state = STREAM_PROCESS;
+                return 0;
+
+        case STREAM_PROCESS:
+                if (!(s->process = strdup(p)))
+                        return -ENOMEM;
+
+                s->state = STREAM_PREFIX;
+                return 0;
+
+        case STREAM_PREFIX:
+
+                if ((r = parse_boolean(p)) < 0)
+                        return r;
+
+                s->prefix = r;
+                s->state = STREAM_RUNNING;
+                return 0;
+
+        case STREAM_RUNNING:
+                return stream_log(s, p, timestamp);
+        }
+
+        assert_not_reached("Unknown stream state");
+}
+
+static int stream_scan(Stream *s, usec_t timestamp) {
+        char *p;
+        size_t remaining;
+        int r = 0;
+
+        assert(s);
+
+        p = s->buffer;
+        remaining = s->length;
+        for (;;) {
+                char *newline;
+
+                if (!(newline = memchr(p, '\n', remaining)))
+                        break;
+
+                *newline = 0;
+
+                if ((r = stream_line(s, p, timestamp)) >= 0) {
+                        remaining -= newline-p+1;
+                        p = newline+1;
+                }
+        }
+
+        if (p > s->buffer) {
+                memmove(s->buffer, p, remaining);
+                s->length = remaining;
+        }
+
+        return r;
+}
+
+static int stream_process(Stream *s, usec_t timestamp) {
+        ssize_t l;
+        int r;
+        assert(s);
+
+        if ((l = read(s->fd, s->buffer+s->length, STREAM_BUFFER-s->length)) < 0) {
+
+                if (errno == EAGAIN)
+                        return 0;
+
+                log_warning("Failed to read from stream: %s", strerror(errno));
+                return -1;
+        }
+
+
+        if (l == 0)
+                return 0;
+
+        s->length += l;
+        r = stream_scan(s, timestamp);
+
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static void stream_free(Stream *s) {
+        assert(s);
+
+        if (s->server) {
+                assert(s->server->n_streams > 0);
+                s->server->n_streams--;
+                LIST_REMOVE(Stream, stream, s->server->streams, s);
+
+        }
+
+        if (s->fd >= 0) {
+                if (s->server)
+                        epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
+
+                close_nointr_nofail(s->fd);
+        }
+
+        free(s->process);
+        free(s);
+}
+
+static int stream_new(Server *s, int server_fd) {
+        Stream *stream;
+        int fd;
+        struct ucred ucred;
+        socklen_t len = sizeof(ucred);
+        struct epoll_event ev;
+        int r;
+
+        assert(s);
+
+        if ((fd = accept4(server_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC)) < 0)
+                return -errno;
+
+        if (s->n_streams >= STREAMS_MAX) {
+                log_warning("Too many connections, refusing connection.");
+                close_nointr_nofail(fd);
+                return 0;
+        }
+
+        if (!(stream = new0(Stream, 1))) {
+                close_nointr_nofail(fd);
+                return -ENOMEM;
+        }
+
+        stream->fd = fd;
+
+        if (getsockopt(stream->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if (shutdown(fd, SHUT_WR) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        zero(ev);
+        ev.data.ptr = stream;
+        ev.events = EPOLLIN;
+        if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        stream->pid = ucred.pid;
+        stream->uid = ucred.uid;
+
+        stream->server = s;
+        LIST_PREPEND(Stream, stream, s->streams, stream);
+        s->n_streams ++;
+
+        return 0;
+
+fail:
+        stream_free(stream);
+        return r;
+}
+
+static void server_done(Server *s) {
+        unsigned i;
+        assert(s);
+
+        while (s->streams)
+                stream_free(s->streams);
+
+        for (i = 0; i < s->n_server_fd; i++)
+                close_nointr_nofail(SD_LISTEN_FDS_START+i);
+
+        if (s->syslog_fd >= 0)
+                close_nointr_nofail(s->syslog_fd);
+
+        if (s->epoll_fd >= 0)
+                close_nointr_nofail(s->epoll_fd);
+
+        if (s->kmsg_fd >= 0)
+                close_nointr_nofail(s->kmsg_fd);
+}
+
+static int server_init(Server *s, unsigned n_sockets) {
+        int r;
+        unsigned i;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_un un;
+        } sa;
+
+        assert(s);
+        assert(n_sockets > 0);
+
+        zero(*s);
+
+        s->n_server_fd = n_sockets;
+        s->syslog_fd = -1;
+        s->kmsg_fd = -1;
+
+        if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
+                r = -errno;
+                log_error("Failed to create epoll object: %s", strerror(errno));
+                goto fail;
+        }
+
+        for (i = 0; i < n_sockets; i++) {
+                struct epoll_event ev;
+
+                zero(ev);
+                ev.events = EPOLLIN;
+                ev.data.ptr = UINT_TO_PTR(SD_LISTEN_FDS_START+i);
+                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) {
+                        r = -errno;
+                        log_error("Failed to add server fd to epoll object: %s", strerror(errno));
+                        goto fail;
+                }
+        }
+
+        if ((s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
+                r = -errno;
+                log_error("Failed to create log fd: %s", strerror(errno));
+                goto fail;
+        }
+
+        zero(sa);
+        sa.un.sun_family = AF_UNIX;
+        strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
+
+        if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+                r = -errno;
+                log_error("Failed to connect log socket to /dev/log: %s", strerror(errno));
+                goto fail;
+        }
+
+        /* /dev/kmsg logging is strictly optional */
+        if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
+                log_debug("Failed to open /dev/kmsg for logging, disabling kernel log buffer support: %s", strerror(errno));
+
+        return 0;
+
+fail:
+        server_done(s);
+        return r;
+}
+
+static int process_event(Server *s, struct epoll_event *ev) {
+        int r;
+
+        assert(s);
+
+        /* Yes, this is a bit ugly, we assume that that valid pointers
+         * are > SD_LISTEN_FDS_START+SERVER_FD_MAX. Which is certainly
+         * true on Linux (and probably most other OSes, too, since the
+         * first 4k usually are part of a seperate null pointer
+         * dereference page. */
+
+        if (PTR_TO_UINT(ev->data.ptr) >= SD_LISTEN_FDS_START &&
+            PTR_TO_UINT(ev->data.ptr) < SD_LISTEN_FDS_START+s->n_server_fd) {
+
+                if (ev->events != EPOLLIN) {
+                        log_info("Got invalid event from epoll. (1)");
+                        return -EIO;
+                }
+
+                if ((r = stream_new(s, PTR_TO_UINT(ev->data.ptr))) < 0) {
+                        log_info("Failed to accept new connection: %s", strerror(-r));
+                        return r;
+                }
+
+        } else {
+                usec_t timestamp;
+                Stream *stream = ev->data.ptr;
+
+                timestamp = now(CLOCK_REALTIME);
+
+                if (!(ev->events & EPOLLIN)) {
+                        log_info("Got invalid event from epoll. (2)");
+                        stream_free(stream);
+                        return 0;
+                }
+
+                if ((r = stream_process(stream, timestamp)) <= 0) {
+
+                        if (r < 0)
+                                log_info("Got error on stream: %s", strerror(-r));
+
+                        stream_free(stream);
+                        return 0;
+                }
+        }
+
+        return 0;
+}
+
+int main(int argc, char *argv[]) {
+        Server server;
+        int r = 3, n;
+
+        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        log_parse_environment();
+
+        log_info("systemd-logger running as pid %llu", (unsigned long long) getpid());
+
+        if ((n = sd_listen_fds(true)) < 0) {
+                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
+                return 1;
+        }
+
+        if (n <= 0 || n > SERVER_FD_MAX) {
+                log_error("No or too many file descriptors passed.");
+                return 2;
+        }
+
+        if (server_init(&server, (unsigned) n) < 0)
+                return 3;
+
+        for (;;) {
+                struct epoll_event event;
+                int k;
+
+                if ((k = epoll_wait(server.epoll_fd,
+                                    &event, 1,
+                                    server.n_streams <= 0 ? TIMEOUT : -1)) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        log_error("epoll_wait() failed: %s", strerror(errno));
+                        goto fail;
+                }
+
+                if (k <= 0)
+                        break;
+
+                if ((k = process_event(&server, &event)) < 0)
+                        goto fail;
+        }
+        r = 0;
+
+fail:
+        server_done(&server);
+
+        log_info("systemd-logger stopped as pid %llu", (unsigned long long) getpid());
+
+        return r;
+}
diff --git a/src/loopback-setup.c b/src/loopback-setup.c
new file mode 100644
index 0000000..e37bf41
--- /dev/null
+++ b/src/loopback-setup.c
@@ -0,0 +1,276 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <asm/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "util.h"
+#include "macro.h"
+#include "loopback-setup.h"
+
+enum {
+        REQUEST_NONE = 0,
+        REQUEST_ADDRESS_IPV4 = 1,
+        REQUEST_ADDRESS_IPV6 = 2,
+        REQUEST_FLAGS = 4,
+        REQUEST_ALL = 7
+};
+
+#define NLMSG_TAIL(nmsg)                                                \
+        ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) {
+        size_t length;
+        struct rtattr *rta;
+
+        length = RTA_LENGTH(data_length);
+
+        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
+                return -E2BIG;
+
+        rta = NLMSG_TAIL(n);
+        rta->rta_type = type;
+        rta->rta_len = length;
+        memcpy(RTA_DATA(rta), data, data_length);
+        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
+
+        return 0;
+}
+
+static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) {
+
+        for (;;) {
+                ssize_t l;
+
+                if ((l = sendto(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
+                        return l;
+
+                if (errno != EINTR)
+                        return -errno;
+        }
+}
+
+static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) {
+
+        for (;;) {
+                ssize_t l;
+
+                if ((l = recvfrom(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
+                        return l;
+
+                if (errno != EINTR)
+                        return -errno;
+        }
+}
+
+static int add_adresses(int fd, int if_loopback) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sa;
+        union {
+                struct nlmsghdr header;
+                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                            NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
+                            RTA_LENGTH(sizeof(struct in6_addr))];
+        } request;
+
+        struct ifaddrmsg *ifaddrmsg;
+        uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
+        int r;
+
+        zero(request);
+
+        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        request.header.nlmsg_type = RTM_NEWADDR;
+        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
+        request.header.nlmsg_seq = REQUEST_ADDRESS_IPV4;
+
+        ifaddrmsg = NLMSG_DATA(&request.header);
+        ifaddrmsg->ifa_family = AF_INET;
+        ifaddrmsg->ifa_prefixlen = 8;
+        ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
+        ifaddrmsg->ifa_scope = RT_SCOPE_HOST;
+        ifaddrmsg->ifa_index = if_loopback;
+
+        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address))) < 0)
+                return r;
+
+        zero(sa);
+        sa.nl.nl_family = AF_NETLINK;
+
+        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
+                return -errno;
+
+        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        request.header.nlmsg_seq = REQUEST_ADDRESS_IPV6;
+
+        ifaddrmsg->ifa_family = AF_INET6;
+        ifaddrmsg->ifa_prefixlen = 128;
+
+        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback))) < 0)
+                return r;
+
+        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int start_interface(int fd, int if_loopback) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sa;
+        union {
+                struct nlmsghdr header;
+                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                            NLMSG_ALIGN(sizeof(struct ifinfomsg))];
+        } request;
+
+        struct ifinfomsg *ifinfomsg;
+
+        zero(request);
+
+        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+        request.header.nlmsg_type = RTM_NEWLINK;
+        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+        request.header.nlmsg_seq = REQUEST_FLAGS;
+
+        ifinfomsg = NLMSG_DATA(&request.header);
+        ifinfomsg->ifi_family = AF_UNSPEC;
+        ifinfomsg->ifi_index = if_loopback;
+        ifinfomsg->ifi_flags = IFF_UP;
+        ifinfomsg->ifi_change = IFF_UP;
+
+        zero(sa);
+        sa.nl.nl_family = AF_NETLINK;
+
+        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int read_response(int fd) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sa;
+        union {
+                struct nlmsghdr header;
+                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                            NLMSG_ALIGN(sizeof(struct nlmsgerr))];
+        } response;
+
+        ssize_t l;
+        socklen_t sa_len = sizeof(sa);
+        struct nlmsgerr *nlmsgerr;
+
+        if ((l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len)) < 0)
+                return -errno;
+
+        if (sa_len != sizeof(sa.nl) ||
+            sa.nl.nl_family != AF_NETLINK)
+                return -EIO;
+
+        if (sa.nl.nl_pid != 0)
+                return 0;
+
+        if ((size_t) l < sizeof(struct nlmsghdr))
+                return -EIO;
+
+        if (response.header.nlmsg_type != NLMSG_ERROR ||
+            (pid_t) response.header.nlmsg_pid != getpid() ||
+            response.header.nlmsg_seq >= REQUEST_ALL)
+                return 0;
+
+        if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
+            response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+                return -EIO;
+
+        nlmsgerr = NLMSG_DATA(&response.header);
+
+        if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST)
+                return nlmsgerr->error;
+
+        return response.header.nlmsg_seq;
+}
+
+int loopback_setup(void) {
+        int r, if_loopback;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+                struct sockaddr_storage storage;
+        } sa;
+        int requests = REQUEST_NONE;
+
+        int fd;
+
+        errno = 0;
+        if ((if_loopback = (int) if_nametoindex("lo")) <= 0)
+                return errno ? -errno : -ENODEV;
+
+        if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
+                return -errno;
+
+        zero(sa);
+        sa.nl.nl_family = AF_NETLINK;
+
+        if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if ((r = add_adresses(fd, if_loopback)) < 0)
+                goto finish;
+
+        if ((r = start_interface(fd, if_loopback)) < 0)
+                goto finish;
+
+        do {
+                if ((r = read_response(fd)) < 0)
+                        goto finish;
+
+                requests |= r;
+
+        } while (requests != REQUEST_ALL);
+
+        r = 0;
+
+finish:
+        if (r < 0)
+                log_error("Failed to configure loopback device: %s", strerror(-r));
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
diff --git a/src/loopback-setup.h b/src/loopback-setup.h
new file mode 100644
index 0000000..b4614fa
--- /dev/null
+++ b/src/loopback-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooloopbacksetuphfoo
+#define fooloopbacksetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int loopback_setup(void);
+
+#endif
diff --git a/src/macro.h b/src/macro.h
new file mode 100644
index 0000000..622c08e
--- /dev/null
+++ b/src/macro.h
@@ -0,0 +1,130 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foomacrohfoo
+#define foomacrohfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <sys/types.h>
+
+#define _printf_attr(a,b) __attribute__ ((format (printf, a, b)))
+#define _sentinel __attribute__ ((sentinel))
+#define _noreturn __attribute__((noreturn))
+#define _unused __attribute__ ((unused))
+#define _destructor __attribute__ ((destructor))
+#define _pure __attribute__ ((pure))
+#define _const __attribute__ ((const))
+#define _deprecated __attribute__ ((deprecated))
+#define _packed __attribute__ ((packed))
+#define _malloc __attribute__ ((malloc))
+#define _weak __attribute__ ((weak))
+#define _likely(x) (__builtin_expect(!!(x),1))
+#define _unlikely(x) (__builtin_expect(!!(x),0))
+
+/* Rounds up */
+static inline size_t ALIGN(size_t l) {
+        return ((l + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
+}
+
+#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
+
+#define MAX(a,b)                                \
+        __extension__ ({                        \
+                        typeof(a) _a = (a);     \
+                        typeof(b) _b = (b);     \
+                        _a > _b ? _a : _b;      \
+                })
+
+#define MIN(a,b)                                \
+        __extension__ ({                        \
+                        typeof(a) _a = (a);     \
+                        typeof(b) _b = (b);     \
+                        _a < _b ? _a : _b;      \
+                })
+
+#define CLAMP(x, low, high)                                             \
+        __extension__ ({                                                \
+                        typeof(x) _x = (x);                             \
+                        typeof(low) _low = (low);                       \
+                        typeof(high) _high = (high);                    \
+                        ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
+                })
+
+#define assert_se(expr)                                                 \
+        do {                                                            \
+                if (_unlikely(!(expr)))                                 \
+                        log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
+                                   "Assertion '%s' failed at %s:%u, function %s(). Aborting.", \
+                                   #expr , __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+        } while (false)                                                 \
+
+/* We override the glibc assert() here. */
+#undef assert
+#ifdef NDEBUG
+#define assert(expr) do {} while(false)
+#else
+#define assert(expr) assert_se(expr)
+#endif
+
+#define assert_not_reached(t)                                           \
+        do {                                                            \
+                log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__,     \
+                           "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", \
+                           t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+        } while (false)
+
+#define assert_cc(expr)                            \
+        do {                                       \
+                switch (0) {                       \
+                        case 0:                    \
+                        case !!(expr):             \
+                                ;                  \
+                }                                  \
+        } while (false)
+
+#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
+#define UINT_TO_PTR(u) ((void*) ((uintptr_t) (u)))
+
+#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
+#define UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))
+
+#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
+#define INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
+
+#define TO_INT32(p) ((int32_t) ((intptr_t) (p)))
+#define INT32_TO_PTR(u) ((void*) ((intptr_t) (u)))
+
+#define memzero(x,l) (memset((x), 0, (l)))
+#define zero(x) (memzero(&(x), sizeof(x)))
+
+#define char_array_0(x) x[sizeof(x)-1] = 0;
+
+#define IOVEC_SET_STRING(i, s)                  \
+        do {                                    \
+                struct iovec *_i = &(i);        \
+                char *_s = (char *)(s);         \
+                _i->iov_base = _s;              \
+                _i->iov_len = strlen(_s);       \
+        } while(false);
+
+#include "log.h"
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..bba2975
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,787 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include "manager.h"
+#include "log.h"
+#include "mount-setup.h"
+#include "hostname-setup.h"
+#include "loopback-setup.h"
+#include "load-fragment.h"
+#include "fdset.h"
+
+static enum {
+        ACTION_RUN,
+        ACTION_HELP,
+        ACTION_TEST,
+        ACTION_DUMP_CONFIGURATION_ITEMS
+} action = ACTION_RUN;
+
+static char *default_unit = NULL;
+static ManagerRunningAs running_as = _MANAGER_RUNNING_AS_INVALID;
+
+static bool dump_core = true;
+static bool crash_shell = false;
+static int crash_chvt = -1;
+static bool confirm_spawn = false;
+static FILE* serialization = NULL;
+
+_noreturn static void freeze(void) {
+        for (;;)
+                pause();
+}
+
+static void nop_handler(int sig) {
+}
+
+_noreturn static void crash(int sig) {
+
+        if (!dump_core)
+                log_error("Caught <%s>, not dumping core.", strsignal(sig));
+        else {
+                struct sigaction sa;
+                pid_t pid;
+
+                /* We want to wait for the core process, hence let's enable SIGCHLD */
+                zero(sa);
+                sa.sa_handler = nop_handler;
+                sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
+                assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
+
+                if ((pid = fork()) < 0)
+                        log_error("Caught <%s>, cannot fork for core dump: %s", strsignal(sig), strerror(errno));
+
+                else if (pid == 0) {
+                        struct rlimit rl;
+
+                        /* Enable default signal handler for core dump */
+                        zero(sa);
+                        sa.sa_handler = SIG_DFL;
+                        assert_se(sigaction(sig, &sa, NULL) == 0);
+
+                        /* Don't limit the core dump size */
+                        zero(rl);
+                        rl.rlim_cur = RLIM_INFINITY;
+                        rl.rlim_max = RLIM_INFINITY;
+                        setrlimit(RLIMIT_CORE, &rl);
+
+                        /* Just to be sure... */
+                        assert_se(chdir("/") == 0);
+
+                        /* Raise the signal again */
+                        raise(sig);
+
+                        assert_not_reached("We shouldn't be here...");
+                        _exit(1);
+
+                } else {
+                        int status, r;
+
+                        /* Order things nicely. */
+                        if ((r = waitpid(pid, &status, 0)) < 0)
+                                log_error("Caught <%s>, waitpid() failed: %s", strsignal(sig), strerror(errno));
+                        else if (!WCOREDUMP(status))
+                                log_error("Caught <%s>, core dump failed.", strsignal(sig));
+                        else
+                                log_error("Caught <%s>, dumped core as pid %llu.", strsignal(sig), (unsigned long long) pid);
+                }
+        }
+
+        if (crash_chvt)
+                chvt(crash_chvt);
+
+        if (crash_shell) {
+                struct sigaction sa;
+                pid_t pid;
+
+                log_info("Executing crash shell in 10s...");
+                sleep(10);
+
+                /* Let the kernel reap children for us */
+                zero(sa);
+                sa.sa_handler = SIG_IGN;
+                sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
+                assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
+
+                if ((pid = fork()) < 0)
+                        log_error("Failed to fork off crash shell: %s", strerror(errno));
+                else if (pid == 0) {
+                        int fd, r;
+
+                        if ((fd = acquire_terminal("/dev/console", false, true)) < 0) {
+                                log_error("Failed to acquire terminal: %s", strerror(-fd));
+                                _exit(1);
+                        }
+
+                        if ((r = make_stdio(fd)) < 0) {
+                                log_error("Failed to duplicate terminal fd: %s", strerror(-r));
+                                _exit(1);
+                        }
+
+                        execl("/bin/sh", "/bin/sh", NULL);
+
+                        log_error("execl() failed: %s", strerror(errno));
+                        _exit(1);
+                }
+
+                log_info("Successfully spawned crash shall as pid %llu.", (unsigned long long) pid);
+        }
+
+        log_info("Freezing execution.");
+        freeze();
+}
+
+static void install_crash_handler(void) {
+        struct sigaction sa;
+
+        zero(sa);
+
+        sa.sa_handler = crash;
+        sa.sa_flags = SA_NODEFER;
+
+        assert_se(sigaction(SIGSEGV, &sa, NULL) == 0);
+        assert_se(sigaction(SIGILL, &sa, NULL) == 0);
+        assert_se(sigaction(SIGFPE, &sa, NULL) == 0);
+        assert_se(sigaction(SIGBUS, &sa, NULL) == 0);
+        assert_se(sigaction(SIGQUIT, &sa, NULL) == 0);
+        assert_se(sigaction(SIGABRT, &sa, NULL) == 0);
+}
+
+static int make_null_stdio(void) {
+        int null_fd, r;
+
+        if ((null_fd = open("/dev/null", O_RDWR)) < 0) {
+                log_error("Failed to open /dev/null: %m");
+                return -errno;
+        }
+
+        if ((r = make_stdio(null_fd)) < 0)
+                log_warning("Failed to dup2() device: %s", strerror(-r));
+
+        return r;
+}
+
+static int console_setup(bool do_reset) {
+        int tty_fd, r;
+
+        /* If we are init, we connect stdin/stdout/stderr to /dev/null
+         * and make sure we don't have a controlling tty. */
+
+        release_terminal();
+
+        if (!do_reset)
+                return 0;
+
+        if ((tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
+                log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
+                return -tty_fd;
+        }
+
+        if ((r = reset_terminal(tty_fd)) < 0)
+                log_error("Failed to reset /dev/console: %s", strerror(-r));
+
+        close_nointr_nofail(tty_fd);
+        return r;
+}
+
+static int set_default_unit(const char *u) {
+        char *c;
+
+        assert(u);
+
+        if (!(c = strdup(u)))
+                return -ENOMEM;
+
+        free(default_unit);
+        default_unit = c;
+        return 0;
+}
+
+static int parse_proc_cmdline_word(const char *word) {
+
+        static const char * const rlmap[] = {
+                "single", SPECIAL_RUNLEVEL1_TARGET,
+                "-s",     SPECIAL_RUNLEVEL1_TARGET,
+                "s",      SPECIAL_RUNLEVEL1_TARGET,
+                "S",      SPECIAL_RUNLEVEL1_TARGET,
+                "1",      SPECIAL_RUNLEVEL1_TARGET,
+                "2",      SPECIAL_RUNLEVEL2_TARGET,
+                "3",      SPECIAL_RUNLEVEL3_TARGET,
+                "4",      SPECIAL_RUNLEVEL4_TARGET,
+                "5",      SPECIAL_RUNLEVEL5_TARGET
+        };
+
+        if (startswith(word, "systemd.default="))
+                return set_default_unit(word + 16);
+
+        else if (startswith(word, "systemd.log_target=")) {
+
+                if (log_set_target_from_string(word + 19) < 0)
+                        log_warning("Failed to parse log target %s. Ignoring.", word + 19);
+
+        } else if (startswith(word, "systemd.log_level=")) {
+
+                if (log_set_max_level_from_string(word + 18) < 0)
+                        log_warning("Failed to parse log level %s. Ignoring.", word + 18);
+
+        } else if (startswith(word, "systemd.dump_core=")) {
+                int r;
+
+                if ((r = parse_boolean(word + 18)) < 0)
+                        log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18);
+                else
+                        dump_core = r;
+
+        } else if (startswith(word, "systemd.crash_shell=")) {
+                int r;
+
+                if ((r = parse_boolean(word + 20)) < 0)
+                        log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20);
+                else
+                        crash_shell = r;
+
+
+        } else if (startswith(word, "systemd.confirm_spawn=")) {
+                int r;
+
+                if ((r = parse_boolean(word + 22)) < 0)
+                        log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22);
+                else
+                        confirm_spawn = r;
+
+        } else if (startswith(word, "systemd.crash_chvt=")) {
+                int k;
+
+                if (safe_atoi(word + 19, &k) < 0)
+                        log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19);
+                else
+                        crash_chvt = k;
+
+        } else if (startswith(word, "systemd.")) {
+
+                log_warning("Unknown kernel switch %s. Ignoring.", word);
+
+                log_info("Supported kernel switches:");
+                log_info("systemd.default=UNIT                     Default unit to start");
+                log_info("systemd.log_target=console|kmsg|syslog   Log target");
+                log_info("systemd.log_level=LEVEL                  Log level");
+                log_info("systemd.dump_core=0|1                    Dump core on crash");
+                log_info("systemd.crash_shell=0|1                  On crash run shell");
+                log_info("systemd.crash_chvt=N                     Change to VT #N on crash");
+                log_info("systemd.confirm_spawn=0|1                Confirm every process spawn");
+
+        } else {
+                unsigned i;
+
+                /* SysV compatibility */
+                for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
+                        if (streq(word, rlmap[i]))
+                                return set_default_unit(rlmap[i+1]);
+        }
+
+        return 0;
+}
+
+static int parse_proc_cmdline(void) {
+        char *line;
+        int r;
+        char *w;
+        size_t l;
+        char *state;
+
+        if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
+                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(errno));
+                return 0;
+        }
+
+        FOREACH_WORD_QUOTED(w, l, line, state) {
+                char *word;
+
+                if (!(word = strndup(w, l))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                r = parse_proc_cmdline_word(word);
+                free(word);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        free(line);
+        return r;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_LOG_LEVEL = 0x100,
+                ARG_LOG_TARGET,
+                ARG_DEFAULT,
+                ARG_RUNNING_AS,
+                ARG_TEST,
+                ARG_DUMP_CONFIGURATION_ITEMS,
+                ARG_CONFIRM_SPAWN,
+                ARG_DESERIALIZE
+        };
+
+        static const struct option options[] = {
+                { "log-level",                required_argument, NULL, ARG_LOG_LEVEL                },
+                { "log-target",               required_argument, NULL, ARG_LOG_TARGET               },
+                { "default",                  required_argument, NULL, ARG_DEFAULT                  },
+                { "running-as",               required_argument, NULL, ARG_RUNNING_AS               },
+                { "test",                     no_argument,       NULL, ARG_TEST                     },
+                { "help",                     no_argument,       NULL, 'h'                          },
+                { "dump-configuration-items", no_argument,       NULL, ARG_DUMP_CONFIGURATION_ITEMS },
+                { "confirm-spawn",            no_argument,       NULL, ARG_CONFIRM_SPAWN            },
+                { "deserialize",              required_argument, NULL, ARG_DESERIALIZE              },
+                { NULL,                       0,                 NULL, 0                            }
+        };
+
+        int c, r;
+
+        assert(argc >= 1);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+
+                switch (c) {
+
+                case ARG_LOG_LEVEL:
+                        if ((r = log_set_max_level_from_string(optarg)) < 0) {
+                                log_error("Failed to parse log level %s.", optarg);
+                                return r;
+                        }
+
+                        break;
+
+                case ARG_LOG_TARGET:
+
+                        if ((r = log_set_target_from_string(optarg)) < 0) {
+                                log_error("Failed to parse log target %s.", optarg);
+                                return r;
+                        }
+
+                        break;
+
+                case ARG_DEFAULT:
+
+                        if ((r = set_default_unit(optarg)) < 0) {
+                                log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
+                                return r;
+                        }
+
+                        break;
+
+                case ARG_RUNNING_AS: {
+                        ManagerRunningAs as;
+
+                        if ((as = manager_running_as_from_string(optarg)) < 0) {
+                                log_error("Failed to parse running as value %s", optarg);
+                                return -EINVAL;
+                        }
+
+                        running_as = as;
+                        break;
+                }
+
+                case ARG_TEST:
+                        action = ACTION_TEST;
+                        break;
+
+                case ARG_DUMP_CONFIGURATION_ITEMS:
+                        action = ACTION_DUMP_CONFIGURATION_ITEMS;
+                        break;
+
+                case ARG_CONFIRM_SPAWN:
+                        confirm_spawn = true;
+                        break;
+
+                case ARG_DESERIALIZE: {
+                        int fd;
+                        FILE *f;
+
+                        if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
+                                log_error("Failed to parse deserialize option %s.", optarg);
+                                return r;
+                        }
+
+                        if (!(f = fdopen(fd, "r"))) {
+                                log_error("Failed to open serialization fd: %m");
+                                return r;
+                        }
+
+                        if (serialization)
+                                fclose(serialization);
+
+                        serialization = f;
+
+                        break;
+                }
+
+                case 'h':
+                        action = ACTION_HELP;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+
+        /* PID 1 will get the kernel arguments as parameters, which we
+         * ignore and unconditionally read from
+         * /proc/cmdline. However, we need to ignore those arguments
+         * here. */
+        if (running_as != MANAGER_INIT && optind < argc) {
+                log_error("Excess arguments.");
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int help(void) {
+
+        printf("%s [options]\n\n"
+               "  -h --help                      Show this help\n"
+               "     --default=UNIT              Set default unit\n"
+               "     --log-level=LEVEL           Set log level\n"
+               "     --log-target=TARGET         Set log target (console, syslog, kmsg, syslog-or-kmsg)\n"
+               "     --running-as=AS             Set running as (init, system, session)\n"
+               "     --test                      Determine startup sequence, dump it and exit\n"
+               "     --dump-configuration-items  Dump understood unit configuration items\n"
+               "     --confirm-spawn             Ask for confirmation when spawning processes\n",
+               __progname);
+
+        return 0;
+}
+
+static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) {
+        FILE *f = NULL;
+        FDSet *fds = NULL;
+        int r;
+
+        assert(m);
+        assert(_f);
+        assert(_fds);
+
+        if ((r = manager_open_serialization(&f)) < 0) {
+                log_error("Failed to create serialization faile: %s", strerror(-r));
+                goto fail;
+        }
+
+        if (!(fds = fdset_new())) {
+                r = -ENOMEM;
+                log_error("Failed to allocate fd set: %s", strerror(-r));
+                goto fail;
+        }
+
+        if ((r = manager_serialize(m, f, fds)) < 0) {
+                log_error("Failed to serialize state: %s", strerror(-r));
+                goto fail;
+        }
+
+        if (fseeko(f, 0, SEEK_SET) < 0) {
+                log_error("Failed to rewind serialization fd: %m");
+                goto fail;
+        }
+
+        if ((r = fd_cloexec(fileno(f), false)) < 0) {
+                log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
+                goto fail;
+        }
+
+        if ((r = fdset_cloexec(fds, false)) < 0) {
+                log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
+                goto fail;
+        }
+
+        *_f = f;
+        *_fds = fds;
+
+        return 0;
+
+fail:
+        fdset_free(fds);
+
+        if (f)
+                fclose(f);
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        Manager *m = NULL;
+        Unit *target = NULL;
+        Job *job = NULL;
+        int r, retval = 1;
+        FDSet *fds = NULL;
+        bool reexecute = false;
+
+        if (getpid() == 1) {
+                running_as = MANAGER_INIT;
+                log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        } else
+                running_as = MANAGER_SESSION;
+
+        if (set_default_unit(SPECIAL_DEFAULT_TARGET) < 0)
+                goto finish;
+
+        /* Mount /proc, /sys and friends, so that /proc/cmdline and
+         * /proc/$PID/fd is available. */
+        if (mount_setup() < 0)
+                goto finish;
+
+        /* Reset all signal handlers. */
+        assert_se(reset_all_signal_handlers() == 0);
+
+        /* If we are init, we can block sigkill. Yay. */
+        ignore_signal(SIGKILL);
+        ignore_signal(SIGPIPE);
+
+        if (running_as != MANAGER_SESSION)
+                if (parse_proc_cmdline() < 0)
+                        goto finish;
+
+        log_parse_environment();
+
+        if (parse_argv(argc, argv) < 0)
+                goto finish;
+
+        if (action == ACTION_HELP) {
+                retval = help();
+                goto finish;
+        } else if (action == ACTION_DUMP_CONFIGURATION_ITEMS) {
+                unit_dump_config_items(stdout);
+                retval = 0;
+                goto finish;
+        }
+
+        assert_se(action == ACTION_RUN || action == ACTION_TEST);
+
+        /* Remember open file descriptors for later deserialization */
+        if (serialization) {
+                if ((r = fdset_new_fill(&fds)) < 0) {
+                        log_error("Failed to allocate fd set: %s", strerror(-r));
+                        goto finish;
+                }
+
+                assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
+        } else
+                close_all_fds(NULL, 0);
+
+        /* Set up PATH unless it is already set */
+        setenv("PATH",
+               "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+               running_as == MANAGER_INIT);
+
+        /* Move out of the way, so that we won't block unmounts */
+        assert_se(chdir("/")  == 0);
+
+        if (running_as != MANAGER_SESSION) {
+                /* Become a session leader if we aren't one yet. */
+                setsid();
+
+                /* Disable the umask logic */
+                umask(0);
+        }
+
+        /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
+        dbus_connection_set_change_sigpipe(FALSE);
+
+        /* Reset the console, but only if this is really init and we
+         * are freshly booted */
+        if (running_as != MANAGER_SESSION && action == ACTION_RUN) {
+                console_setup(getpid() == 1 && !serialization);
+                make_null_stdio();
+        }
+
+        /* Open the logging devices, if possible and necessary */
+        log_open();
+
+        /* Make sure we leave a core dump without panicing the
+         * kernel. */
+        if (getpid() == 1)
+                install_crash_handler();
+
+        log_debug("systemd running in %s mode.", manager_running_as_to_string(running_as));
+
+        if (running_as == MANAGER_INIT) {
+                hostname_setup();
+                loopback_setup();
+        }
+
+        if ((r = manager_new(running_as, confirm_spawn, &m)) < 0) {
+                log_error("Failed to allocate manager object: %s", strerror(-r));
+                goto finish;
+        }
+
+        if ((r = manager_startup(m, serialization, fds)) < 0)
+                log_error("Failed to fully start up daemon: %s", strerror(-r));
+
+        if (fds) {
+                /* This will close all file descriptors that were opened, but
+                 * not claimed by any unit. */
+
+                fdset_free(fds);
+                fds = NULL;
+        }
+
+        if (serialization) {
+                fclose(serialization);
+                serialization = NULL;
+        } else {
+                log_debug("Activating default unit: %s", default_unit);
+
+                if ((r = manager_load_unit(m, default_unit, NULL, &target)) < 0) {
+                        log_error("Failed to load default target: %s", strerror(-r));
+
+                        log_info("Trying to load rescue target...");
+                        if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &target)) < 0) {
+                                log_error("Failed to load rescue target: %s", strerror(-r));
+                                goto finish;
+                        }
+                }
+
+                if (action == ACTION_TEST) {
+                        printf("-> By units:\n");
+                        manager_dump_units(m, stdout, "\t");
+                }
+
+                if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) {
+                        log_error("Failed to start default target: %s", strerror(-r));
+                        goto finish;
+                }
+
+                if (action == ACTION_TEST) {
+                        printf("-> By jobs:\n");
+                        manager_dump_jobs(m, stdout, "\t");
+                        retval = 0;
+                        goto finish;
+                }
+        }
+
+        for (;;) {
+                if ((r = manager_loop(m)) < 0) {
+                        log_error("Failed to run mainloop: %s", strerror(-r));
+                        goto finish;
+                }
+
+                switch (m->exit_code) {
+
+                case MANAGER_EXIT:
+                        retval = 0;
+                        log_debug("Exit.");
+                        goto finish;
+
+                case MANAGER_RELOAD:
+                        if ((r = manager_reload(m)) < 0)
+                                log_error("Failed to reload: %s", strerror(-r));
+                        break;
+
+                case MANAGER_REEXECUTE:
+                        if (prepare_reexecute(m, &serialization, &fds) < 0)
+                                goto finish;
+
+                        reexecute = true;
+                        log_debug("Reexecuting.");
+                        goto finish;
+
+                default:
+                        assert_not_reached("Unknown exit code.");
+                }
+        }
+
+finish:
+        if (m)
+                manager_free(m);
+
+        free(default_unit);
+
+        dbus_shutdown();
+
+        if (reexecute) {
+                const char *args[11];
+                unsigned i = 0;
+                char sfd[16];
+
+                assert(serialization);
+                assert(fds);
+
+                args[i++] = SYSTEMD_BINARY_PATH;
+
+                args[i++] = "--log-level";
+                args[i++] = log_level_to_string(log_get_max_level());
+
+                args[i++] = "--log-target";
+                args[i++] = log_target_to_string(log_get_target());
+
+                args[i++] = "--running-as";
+                args[i++] = manager_running_as_to_string(running_as);
+
+                snprintf(sfd, sizeof(sfd), "%i", fileno(serialization));
+                char_array_0(sfd);
+
+                args[i++] = "--deserialize";
+                args[i++] = sfd;
+
+                if (confirm_spawn)
+                        args[i++] = "--confirm-spawn";
+
+                args[i++] = NULL;
+
+                assert(i <= ELEMENTSOF(args));
+
+                execv(args[0], (char* const*) args);
+
+                log_error("Failed to reexecute: %m");
+        }
+
+        if (serialization)
+                fclose(serialization);
+
+        if (fds)
+                fdset_free(fds);
+
+        if (getpid() == 1)
+                freeze();
+
+        return retval;
+}
diff --git a/src/manager.c b/src/manager.c
new file mode 100644
index 0000000..688d9fa
--- /dev/null
+++ b/src/manager.c
@@ -0,0 +1,2291 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include <sys/poll.h>
+#include <sys/reboot.h>
+#include <sys/ioctl.h>
+#include <linux/kd.h>
+#include <libcgroup.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "manager.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "strv.h"
+#include "log.h"
+#include "util.h"
+#include "ratelimit.h"
+#include "cgroup.h"
+#include "mount-setup.h"
+#include "utmp-wtmp.h"
+#include "unit-name.h"
+#include "dbus-unit.h"
+#include "dbus-job.h"
+#include "missing.h"
+
+/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
+#define GC_QUEUE_ENTRIES_MAX 16
+
+/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
+#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
+
+static int enable_special_signals(Manager *m) {
+        char fd;
+
+        assert(m);
+
+        /* Enable that we get SIGINT on control-alt-del */
+        if (reboot(RB_DISABLE_CAD) < 0)
+                log_warning("Failed to enable ctrl-alt-del handling: %m");
+
+        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0)
+                log_warning("Failed to open /dev/tty0: %m");
+        else {
+                /* Enable that we get SIGWINCH on kbrequest */
+                if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
+                        log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
+
+                close_nointr_nofail(fd);
+        }
+
+        return 0;
+}
+
+static int manager_setup_signals(Manager *m) {
+        sigset_t mask;
+        struct epoll_event ev;
+        struct sigaction sa;
+
+        assert(m);
+
+        /* We are not interested in SIGSTOP and friends. */
+        zero(sa);
+        sa.sa_handler = SIG_DFL;
+        sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
+        assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
+
+        assert_se(sigemptyset(&mask) == 0);
+        assert_se(sigaddset(&mask, SIGCHLD) == 0);
+        assert_se(sigaddset(&mask, SIGTERM) == 0);
+        assert_se(sigaddset(&mask, SIGHUP) == 0);
+        assert_se(sigaddset(&mask, SIGUSR1) == 0);
+        assert_se(sigaddset(&mask, SIGUSR2) == 0);
+        assert_se(sigaddset(&mask, SIGINT) == 0);   /* Kernel sends us this on control-alt-del */
+        assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */
+        assert_se(sigaddset(&mask, SIGPWR) == 0);   /* Some kernel drivers and upsd send us this on power failure */
+        assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
+
+        m->signal_watch.type = WATCH_SIGNAL;
+        if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
+                return -errno;
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.ptr = &m->signal_watch;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
+                return -errno;
+
+        if (m->running_as == MANAGER_INIT)
+                return enable_special_signals(m);
+
+        return 0;
+}
+
+static char** session_dirs(void) {
+        const char *home, *e;
+        char *config_home = NULL, *data_home = NULL;
+        char **config_dirs = NULL, **data_dirs = NULL;
+        char **r = NULL, **t;
+
+        /* Implement the mechanisms defined in
+         *
+         * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
+         *
+         * We look in both the config and the data dirs because we
+         * want to encourage that distributors ship their unit files
+         * as data, and allow overriding as configuration.
+         */
+
+        home = getenv("HOME");
+
+        if ((e = getenv("XDG_CONFIG_HOME"))) {
+                if (asprintf(&config_home, "%s/systemd/session", e) < 0)
+                        goto fail;
+
+        } else if (home) {
+                if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0)
+                        goto fail;
+        }
+
+        if ((e = getenv("XDG_CONFIG_DIRS")))
+                if (!(config_dirs = strv_split(e, ":")))
+                        goto fail;
+
+        /* We don't treat /etc/xdg/systemd here as the spec
+         * suggests because we assume that that is a link to
+         * /etc/systemd/ anyway. */
+
+        if ((e = getenv("XDG_DATA_HOME"))) {
+                if (asprintf(&data_home, "%s/systemd/session", e) < 0)
+                        goto fail;
+
+        } else if (home) {
+                if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0)
+                        goto fail;
+        }
+
+        if ((e = getenv("XDG_DATA_DIRS")))
+                data_dirs = strv_split(e, ":");
+        else
+                data_dirs = strv_new("/usr/local/share", "/usr/share", NULL);
+
+        if (!data_dirs)
+                goto fail;
+
+        /* Now merge everything we found. */
+        if (config_home) {
+                if (!(t = strv_append(r, config_home)))
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
+        if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session")))
+                goto finish;
+        strv_free(r);
+        r = t;
+
+        if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH)))
+                goto fail;
+        strv_free(r);
+        r = t;
+
+        if (data_home) {
+                if (!(t = strv_append(r, data_home)))
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
+        if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session")))
+                goto fail;
+        strv_free(r);
+        r = t;
+
+        if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH)))
+                goto fail;
+        strv_free(r);
+        r = t;
+
+        if (!strv_path_make_absolute_cwd(r))
+            goto fail;
+
+finish:
+        free(config_home);
+        strv_free(config_dirs);
+        free(data_home);
+        strv_free(data_dirs);
+
+        return r;
+
+fail:
+        strv_free(r);
+        r = NULL;
+        goto finish;
+}
+
+static int manager_find_paths(Manager *m) {
+        const char *e;
+        char *t;
+
+        assert(m);
+
+        /* First priority is whatever has been passed to us via env
+         * vars */
+        if ((e = getenv("SYSTEMD_UNIT_PATH")))
+                if (!(m->unit_path = split_path_and_make_absolute(e)))
+                        return -ENOMEM;
+
+        if (strv_isempty(m->unit_path)) {
+
+                /* Nothing is set, so let's figure something out. */
+                strv_free(m->unit_path);
+
+                if (m->running_as == MANAGER_SESSION) {
+                        if (!(m->unit_path = session_dirs()))
+                                return -ENOMEM;
+                } else
+                        if (!(m->unit_path = strv_new(
+                                              SYSTEM_CONFIG_UNIT_PATH,  /* /etc/systemd/system/ */
+                                              SYSTEM_DATA_UNIT_PATH,    /* /lib/systemd/system/ */
+                                              NULL)))
+                                return -ENOMEM;
+        }
+
+        if (m->running_as == MANAGER_INIT) {
+                /* /etc/init.d/ compatibility does not matter to users */
+
+                if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
+                        if (!(m->sysvinit_path = split_path_and_make_absolute(e)))
+                                return -ENOMEM;
+
+                if (strv_isempty(m->sysvinit_path)) {
+                        strv_free(m->sysvinit_path);
+
+                        if (!(m->sysvinit_path = strv_new(
+                                              SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
+                                              NULL)))
+                                return -ENOMEM;
+                }
+
+                if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
+                        if (!(m->sysvrcnd_path = split_path_and_make_absolute(e)))
+                                return -ENOMEM;
+
+                if (strv_isempty(m->sysvrcnd_path)) {
+                        strv_free(m->sysvrcnd_path);
+
+                        if (!(m->sysvrcnd_path = strv_new(
+                                              SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
+                                              NULL)))
+                                return -ENOMEM;
+                }
+        }
+
+        strv_uniq(m->unit_path);
+        strv_uniq(m->sysvinit_path);
+        strv_uniq(m->sysvrcnd_path);
+
+        assert(!strv_isempty(m->unit_path));
+        if (!(t = strv_join(m->unit_path, "\n\t")))
+                return -ENOMEM;
+        log_debug("Looking for unit files in:\n\t%s", t);
+        free(t);
+
+        if (!strv_isempty(m->sysvinit_path)) {
+
+                if (!(t = strv_join(m->sysvinit_path, "\n\t")))
+                        return -ENOMEM;
+
+                log_debug("Looking for SysV init scripts in:\n\t%s", t);
+                free(t);
+        } else
+                log_debug("Ignoring SysV init scripts.");
+
+        if (!strv_isempty(m->sysvrcnd_path)) {
+
+                if (!(t = strv_join(m->sysvrcnd_path, "\n\t")))
+                        return -ENOMEM;
+
+                log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
+                free(t);
+        } else
+                log_debug("Ignoring SysV rcN.d links.");
+
+        return 0;
+}
+
+int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
+        Manager *m;
+        int r = -ENOMEM;
+
+        assert(_m);
+        assert(running_as >= 0);
+        assert(running_as < _MANAGER_RUNNING_AS_MAX);
+
+        if (!(m = new0(Manager, 1)))
+                return -ENOMEM;
+
+        m->boot_timestamp = now(CLOCK_REALTIME);
+
+        m->running_as = running_as;
+        m->confirm_spawn = confirm_spawn;
+        m->name_data_slot = -1;
+        m->exit_code = _MANAGER_EXIT_CODE_INVALID;
+
+        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
+        m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
+
+        if (!(m->environment = strv_copy(environ)))
+                goto fail;
+
+        if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
+                goto fail;
+
+        if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
+                goto fail;
+
+        if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
+                goto fail;
+
+        if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
+                goto fail;
+
+        if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
+                goto fail;
+
+        if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
+                goto fail;
+
+        if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
+                goto fail;
+
+        if ((r = manager_find_paths(m)) < 0)
+                goto fail;
+
+        if ((r = manager_setup_signals(m)) < 0)
+                goto fail;
+
+        if ((r = manager_setup_cgroup(m)) < 0)
+                goto fail;
+
+        /* Try to connect to the busses, if possible. */
+        if ((r = bus_init_system(m)) < 0 ||
+            (r = bus_init_api(m)) < 0)
+                goto fail;
+
+        *_m = m;
+        return 0;
+
+fail:
+        manager_free(m);
+        return r;
+}
+
+static unsigned manager_dispatch_cleanup_queue(Manager *m) {
+        Meta *meta;
+        unsigned n = 0;
+
+        assert(m);
+
+        while ((meta = m->cleanup_queue)) {
+                assert(meta->in_cleanup_queue);
+
+                unit_free(UNIT(meta));
+                n++;
+        }
+
+        return n;
+}
+
+enum {
+        GC_OFFSET_IN_PATH,  /* This one is on the path we were travelling */
+        GC_OFFSET_UNSURE,   /* No clue */
+        GC_OFFSET_GOOD,     /* We still need this unit */
+        GC_OFFSET_BAD,      /* We don't need this unit anymore */
+        _GC_OFFSET_MAX
+};
+
+static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
+        Iterator i;
+        Unit *other;
+        bool is_bad;
+
+        assert(u);
+
+        if (u->meta.gc_marker == gc_marker + GC_OFFSET_GOOD ||
+            u->meta.gc_marker == gc_marker + GC_OFFSET_BAD ||
+            u->meta.gc_marker == gc_marker + GC_OFFSET_IN_PATH)
+                return;
+
+        if (u->meta.in_cleanup_queue)
+                goto bad;
+
+        if (unit_check_gc(u))
+                goto good;
+
+        u->meta.gc_marker = gc_marker + GC_OFFSET_IN_PATH;
+
+        is_bad = true;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) {
+                unit_gc_sweep(other, gc_marker);
+
+                if (other->meta.gc_marker == gc_marker + GC_OFFSET_GOOD)
+                        goto good;
+
+                if (other->meta.gc_marker != gc_marker + GC_OFFSET_BAD)
+                        is_bad = false;
+        }
+
+        if (is_bad)
+                goto bad;
+
+        /* We were unable to find anything out about this entry, so
+         * let's investigate it later */
+        u->meta.gc_marker = gc_marker + GC_OFFSET_UNSURE;
+        unit_add_to_gc_queue(u);
+        return;
+
+bad:
+        /* We definitely know that this one is not useful anymore, so
+         * let's mark it for deletion */
+        u->meta.gc_marker = gc_marker + GC_OFFSET_BAD;
+        unit_add_to_cleanup_queue(u);
+        return;
+
+good:
+        u->meta.gc_marker = gc_marker + GC_OFFSET_GOOD;
+}
+
+static unsigned manager_dispatch_gc_queue(Manager *m) {
+        Meta *meta;
+        unsigned n = 0;
+        unsigned gc_marker;
+
+        assert(m);
+
+        if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
+            (m->gc_queue_timestamp <= 0 ||
+             (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
+                return 0;
+
+        log_debug("Running GC...");
+
+        m->gc_marker += _GC_OFFSET_MAX;
+        if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
+                m->gc_marker = 1;
+
+        gc_marker = m->gc_marker;
+
+        while ((meta = m->gc_queue)) {
+                assert(meta->in_gc_queue);
+
+                unit_gc_sweep(UNIT(meta), gc_marker);
+
+                LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta);
+                meta->in_gc_queue = false;
+
+                n++;
+
+                if (meta->gc_marker == gc_marker + GC_OFFSET_BAD ||
+                    meta->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
+                        log_debug("Collecting %s", meta->id);
+                        meta->gc_marker = gc_marker + GC_OFFSET_BAD;
+                        unit_add_to_cleanup_queue(UNIT(meta));
+                }
+        }
+
+        m->n_in_gc_queue = 0;
+        m->gc_queue_timestamp = 0;
+
+        return n;
+}
+
+static void manager_clear_jobs_and_units(Manager *m) {
+        Job *j;
+        Unit *u;
+
+        assert(m);
+
+        while ((j = hashmap_first(m->transaction_jobs)))
+                job_free(j);
+
+        while ((u = hashmap_first(m->units)))
+                unit_free(u);
+}
+
+void manager_free(Manager *m) {
+        UnitType c;
+
+        assert(m);
+
+        manager_dispatch_cleanup_queue(m);
+        manager_clear_jobs_and_units(m);
+
+        for (c = 0; c < _UNIT_TYPE_MAX; c++)
+                if (unit_vtable[c]->shutdown)
+                        unit_vtable[c]->shutdown(m);
+
+        /* If we reexecute ourselves, we keep the root cgroup
+         * around */
+        manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
+
+        bus_done_api(m);
+        bus_done_system(m);
+
+        hashmap_free(m->units);
+        hashmap_free(m->jobs);
+        hashmap_free(m->transaction_jobs);
+        hashmap_free(m->watch_pids);
+        hashmap_free(m->watch_bus);
+
+        if (m->epoll_fd >= 0)
+                close_nointr_nofail(m->epoll_fd);
+        if (m->signal_watch.fd >= 0)
+                close_nointr_nofail(m->signal_watch.fd);
+
+        strv_free(m->unit_path);
+        strv_free(m->sysvinit_path);
+        strv_free(m->sysvrcnd_path);
+        strv_free(m->environment);
+
+        free(m->cgroup_controller);
+        free(m->cgroup_hierarchy);
+
+        hashmap_free(m->cgroup_bondings);
+
+        free(m);
+}
+
+int manager_enumerate(Manager *m) {
+        int r = 0, q;
+        UnitType c;
+
+        assert(m);
+
+        /* Let's ask every type to load all units from disk/kernel
+         * that it might know */
+        for (c = 0; c < _UNIT_TYPE_MAX; c++)
+                if (unit_vtable[c]->enumerate)
+                        if ((q = unit_vtable[c]->enumerate(m)) < 0)
+                                r = q;
+
+        manager_dispatch_load_queue(m);
+        return r;
+}
+
+int manager_coldplug(Manager *m) {
+        int r = 0, q;
+        Iterator i;
+        Unit *u;
+        char *k;
+
+        assert(m);
+
+        /* Then, let's set up their initial state. */
+        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+
+                /* ignore aliases */
+                if (u->meta.id != k)
+                        continue;
+
+                if (UNIT_VTABLE(u)->coldplug)
+                        if ((q = UNIT_VTABLE(u)->coldplug(u)) < 0)
+                                r = q;
+        }
+
+        return r;
+}
+
+int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+        int r, q;
+
+        assert(m);
+
+        /* First, enumerate what we can from all config files */
+        r = manager_enumerate(m);
+
+        /* Second, deserialize if there is something to deserialize */
+        if (serialization)
+                if ((q = manager_deserialize(m, serialization, fds)) < 0)
+                        r = q;
+
+        /* Third, fire things up! */
+        if ((q = manager_coldplug(m)) < 0)
+                r = q;
+
+        /* Now that the initial devices are available, let's see if we
+         * can write the utmp file */
+        manager_write_utmp_reboot(m);
+
+        return r;
+}
+
+static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
+        assert(m);
+        assert(j);
+
+        /* Deletes one job from the transaction */
+
+        manager_transaction_unlink_job(m, j, delete_dependencies);
+
+        if (!j->installed)
+                job_free(j);
+}
+
+static void transaction_delete_unit(Manager *m, Unit *u) {
+        Job *j;
+
+        /* Deletes all jobs associated with a certain unit from the
+         * transaction */
+
+        while ((j = hashmap_get(m->transaction_jobs, u)))
+                transaction_delete_job(m, j, true);
+}
+
+static void transaction_clean_dependencies(Manager *m) {
+        Iterator i;
+        Job *j;
+
+        assert(m);
+
+        /* Drops all dependencies of all installed jobs */
+
+        HASHMAP_FOREACH(j, m->jobs, i) {
+                while (j->subject_list)
+                        job_dependency_free(j->subject_list);
+                while (j->object_list)
+                        job_dependency_free(j->object_list);
+        }
+
+        assert(!m->transaction_anchor);
+}
+
+static void transaction_abort(Manager *m) {
+        Job *j;
+
+        assert(m);
+
+        while ((j = hashmap_first(m->transaction_jobs)))
+                if (j->installed)
+                        transaction_delete_job(m, j, true);
+                else
+                        job_free(j);
+
+        assert(hashmap_isempty(m->transaction_jobs));
+
+        transaction_clean_dependencies(m);
+}
+
+static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) {
+        JobDependency *l;
+
+        assert(m);
+
+        /* A recursive sweep through the graph that marks all units
+         * that matter to the anchor job, i.e. are directly or
+         * indirectly a dependency of the anchor job via paths that
+         * are fully marked as mattering. */
+
+        if (j)
+                l = j->subject_list;
+        else
+                l = m->transaction_anchor;
+
+        LIST_FOREACH(subject, l, l) {
+
+                /* This link does not matter */
+                if (!l->matters)
+                        continue;
+
+                /* This unit has already been marked */
+                if (l->object->generation == generation)
+                        continue;
+
+                l->object->matters_to_anchor = true;
+                l->object->generation = generation;
+
+                transaction_find_jobs_that_matter_to_anchor(m, l->object, generation);
+        }
+}
+
+static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
+        JobDependency *l, *last;
+
+        assert(j);
+        assert(other);
+        assert(j->unit == other->unit);
+        assert(!j->installed);
+
+        /* Merges 'other' into 'j' and then deletes j. */
+
+        j->type = t;
+        j->state = JOB_WAITING;
+        j->override = j->override || other->override;
+
+        j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
+
+        /* Patch us in as new owner of the JobDependency objects */
+        last = NULL;
+        LIST_FOREACH(subject, l, other->subject_list) {
+                assert(l->subject == other);
+                l->subject = j;
+                last = l;
+        }
+
+        /* Merge both lists */
+        if (last) {
+                last->subject_next = j->subject_list;
+                if (j->subject_list)
+                        j->subject_list->subject_prev = last;
+                j->subject_list = other->subject_list;
+        }
+
+        /* Patch us in as new owner of the JobDependency objects */
+        last = NULL;
+        LIST_FOREACH(object, l, other->object_list) {
+                assert(l->object == other);
+                l->object = j;
+                last = l;
+        }
+
+        /* Merge both lists */
+        if (last) {
+                last->object_next = j->object_list;
+                if (j->object_list)
+                        j->object_list->object_prev = last;
+                j->object_list = other->object_list;
+        }
+
+        /* Kill the other job */
+        other->subject_list = NULL;
+        other->object_list = NULL;
+        transaction_delete_job(m, other, true);
+}
+
+static int delete_one_unmergeable_job(Manager *m, Job *j) {
+        Job *k;
+
+        assert(j);
+
+        /* Tries to delete one item in the linked list
+         * j->transaction_next->transaction_next->... that conflicts
+         * whith another one, in an attempt to make an inconsistent
+         * transaction work. */
+
+        /* We rely here on the fact that if a merged with b does not
+         * merge with c, either a or b merge with c neither */
+        LIST_FOREACH(transaction, j, j)
+                LIST_FOREACH(transaction, k, j->transaction_next) {
+                        Job *d;
+
+                        /* Is this one mergeable? Then skip it */
+                        if (job_type_is_mergeable(j->type, k->type))
+                                continue;
+
+                        /* Ok, we found two that conflict, let's see if we can
+                         * drop one of them */
+                        if (!j->matters_to_anchor)
+                                d = j;
+                        else if (!k->matters_to_anchor)
+                                d = k;
+                        else
+                                return -ENOEXEC;
+
+                        /* Ok, we can drop one, so let's do so. */
+                        log_debug("Trying to fix job merging by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
+                        transaction_delete_job(m, d, true);
+                        return 0;
+                }
+
+        return -EINVAL;
+}
+
+static int transaction_merge_jobs(Manager *m) {
+        Job *j;
+        Iterator i;
+        int r;
+
+        assert(m);
+
+        /* First step, check whether any of the jobs for one specific
+         * task conflict. If so, try to drop one of them. */
+        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                JobType t;
+                Job *k;
+
+                t = j->type;
+                LIST_FOREACH(transaction, k, j->transaction_next) {
+                        if ((r = job_type_merge(&t, k->type)) >= 0)
+                                continue;
+
+                        /* OK, we could not merge all jobs for this
+                         * action. Let's see if we can get rid of one
+                         * of them */
+
+                        if ((r = delete_one_unmergeable_job(m, j)) >= 0)
+                                /* Ok, we managed to drop one, now
+                                 * let's ask our callers to call us
+                                 * again after garbage collecting */
+                                return -EAGAIN;
+
+                        /* We couldn't merge anything. Failure */
+                        return r;
+                }
+        }
+
+        /* Second step, merge the jobs. */
+        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                JobType t = j->type;
+                Job *k;
+
+                /* Merge all transactions */
+                LIST_FOREACH(transaction, k, j->transaction_next)
+                        assert_se(job_type_merge(&t, k->type) == 0);
+
+                /* If an active job is mergeable, merge it too */
+                if (j->unit->meta.job)
+                        job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */
+
+                while ((k = j->transaction_next)) {
+                        if (j->installed) {
+                                transaction_merge_and_delete_job(m, k, j, t);
+                                j = k;
+                        } else
+                                transaction_merge_and_delete_job(m, j, k, t);
+                }
+
+                assert(!j->transaction_next);
+                assert(!j->transaction_prev);
+        }
+
+        return 0;
+}
+
+static void transaction_drop_redundant(Manager *m) {
+        bool again;
+
+        assert(m);
+
+        /* Goes through the transaction and removes all jobs that are
+         * a noop */
+
+        do {
+                Job *j;
+                Iterator i;
+
+                again = false;
+
+                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                        bool changes_something = false;
+                        Job *k;
+
+                        LIST_FOREACH(transaction, k, j) {
+
+                                if (!job_is_anchor(k) &&
+                                    job_type_is_redundant(k->type, unit_active_state(k->unit)))
+                                        continue;
+
+                                changes_something = true;
+                                break;
+                        }
+
+                        if (changes_something)
+                                continue;
+
+                        log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
+                        transaction_delete_job(m, j, false);
+                        again = true;
+                        break;
+                }
+
+        } while (again);
+}
+
+static bool unit_matters_to_anchor(Unit *u, Job *j) {
+        assert(u);
+        assert(!j->transaction_prev);
+
+        /* Checks whether at least one of the jobs for this unit
+         * matters to the anchor. */
+
+        LIST_FOREACH(transaction, j, j)
+                if (j->matters_to_anchor)
+                        return true;
+
+        return false;
+}
+
+static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation) {
+        Iterator i;
+        Unit *u;
+        int r;
+
+        assert(m);
+        assert(j);
+        assert(!j->transaction_prev);
+
+        /* Does a recursive sweep through the ordering graph, looking
+         * for a cycle. If we find cycle we try to break it. */
+
+        /* Did we find a cycle? */
+        if (j->marker && j->generation == generation) {
+                Job *k;
+
+                /* So, we already have been here. We have a
+                 * cycle. Let's try to break it. We go backwards in
+                 * our path and try to find a suitable job to
+                 * remove. We use the marker to find our way back,
+                 * since smart how we are we stored our way back in
+                 * there. */
+
+                log_debug("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
+
+                for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
+
+                        log_debug("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type));
+
+                        if (!k->installed &&
+                            !unit_matters_to_anchor(k->unit, k)) {
+                                /* Ok, we can drop this one, so let's
+                                 * do so. */
+                                log_debug("Breaking order cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type));
+                                transaction_delete_unit(m, k->unit);
+                                return -EAGAIN;
+                        }
+
+                        /* Check if this in fact was the beginning of
+                         * the cycle */
+                        if (k == j)
+                                break;
+                }
+
+                log_debug("Unable to break cycle");
+
+                return -ENOEXEC;
+        }
+
+        /* Make the marker point to where we come from, so that we can
+         * find our way backwards if we want to break a cycle */
+        j->marker = from;
+        j->generation = generation;
+
+        /* We assume that the the dependencies are bidirectional, and
+         * hence can ignore UNIT_AFTER */
+        SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
+                Job *o;
+
+                /* Is there a job for this unit? */
+                if (!(o = hashmap_get(m->transaction_jobs, u)))
+
+                        /* Ok, there is no job for this in the
+                         * transaction, but maybe there is already one
+                         * running? */
+                        if (!(o = u->meta.job))
+                                continue;
+
+                if ((r = transaction_verify_order_one(m, o, j, generation)) < 0)
+                        return r;
+        }
+
+        /* Ok, let's backtrack, and remember that this entry is not on
+         * our path anymore. */
+        j->marker = NULL;
+
+        return 0;
+}
+
+static int transaction_verify_order(Manager *m, unsigned *generation) {
+        Job *j;
+        int r;
+        Iterator i;
+
+        assert(m);
+        assert(generation);
+
+        /* Check if the ordering graph is cyclic. If it is, try to fix
+         * that up by dropping one of the jobs. */
+
+        HASHMAP_FOREACH(j, m->transaction_jobs, i)
+                if ((r = transaction_verify_order_one(m, j, NULL, (*generation)++)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static void transaction_collect_garbage(Manager *m) {
+        bool again;
+
+        assert(m);
+
+        /* Drop jobs that are not required by any other job */
+
+        do {
+                Iterator i;
+                Job *j;
+
+                again = false;
+
+                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                        if (j->object_list)
+                                continue;
+
+                        log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
+                        transaction_delete_job(m, j, true);
+                        again = true;
+                        break;
+                }
+
+        } while (again);
+}
+
+static int transaction_is_destructive(Manager *m) {
+        Iterator i;
+        Job *j;
+
+        assert(m);
+
+        /* Checks whether applying this transaction means that
+         * existing jobs would be replaced */
+
+        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+
+                /* Assume merged */
+                assert(!j->transaction_prev);
+                assert(!j->transaction_next);
+
+                if (j->unit->meta.job &&
+                    j->unit->meta.job != j &&
+                    !job_type_is_superset(j->type, j->unit->meta.job->type))
+                        return -EEXIST;
+        }
+
+        return 0;
+}
+
+static void transaction_minimize_impact(Manager *m) {
+        bool again;
+        assert(m);
+
+        /* Drops all unnecessary jobs that reverse already active jobs
+         * or that stop a running service. */
+
+        do {
+                Job *j;
+                Iterator i;
+
+                again = false;
+
+                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                        LIST_FOREACH(transaction, j, j) {
+                                bool stops_running_service, changes_existing_job;
+
+                                /* If it matters, we shouldn't drop it */
+                                if (j->matters_to_anchor)
+                                        continue;
+
+                                /* Would this stop a running service?
+                                 * Would this change an existing job?
+                                 * If so, let's drop this entry */
+
+                                stops_running_service =
+                                        j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
+
+                                changes_existing_job =
+                                        j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state);
+
+                                if (!stops_running_service && !changes_existing_job)
+                                        continue;
+
+                                if (stops_running_service)
+                                        log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
+
+                                if (changes_existing_job)
+                                        log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
+
+                                /* Ok, let's get rid of this */
+                                log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
+
+                                transaction_delete_job(m, j, true);
+                                again = true;
+                                break;
+                        }
+
+                        if (again)
+                                break;
+                }
+
+        } while (again);
+}
+
+static int transaction_apply(Manager *m) {
+        Iterator i;
+        Job *j;
+        int r;
+
+        /* Moves the transaction jobs to the set of active jobs */
+
+        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                /* Assume merged */
+                assert(!j->transaction_prev);
+                assert(!j->transaction_next);
+
+                if (j->installed)
+                        continue;
+
+                if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
+                        goto rollback;
+        }
+
+        while ((j = hashmap_steal_first(m->transaction_jobs))) {
+                if (j->installed)
+                        continue;
+
+                if (j->unit->meta.job)
+                        job_free(j->unit->meta.job);
+
+                j->unit->meta.job = j;
+                j->installed = true;
+
+                /* We're fully installed. Now let's free data we don't
+                 * need anymore. */
+
+                assert(!j->transaction_next);
+                assert(!j->transaction_prev);
+
+                job_add_to_run_queue(j);
+                job_add_to_dbus_queue(j);
+        }
+
+        /* As last step, kill all remaining job dependencies. */
+        transaction_clean_dependencies(m);
+
+        return 0;
+
+rollback:
+
+        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
+                if (j->installed)
+                        continue;
+
+                hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
+        }
+
+        return r;
+}
+
+static int transaction_activate(Manager *m, JobMode mode) {
+        int r;
+        unsigned generation = 1;
+
+        assert(m);
+
+        /* This applies the changes recorded in transaction_jobs to
+         * the actual list of jobs, if possible. */
+
+        /* First step: figure out which jobs matter */
+        transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++);
+
+        /* Second step: Try not to stop any running services if
+         * we don't have to. Don't try to reverse running
+         * jobs if we don't have to. */
+        transaction_minimize_impact(m);
+
+        /* Third step: Drop redundant jobs */
+        transaction_drop_redundant(m);
+
+        for (;;) {
+                /* Fourth step: Let's remove unneeded jobs that might
+                 * be lurking. */
+                transaction_collect_garbage(m);
+
+                /* Fifth step: verify order makes sense and correct
+                 * cycles if necessary and possible */
+                if ((r = transaction_verify_order(m, &generation)) >= 0)
+                        break;
+
+                if (r != -EAGAIN) {
+                        log_debug("Requested transaction contains an unfixable cyclic ordering dependency: %s", strerror(-r));
+                        goto rollback;
+                }
+
+                /* Let's see if the resulting transaction ordering
+                 * graph is still cyclic... */
+        }
+
+        for (;;) {
+                /* Sixth step: let's drop unmergeable entries if
+                 * necessary and possible, merge entries we can
+                 * merge */
+                if ((r = transaction_merge_jobs(m)) >= 0)
+                        break;
+
+                if (r != -EAGAIN) {
+                        log_debug("Requested transaction contains unmergable jobs: %s", strerror(-r));
+                        goto rollback;
+                }
+
+                /* Seventh step: an entry got dropped, let's garbage
+                 * collect its dependencies. */
+                transaction_collect_garbage(m);
+
+                /* Let's see if the resulting transaction still has
+                 * unmergeable entries ... */
+        }
+
+        /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
+        transaction_drop_redundant(m);
+
+        /* Ninth step: check whether we can actually apply this */
+        if (mode == JOB_FAIL)
+                if ((r = transaction_is_destructive(m)) < 0) {
+                        log_debug("Requested transaction contradicts existing jobs: %s", strerror(-r));
+                        goto rollback;
+                }
+
+        /* Tenth step: apply changes */
+        if ((r = transaction_apply(m)) < 0) {
+                log_debug("Failed to apply transaction: %s", strerror(-r));
+                goto rollback;
+        }
+
+        assert(hashmap_isempty(m->transaction_jobs));
+        assert(!m->transaction_anchor);
+
+        return 0;
+
+rollback:
+        transaction_abort(m);
+        return r;
+}
+
+static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) {
+        Job *j, *f;
+        int r;
+
+        assert(m);
+        assert(unit);
+
+        /* Looks for an axisting prospective job and returns that. If
+         * it doesn't exist it is created and added to the prospective
+         * jobs list. */
+
+        f = hashmap_get(m->transaction_jobs, unit);
+
+        LIST_FOREACH(transaction, j, f) {
+                assert(j->unit == unit);
+
+                if (j->type == type) {
+                        if (is_new)
+                                *is_new = false;
+                        return j;
+                }
+        }
+
+        if (unit->meta.job && unit->meta.job->type == type)
+                j = unit->meta.job;
+        else if (!(j = job_new(m, type, unit)))
+                return NULL;
+
+        j->generation = 0;
+        j->marker = NULL;
+        j->matters_to_anchor = false;
+        j->override = override;
+
+        LIST_PREPEND(Job, transaction, f, j);
+
+        if ((r = hashmap_replace(m->transaction_jobs, unit, f)) < 0) {
+                job_free(j);
+                return NULL;
+        }
+
+        if (is_new)
+                *is_new = true;
+
+        log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type));
+
+        return j;
+}
+
+void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) {
+        assert(m);
+        assert(j);
+
+        if (j->transaction_prev)
+                j->transaction_prev->transaction_next = j->transaction_next;
+        else if (j->transaction_next)
+                hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next);
+        else
+                hashmap_remove_value(m->transaction_jobs, j->unit, j);
+
+        if (j->transaction_next)
+                j->transaction_next->transaction_prev = j->transaction_prev;
+
+        j->transaction_prev = j->transaction_next = NULL;
+
+        while (j->subject_list)
+                job_dependency_free(j->subject_list);
+
+        while (j->object_list) {
+                Job *other = j->object_list->matters ? j->object_list->subject : NULL;
+
+                job_dependency_free(j->object_list);
+
+                if (other && delete_dependencies) {
+                        log_debug("Deleting job %s/%s as dependency of job %s/%s",
+                                  other->unit->meta.id, job_type_to_string(other->type),
+                                  j->unit->meta.id, job_type_to_string(j->type));
+                        transaction_delete_job(m, other, delete_dependencies);
+                }
+        }
+}
+
+static int transaction_add_job_and_dependencies(
+                Manager *m,
+                JobType type,
+                Unit *unit,
+                Job *by,
+                bool matters,
+                bool override,
+                Job **_ret) {
+        Job *ret;
+        Iterator i;
+        Unit *dep;
+        int r;
+        bool is_new;
+
+        assert(m);
+        assert(type < _JOB_TYPE_MAX);
+        assert(unit);
+
+        if (unit->meta.load_state != UNIT_LOADED)
+                return -EINVAL;
+
+        if (!unit_job_is_applicable(unit, type))
+                return -EBADR;
+
+        /* First add the job. */
+        if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
+                return -ENOMEM;
+
+        /* Then, add a link to the job. */
+        if (!job_dependency_new(by, ret, matters))
+                return -ENOMEM;
+
+        if (is_new) {
+                /* Finally, recursively add in all dependencies. */
+                if (type == JOB_START || type == JOB_RELOAD_OR_START) {
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
+                                        goto fail;
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, NULL)) < 0)
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
+                                        goto fail;
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
+                                        goto fail;
+
+                } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
+                                        goto fail;
+                }
+
+                /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
+        }
+
+        if (_ret)
+                *_ret = ret;
+
+        return 0;
+
+fail:
+        return r;
+}
+
+static int transaction_add_isolate_jobs(Manager *m) {
+        Iterator i;
+        Unit *u;
+        char *k;
+        int r;
+
+        assert(m);
+
+        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+
+                /* ignore aliases */
+                if (u->meta.id != k)
+                        continue;
+
+                if (UNIT_VTABLE(u)->no_isolate)
+                        continue;
+
+                /* No need to stop inactive jobs */
+                if (unit_active_state(u) == UNIT_INACTIVE)
+                        continue;
+
+                /* Is there already something listed for this? */
+                if (hashmap_get(m->transaction_jobs, u))
+                        continue;
+
+                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, NULL)) < 0)
+                        log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r));
+        }
+
+        return 0;
+}
+
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, Job **_ret) {
+        int r;
+        Job *ret;
+
+        assert(m);
+        assert(type < _JOB_TYPE_MAX);
+        assert(unit);
+        assert(mode < _JOB_MODE_MAX);
+
+        if (mode == JOB_ISOLATE && type != JOB_START)
+                return -EINVAL;
+
+        log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type));
+
+        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, &ret)) < 0) {
+                transaction_abort(m);
+                return r;
+        }
+
+        if (mode == JOB_ISOLATE)
+                if ((r = transaction_add_isolate_jobs(m)) < 0) {
+                        transaction_abort(m);
+                        return r;
+                }
+
+        if ((r = transaction_activate(m, mode)) < 0)
+                return r;
+
+        log_debug("Enqueued job %s/%s as %u", unit->meta.id, job_type_to_string(type), (unsigned) ret->id);
+
+        if (_ret)
+                *_ret = ret;
+
+        return 0;
+}
+
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, Job **_ret) {
+        Unit *unit;
+        int r;
+
+        assert(m);
+        assert(type < _JOB_TYPE_MAX);
+        assert(name);
+        assert(mode < _JOB_MODE_MAX);
+
+        if ((r = manager_load_unit(m, name, NULL, &unit)) < 0)
+                return r;
+
+        return manager_add_job(m, type, unit, mode, override, _ret);
+}
+
+Job *manager_get_job(Manager *m, uint32_t id) {
+        assert(m);
+
+        return hashmap_get(m->jobs, UINT32_TO_PTR(id));
+}
+
+Unit *manager_get_unit(Manager *m, const char *name) {
+        assert(m);
+        assert(name);
+
+        return hashmap_get(m->units, name);
+}
+
+unsigned manager_dispatch_load_queue(Manager *m) {
+        Meta *meta;
+        unsigned n = 0;
+
+        assert(m);
+
+        /* Make sure we are not run recursively */
+        if (m->dispatching_load_queue)
+                return 0;
+
+        m->dispatching_load_queue = true;
+
+        /* Dispatches the load queue. Takes a unit from the queue and
+         * tries to load its data until the queue is empty */
+
+        while ((meta = m->load_queue)) {
+                assert(meta->in_load_queue);
+
+                unit_load(UNIT(meta));
+                n++;
+        }
+
+        m->dispatching_load_queue = false;
+        return n;
+}
+
+int manager_load_unit_prepare(Manager *m, const char *name, const char *path, Unit **_ret) {
+        Unit *ret;
+        int r;
+
+        assert(m);
+        assert(name || path);
+
+        /* This will prepare the unit for loading, but not actually
+         * load anything from disk. */
+
+        if (path && !is_path(path))
+                return -EINVAL;
+
+        if (!name)
+                name = file_name_from_path(path);
+
+        if (!unit_name_is_valid(name))
+                return -EINVAL;
+
+        if ((ret = manager_get_unit(m, name))) {
+                *_ret = ret;
+                return 1;
+        }
+
+        if (!(ret = unit_new(m)))
+                return -ENOMEM;
+
+        if (path)
+                if (!(ret->meta.fragment_path = strdup(path))) {
+                        unit_free(ret);
+                        return -ENOMEM;
+                }
+
+        if ((r = unit_add_name(ret, name)) < 0) {
+                unit_free(ret);
+                return r;
+        }
+
+        unit_add_to_load_queue(ret);
+        unit_add_to_dbus_queue(ret);
+        unit_add_to_gc_queue(ret);
+
+        if (_ret)
+                *_ret = ret;
+
+        return 0;
+}
+
+int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret) {
+        int r;
+
+        assert(m);
+
+        /* This will load the service information files, but not actually
+         * start any services or anything. */
+
+        if ((r = manager_load_unit_prepare(m, name, path, _ret)) != 0)
+                return r;
+
+        manager_dispatch_load_queue(m);
+
+        if (_ret)
+                *_ret = unit_follow_merge(*_ret);
+
+        return 0;
+}
+
+void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
+        Iterator i;
+        Job *j;
+
+        assert(s);
+        assert(f);
+
+        HASHMAP_FOREACH(j, s->jobs, i)
+                job_dump(j, f, prefix);
+}
+
+void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
+        Iterator i;
+        Unit *u;
+        const char *t;
+
+        assert(s);
+        assert(f);
+
+        HASHMAP_FOREACH_KEY(u, t, s->units, i)
+                if (u->meta.id == t)
+                        unit_dump(u, f, prefix);
+}
+
+void manager_clear_jobs(Manager *m) {
+        Job *j;
+
+        assert(m);
+
+        transaction_abort(m);
+
+        while ((j = hashmap_first(m->jobs)))
+                job_free(j);
+}
+
+unsigned manager_dispatch_run_queue(Manager *m) {
+        Job *j;
+        unsigned n = 0;
+
+        if (m->dispatching_run_queue)
+                return 0;
+
+        m->dispatching_run_queue = true;
+
+        while ((j = m->run_queue)) {
+                assert(j->installed);
+                assert(j->in_run_queue);
+
+                job_run_and_invalidate(j);
+                n++;
+        }
+
+        m->dispatching_run_queue = false;
+        return n;
+}
+
+unsigned manager_dispatch_dbus_queue(Manager *m) {
+        Job *j;
+        Meta *meta;
+        unsigned n = 0;
+
+        assert(m);
+
+        if (m->dispatching_dbus_queue)
+                return 0;
+
+        m->dispatching_dbus_queue = true;
+
+        while ((meta = m->dbus_unit_queue)) {
+                assert(meta->in_dbus_queue);
+
+                bus_unit_send_change_signal(UNIT(meta));
+                n++;
+        }
+
+        while ((j = m->dbus_job_queue)) {
+                assert(j->in_dbus_queue);
+
+                bus_job_send_change_signal(j);
+                n++;
+        }
+
+        m->dispatching_dbus_queue = false;
+        return n;
+}
+
+static int manager_dispatch_sigchld(Manager *m) {
+        assert(m);
+
+        for (;;) {
+                siginfo_t si;
+                Unit *u;
+
+                zero(si);
+
+                /* First we call waitd() for a PID and do not reap the
+                 * zombie. That way we can still access /proc/$PID for
+                 * it while it is a zombie. */
+                if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
+
+                        if (errno == ECHILD)
+                                break;
+
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+                }
+
+                if (si.si_pid <= 0)
+                        break;
+
+                if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
+                        char *name = NULL;
+
+                        get_process_name(si.si_pid, &name);
+                        log_debug("Got SIGCHLD for process %llu (%s)", (unsigned long long) si.si_pid, strna(name));
+                        free(name);
+                }
+
+                /* And now, we actually reap the zombie. */
+                if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+                }
+
+                if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
+                        continue;
+
+                log_debug("Child %llu died (code=%s, status=%i/%s)",
+                          (long long unsigned) si.si_pid,
+                          sigchld_code_to_string(si.si_code),
+                          si.si_status,
+                          strna(si.si_code == CLD_EXITED ? exit_status_to_string(si.si_status) : strsignal(si.si_status)));
+
+                if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
+                        continue;
+
+                log_debug("Child %llu belongs to %s", (long long unsigned) si.si_pid, u->meta.id);
+
+                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
+        }
+
+        return 0;
+}
+
+static void manager_start_target(Manager *m, const char *name) {
+        int r;
+
+        if ((r = manager_add_job_by_name(m, JOB_START, name, JOB_REPLACE, true, NULL)) < 0)
+                log_error("Failed to enqueue %s job: %s", name, strerror(-r));
+}
+
+static int manager_process_signal_fd(Manager *m) {
+        ssize_t n;
+        struct signalfd_siginfo sfsi;
+        bool sigchld = false;
+
+        assert(m);
+
+        for (;;) {
+                if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
+
+                        if (n >= 0)
+                                return -EIO;
+
+                        if (errno == EAGAIN)
+                                break;
+
+                        return -errno;
+                }
+
+                switch (sfsi.ssi_signo) {
+
+                case SIGCHLD:
+                        sigchld = true;
+                        break;
+
+                case SIGTERM:
+                        if (m->running_as == MANAGER_INIT)
+                                /* This is for compatibility with the
+                                 * original sysvinit */
+                                m->exit_code = MANAGER_REEXECUTE;
+                        else
+                                m->exit_code = MANAGER_EXIT;
+
+                        return 0;
+
+                case SIGINT:
+                        if (m->running_as == MANAGER_INIT) {
+                                manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET);
+                                break;
+                        }
+
+                        m->exit_code = MANAGER_EXIT;
+                        return 0;
+
+                case SIGWINCH:
+                        if (m->running_as == MANAGER_INIT)
+                                manager_start_target(m, SPECIAL_KBREQUEST_TARGET);
+
+                        /* This is a nop on non-init */
+                        break;
+
+                case SIGPWR:
+                        if (m->running_as == MANAGER_INIT)
+                                manager_start_target(m, SPECIAL_SIGPWR_TARGET);
+
+                        /* This is a nop on non-init */
+                        break;
+
+                case SIGUSR1: {
+                        Unit *u;
+
+                        u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
+
+                        if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
+                                log_info("Trying to reconnect to bus...");
+                                bus_init_system(m);
+                                bus_init_api(m);
+                        }
+
+                        if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
+                                log_info("Loading D-Bus service...");
+                                manager_start_target(m, SPECIAL_DBUS_SERVICE);
+                        }
+
+                        break;
+                }
+
+                case SIGUSR2:
+                        manager_dump_units(m, stdout, "\t");
+                        manager_dump_jobs(m, stdout, "\t");
+                        break;
+
+                case SIGHUP:
+                        m->exit_code = MANAGER_RELOAD;
+                        break;
+
+                default:
+                        log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo));
+                }
+        }
+
+        if (sigchld)
+                return manager_dispatch_sigchld(m);
+
+        return 0;
+}
+
+static int process_event(Manager *m, struct epoll_event *ev) {
+        int r;
+        Watch *w;
+
+        assert(m);
+        assert(ev);
+
+        assert(w = ev->data.ptr);
+
+        switch (w->type) {
+
+        case WATCH_SIGNAL:
+
+                /* An incoming signal? */
+                if (ev->events != EPOLLIN)
+                        return -EINVAL;
+
+                if ((r = manager_process_signal_fd(m)) < 0)
+                        return r;
+
+                break;
+
+        case WATCH_FD:
+
+                /* Some fd event, to be dispatched to the units */
+                UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w);
+                break;
+
+        case WATCH_TIMER: {
+                uint64_t v;
+                ssize_t k;
+
+                /* Some timer event, to be dispatched to the units */
+                if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
+
+                        if (k < 0 && (errno == EINTR || errno == EAGAIN))
+                                break;
+
+                        return k < 0 ? -errno : -EIO;
+                }
+
+                UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
+                break;
+        }
+
+        case WATCH_MOUNT:
+                /* Some mount table change, intended for the mount subsystem */
+                mount_fd_event(m, ev->events);
+                break;
+
+        case WATCH_UDEV:
+                /* Some notification from udev, intended for the device subsystem */
+                device_fd_event(m, ev->events);
+                break;
+
+        case WATCH_DBUS_WATCH:
+                bus_watch_event(m, w, ev->events);
+                break;
+
+        case WATCH_DBUS_TIMEOUT:
+                bus_timeout_event(m, w, ev->events);
+                break;
+
+        default:
+                assert_not_reached("Unknown epoll event type.");
+        }
+
+        return 0;
+}
+
+int manager_loop(Manager *m) {
+        int r;
+
+        RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
+
+        assert(m);
+        m->exit_code = MANAGER_RUNNING;
+
+        while (m->exit_code == MANAGER_RUNNING) {
+                struct epoll_event event;
+                int n;
+
+                if (!ratelimit_test(&rl)) {
+                        /* Yay, something is going seriously wrong, pause a little */
+                        log_warning("Looping too fast. Throttling execution a little.");
+                        sleep(1);
+                }
+
+                if (manager_dispatch_load_queue(m) > 0)
+                        continue;
+
+                if (manager_dispatch_run_queue(m) > 0)
+                        continue;
+
+                if (bus_dispatch(m) > 0)
+                        continue;
+
+                if (manager_dispatch_cleanup_queue(m) > 0)
+                        continue;
+
+                if (manager_dispatch_gc_queue(m) > 0)
+                        continue;
+
+                if (manager_dispatch_dbus_queue(m) > 0)
+                        continue;
+
+                if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+                }
+
+                assert(n == 1);
+
+                if ((r = process_event(m, &event)) < 0)
+                        return r;
+        }
+
+        return m->exit_code;
+}
+
+int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) {
+        char *n;
+        Unit *u;
+
+        assert(m);
+        assert(s);
+        assert(_u);
+
+        if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
+                return -EINVAL;
+
+        if (!(n = bus_path_unescape(s+31)))
+                return -ENOMEM;
+
+        u = manager_get_unit(m, n);
+        free(n);
+
+        if (!u)
+                return -ENOENT;
+
+        *_u = u;
+
+        return 0;
+}
+
+int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
+        Job *j;
+        unsigned id;
+        int r;
+
+        assert(m);
+        assert(s);
+        assert(_j);
+
+        if (!startswith(s, "/org/freedesktop/systemd1/job/"))
+                return -EINVAL;
+
+        if ((r = safe_atou(s + 30, &id)) < 0)
+                return r;
+
+        if (!(j = manager_get_job(m, id)))
+                return -ENOENT;
+
+        *_j = j;
+
+        return 0;
+}
+
+static bool manager_utmp_good(Manager *m) {
+        int r;
+
+        assert(m);
+
+        if ((r = mount_path_is_mounted(m, _PATH_UTMPX)) <= 0) {
+
+                if (r < 0)
+                        log_warning("Failed to determine whether " _PATH_UTMPX " is mounted: %s", strerror(-r));
+
+                return false;
+        }
+
+        return true;
+}
+
+void manager_write_utmp_reboot(Manager *m) {
+        int r;
+
+        assert(m);
+
+        if (m->utmp_reboot_written)
+                return;
+
+        if (m->running_as != MANAGER_INIT)
+                return;
+
+        if (!manager_utmp_good(m))
+                return;
+
+        if ((r = utmp_put_reboot(m->boot_timestamp)) < 0) {
+
+                if (r != -ENOENT && r != -EROFS)
+                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
+
+                return;
+        }
+
+        m->utmp_reboot_written = true;
+}
+
+void manager_write_utmp_runlevel(Manager *m, Unit *u) {
+        int runlevel, r;
+
+        assert(m);
+        assert(u);
+
+        if (u->meta.type != UNIT_TARGET)
+                return;
+
+        if (m->running_as != MANAGER_INIT)
+                return;
+
+        if (!manager_utmp_good(m))
+                return;
+
+        if ((runlevel = target_get_runlevel(TARGET(u))) <= 0)
+                return;
+
+        if ((r = utmp_put_runlevel(0, runlevel, 0)) < 0) {
+
+                if (r != -ENOENT && r != -EROFS)
+                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
+        }
+}
+
+void manager_dispatch_bus_name_owner_changed(
+                Manager *m,
+                const char *name,
+                const char* old_owner,
+                const char *new_owner) {
+
+        Unit *u;
+
+        assert(m);
+        assert(name);
+
+        if (!(u = hashmap_get(m->watch_bus, name)))
+                return;
+
+        UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
+}
+
+void manager_dispatch_bus_query_pid_done(
+                Manager *m,
+                const char *name,
+                pid_t pid) {
+
+        Unit *u;
+
+        assert(m);
+        assert(name);
+        assert(pid >= 1);
+
+        if (!(u = hashmap_get(m->watch_bus, name)))
+                return;
+
+        UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
+}
+
+int manager_open_serialization(FILE **_f) {
+        char *path;
+        mode_t saved_umask;
+        int fd;
+        FILE *f;
+
+        assert(_f);
+
+        if (asprintf(&path, "/dev/shm/systemd-%u.dump-XXXXXX", (unsigned) getpid()) < 0)
+                return -ENOMEM;
+
+        saved_umask = umask(0077);
+        fd = mkostemp(path, O_RDWR|O_CLOEXEC);
+        umask(saved_umask);
+
+        if (fd < 0) {
+                free(path);
+                return -errno;
+        }
+
+        unlink(path);
+
+        log_debug("Serializing state to %s", path);
+        free(path);
+
+        if (!(f = fdopen(fd, "w+")) < 0)
+                return -errno;
+
+        *_f = f;
+
+        return 0;
+}
+
+int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
+        Iterator i;
+        Unit *u;
+        const char *t;
+        int r;
+
+        assert(m);
+        assert(f);
+        assert(fds);
+
+        HASHMAP_FOREACH_KEY(u, t, m->units, i) {
+                if (u->meta.id != t)
+                        continue;
+
+                if (!unit_can_serialize(u))
+                        continue;
+
+                /* Start marker */
+                fputs(u->meta.id, f);
+                fputc('\n', f);
+
+                if ((r = unit_serialize(u, f, fds)) < 0)
+                        return r;
+        }
+
+        if (ferror(f))
+                return -EIO;
+
+        return 0;
+}
+
+int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
+        int r = 0;
+
+        assert(m);
+        assert(f);
+
+        log_debug("Deserializing state...");
+
+        for (;;) {
+                Unit *u;
+                char name[UNIT_NAME_MAX+2];
+
+                /* Start marker */
+                if (!fgets(name, sizeof(name), f)) {
+                        if (feof(f))
+                                break;
+
+                        return -errno;
+                }
+
+                char_array_0(name);
+
+                if ((r = manager_load_unit(m, strstrip(name), NULL, &u)) < 0)
+                        return r;
+
+                if ((r = unit_deserialize(u, f, fds)) < 0)
+                        return r;
+        }
+
+        if (ferror(f))
+                return -EIO;
+
+        return 0;
+}
+
+int manager_reload(Manager *m) {
+        int r, q;
+        FILE *f;
+        FDSet *fds;
+
+        assert(m);
+
+        if ((r = manager_open_serialization(&f)) < 0)
+                return r;
+
+        if (!(fds = fdset_new())) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if ((r = manager_serialize(m, f, fds)) < 0)
+                goto finish;
+
+        if (fseeko(f, 0, SEEK_SET) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        /* From here on there is no way back. */
+        manager_clear_jobs_and_units(m);
+
+        /* First, enumerate what we can from all config files */
+        if ((q = manager_enumerate(m)) < 0)
+                r = q;
+
+        /* Second, deserialize our stored data */
+        if ((q = manager_deserialize(m, f, fds)) < 0)
+                r = q;
+
+        fclose(f);
+        f = NULL;
+
+        /* Third, fire things up! */
+        if ((q = manager_coldplug(m)) < 0)
+                r = q;
+
+finish:
+        if (f)
+                fclose(f);
+
+        if (fds)
+                fdset_free(fds);
+
+        return r;
+}
+
+static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
+        [MANAGER_INIT] = "init",
+        [MANAGER_SYSTEM] = "system",
+        [MANAGER_SESSION] = "session"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);
diff --git a/src/manager.h b/src/manager.h
new file mode 100644
index 0000000..a6500ac
--- /dev/null
+++ b/src/manager.h
@@ -0,0 +1,284 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foomanagerhfoo
+#define foomanagerhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <dbus/dbus.h>
+
+#include "fdset.h"
+
+/* Enforce upper limit how many names we allow */
+#define MANAGER_MAX_NAMES 2048
+
+typedef struct Manager Manager;
+typedef enum WatchType WatchType;
+typedef struct Watch Watch;
+
+typedef enum ManagerExitCode {
+        MANAGER_RUNNING,
+        MANAGER_EXIT,
+        MANAGER_RELOAD,
+        MANAGER_REEXECUTE,
+        _MANAGER_EXIT_CODE_MAX,
+        _MANAGER_EXIT_CODE_INVALID = -1
+} ManagerExitCode;
+
+typedef enum ManagerRunningAs {
+        MANAGER_INIT,      /* root and pid=1 */
+        MANAGER_SYSTEM,    /* root and pid!=1 */
+        MANAGER_SESSION,   /* non-root, for a session */
+        _MANAGER_RUNNING_AS_MAX,
+        _MANAGER_RUNNING_AS_INVALID = -1
+} ManagerRunningAs;
+
+enum WatchType {
+        WATCH_INVALID,
+        WATCH_SIGNAL,
+        WATCH_FD,
+        WATCH_TIMER,
+        WATCH_MOUNT,
+        WATCH_UDEV,
+        WATCH_DBUS_WATCH,
+        WATCH_DBUS_TIMEOUT
+};
+
+struct Watch {
+        int fd;
+        WatchType type;
+        union {
+                union Unit *unit;
+                DBusWatch *bus_watch;
+                DBusTimeout *bus_timeout;
+        } data;
+        bool fd_is_dupped:1;
+        bool socket_accept:1;
+};
+
+#include "unit.h"
+#include "job.h"
+#include "hashmap.h"
+#include "list.h"
+#include "set.h"
+#include "dbus.h"
+
+#define SPECIAL_DEFAULT_TARGET "default.target"
+
+/* This is not really intended to be started by directly. This is
+ * mostly so that other targets (reboot/halt/poweroff) can depend on
+ * it to bring all services down that want to be brought down on
+ * system shutdown. */
+#define SPECIAL_SHUTDOWN_TARGET "shutdown.target"
+
+#define SPECIAL_LOGGER_SOCKET "systemd-logger.socket"
+
+#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
+#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
+#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
+
+#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"
+#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target"
+#define SPECIAL_SWAP_TARGET "swap.target"
+#define SPECIAL_NETWORK_TARGET "network.target"
+#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target"     /* LSB's $named */
+#define SPECIAL_RPCBIND_TARGET "rpcbind.target"           /* LSB's $portmap */
+#define SPECIAL_SYSLOG_TARGET "syslog.target"             /* Should pull in syslog.socket or syslog.service */
+#define SPECIAL_RTC_SET_TARGET "rtc-set.target"           /* LSB's $time */
+
+#define SPECIAL_BASIC_TARGET "basic.target"
+#define SPECIAL_RESCUE_TARGET "rescue.target"
+
+#ifndef SPECIAL_DBUS_SERVICE
+#define SPECIAL_DBUS_SERVICE "dbus.service"
+#endif
+
+#ifndef SPECIAL_SYSLOG_SERVICE
+#define SPECIAL_SYSLOG_SERVICE "syslog.service"
+#endif
+
+/* For SysV compatibility. Usually an alias for a saner target. On
+ * SysV-free systems this doesn't exist. */
+#define SPECIAL_RUNLEVEL0_TARGET "runlevel0.target"
+#define SPECIAL_RUNLEVEL1_TARGET "runlevel1.target"
+#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target"
+#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
+#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
+#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
+#define SPECIAL_RUNLEVEL6_TARGET "runlevel6.target"
+
+struct Manager {
+        uint32_t current_job_id;
+
+        /* Note that the set of units we know of is allowed to be
+         * incosistent. However the subset of it that is loaded may
+         * not, and the list of jobs may neither. */
+
+        /* Active jobs and units */
+        Hashmap *units;  /* name string => Unit object n:1 */
+        Hashmap *jobs;   /* job id => Job object 1:1 */
+
+        /* To make it easy to iterate through the units of a specific
+         * type we maintain a per type linked list */
+        LIST_HEAD(Meta, units_per_type[_UNIT_TYPE_MAX]);
+
+        /* Units that need to be loaded */
+        LIST_HEAD(Meta, load_queue); /* this is actually more a stack than a queue, but uh. */
+
+        /* Jobs that need to be run */
+        LIST_HEAD(Job, run_queue);   /* more a stack than a queue, too */
+
+        /* Units and jobs that have not yet been announced via
+         * D-Bus. When something about a job changes it is added here
+         * if it is not in there yet. This allows easy coalescing of
+         * D-Bus change signals. */
+        LIST_HEAD(Meta, dbus_unit_queue);
+        LIST_HEAD(Job, dbus_job_queue);
+
+        /* Units to remove */
+        LIST_HEAD(Meta, cleanup_queue);
+
+        /* Units to check when doing GC */
+        LIST_HEAD(Meta, gc_queue);
+
+        /* Jobs to be added */
+        Hashmap *transaction_jobs;      /* Unit object => Job object list 1:1 */
+        JobDependency *transaction_anchor;
+
+        Hashmap *watch_pids;  /* pid => Unit object n:1 */
+
+        Watch signal_watch;
+
+        int epoll_fd;
+
+        unsigned n_snapshots;
+
+        char **unit_path;
+        char **sysvinit_path;
+        char **sysvrcnd_path;
+
+        char **environment;
+
+        usec_t boot_timestamp;
+
+        /* Data specific to the device subsystem */
+        struct udev* udev;
+        struct udev_monitor* udev_monitor;
+        Watch udev_watch;
+
+        /* Data specific to the mount subsystem */
+        FILE *proc_self_mountinfo;
+        Watch mount_watch;
+
+        /* Data specific to the swap filesystem */
+        FILE *proc_swaps;
+
+        /* Data specific to the D-Bus subsystem */
+        DBusConnection *api_bus, *system_bus;
+        Set *subscribed;
+        DBusMessage *queued_message; /* This is used during reloading:
+                                      * before the reload we queue the
+                                      * reply message here, and
+                                      * afterwards we send it */
+
+        Hashmap *watch_bus;  /* D-Bus names => Unit object n:1 */
+        int32_t name_data_slot;
+
+        /* Data specific to the Automount subsystem */
+        int dev_autofs_fd;
+
+        /* Data specific to the cgroup subsystem */
+        Hashmap *cgroup_bondings; /* path string => CGroupBonding object 1:n */
+        char *cgroup_controller;
+        char *cgroup_hierarchy;
+
+        usec_t gc_queue_timestamp;
+
+        int gc_marker;
+        unsigned n_in_gc_queue;
+
+        /* Flags */
+        ManagerRunningAs running_as;
+        ManagerExitCode exit_code:4;
+
+        bool dispatching_load_queue:1;
+        bool dispatching_run_queue:1;
+        bool dispatching_dbus_queue:1;
+
+        bool request_api_bus_dispatch:1;
+        bool request_system_bus_dispatch:1;
+
+        bool utmp_reboot_written:1;
+
+        bool confirm_spawn:1;
+};
+
+int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **m);
+void manager_free(Manager *m);
+
+int manager_enumerate(Manager *m);
+int manager_coldplug(Manager *m);
+int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
+
+Job *manager_get_job(Manager *m, uint32_t id);
+Unit *manager_get_unit(Manager *m, const char *name);
+
+int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u);
+int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
+
+int manager_load_unit_prepare(Manager *m, const char *name, const char *path, Unit **_ret);
+int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret);
+
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, Job **_ret);
+
+void manager_dump_units(Manager *s, FILE *f, const char *prefix);
+void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
+
+void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies);
+
+void manager_clear_jobs(Manager *m);
+
+unsigned manager_dispatch_load_queue(Manager *m);
+unsigned manager_dispatch_run_queue(Manager *m);
+unsigned manager_dispatch_dbus_queue(Manager *m);
+
+int manager_loop(Manager *m);
+
+void manager_write_utmp_reboot(Manager *m);
+void manager_write_utmp_runlevel(Manager *m, Unit *t);
+
+void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
+void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid);
+
+int manager_open_serialization(FILE **_f);
+
+int manager_serialize(Manager *m, FILE *f, FDSet *fds);
+int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
+
+int manager_reload(Manager *m);
+
+const char *manager_running_as_to_string(ManagerRunningAs i);
+ManagerRunningAs manager_running_as_from_string(const char *s);
+
+#endif
diff --git a/src/missing.h b/src/missing.h
new file mode 100644
index 0000000..7db7d7d
--- /dev/null
+++ b/src/missing.h
@@ -0,0 +1,38 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foomissinghfoo
+#define foomissinghfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+/* Missing glibc definitions to access certain kernel APIs */
+
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#ifndef RLIMIT_RTTIME
+#define RLIMIT_RTTIME 15
+#endif
+
+static inline int pivot_root(const char *new_root, const char *put_old) {
+        return syscall(SYS_pivot_root, new_root, put_old);
+}
+
+#endif
diff --git a/src/mount-setup.c b/src/mount-setup.c
new file mode 100644
index 0000000..cb91e18
--- /dev/null
+++ b/src/mount-setup.c
@@ -0,0 +1,168 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/mount.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <assert.h>
+
+#include "mount-setup.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+
+typedef struct MountPoint {
+        const char *what;
+        const char *where;
+        const char *type;
+        const char *options;
+        unsigned long flags;
+        bool fatal;
+} MountPoint;
+
+static const MountPoint mount_table[] = {
+        { "proc",        "/proc",                    "proc",        NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "sysfs",       "/sys",                     "sysfs",       NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "devtmps",     "/dev",                     "devtmpfs",    "mode=755",  MS_NOSUID,                    true },
+        { "tmpfs",       "/dev/shm",                 "tmpfs",       "mode=1777", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "devpts",      "/dev/pts",                 "devpts",      NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "cgroup",      "/cgroup/debug",            "cgroup",      "debug",     MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "debugfs",     "/sys/kernel/debug",        "debugfs",     NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "binfmt_misc", "/proc/sys/fs/binfmt_misc", "binfmt_misc", NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "mqueue",      "/dev/mqueue",              "mqueue",      NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+};
+
+bool mount_point_is_api(const char *path) {
+        unsigned i;
+
+        /* Checks if this mount point is considered "API", and hence
+         * should be ignored */
+
+        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
+                if (path_startswith(path, mount_table[i].where))
+                        return true;
+
+        return path_startswith(path, "/cgroup/");
+}
+
+static int mount_one(const MountPoint *p) {
+        int r;
+
+        assert(p);
+
+        if ((r = path_is_mount_point(p->where)) < 0)
+                return r;
+
+        if (r > 0)
+                return 0;
+
+        /* The access mode here doesn't really matter too much, since
+         * the mounted file system will take precedence anyway. */
+        mkdir_p(p->where, 0755);
+
+        log_debug("Mounting %s to %s of type %s with options %s.",
+                  p->what,
+                  p->where,
+                  p->type,
+                  strna(p->options));
+
+        if (mount(p->what,
+                  p->where,
+                  p->type,
+                  p->flags,
+                  p->options) < 0) {
+                log_error("Failed to mount %s: %s", p->where, strerror(errno));
+                return p->fatal ? -errno : 0;
+        }
+
+        return 0;
+}
+
+static int mount_cgroup_controllers(void) {
+        int r;
+        FILE *f;
+        char buf [256];
+
+        /* Mount all available cgroup controllers. */
+
+        if (!(f = fopen("/proc/cgroups", "re")))
+                return -ENOENT;
+
+        /* Ignore the header line */
+        (void) fgets(buf, sizeof(buf), f);
+
+        for (;;) {
+                MountPoint p;
+                char *controller, *where;
+
+                if (fscanf(f, "%ms %*i %*i %*i", &controller) != 1) {
+
+                        if (feof(f))
+                                break;
+
+                        log_error("Failed to parse /proc/cgroups.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (asprintf(&where, "/cgroup/%s", controller) < 0) {
+                        free(controller);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                zero(p);
+                p.what = "cgroup";
+                p.where = where;
+                p.type = "cgroup";
+                p.options = controller;
+                p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
+                p.fatal = false;
+
+                r = mount_one(&p);
+                free(controller);
+                free(where);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        fclose(f);
+
+        return r;
+}
+
+int mount_setup(void) {
+        int r;
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
+                if ((r = mount_one(mount_table+i)) < 0)
+                        return r;
+
+        return mount_cgroup_controllers();
+}
diff --git a/src/mount-setup.h b/src/mount-setup.h
new file mode 100644
index 0000000..bb13e01
--- /dev/null
+++ b/src/mount-setup.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foomountsetuphfoo
+#define foomountsetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+int mount_setup(void);
+
+bool mount_point_is_api(const char *path);
+
+#endif
diff --git a/src/mount.c b/src/mount.c
new file mode 100644
index 0000000..ec03a52
--- /dev/null
+++ b/src/mount.c
@@ -0,0 +1,1539 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <sys/epoll.h>
+#include <signal.h>
+
+#include "unit.h"
+#include "mount.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "log.h"
+#include "strv.h"
+#include "mount-setup.h"
+#include "unit-name.h"
+#include "mount.h"
+#include "dbus-mount.h"
+
+static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
+        [MOUNT_DEAD] = UNIT_INACTIVE,
+        [MOUNT_MOUNTING] = UNIT_ACTIVATING,
+        [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE,
+        [MOUNT_MOUNTED] = UNIT_ACTIVE,
+        [MOUNT_REMOUNTING] = UNIT_ACTIVE_RELOADING,
+        [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
+        [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
+        [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
+        [MOUNT_REMOUNTING_SIGTERM] = UNIT_ACTIVE_RELOADING,
+        [MOUNT_REMOUNTING_SIGKILL] = UNIT_ACTIVE_RELOADING,
+        [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
+        [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
+        [MOUNT_MAINTAINANCE] = UNIT_INACTIVE,
+};
+
+static void mount_init(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        m->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        exec_context_init(&m->exec_context);
+
+        /* We need to make sure that /bin/mount is always called in
+         * the same process group as us, so that the autofs kernel
+         * side doesn't send us another mount request while we are
+         * already trying to comply its last one. */
+        m->exec_context.no_setsid = true;
+
+        m->timer_watch.type = WATCH_INVALID;
+
+        m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
+}
+
+static void mount_unwatch_control_pid(Mount *m) {
+        assert(m);
+
+        if (m->control_pid <= 0)
+                return;
+
+        unit_unwatch_pid(UNIT(m), m->control_pid);
+        m->control_pid = 0;
+}
+
+static void mount_parameters_done(MountParameters *p) {
+        assert(p);
+
+        free(p->what);
+        free(p->options);
+        free(p->fstype);
+
+        p->what = p->options = p->fstype = NULL;
+}
+
+static void mount_done(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        free(m->where);
+        m->where = NULL;
+
+        mount_parameters_done(&m->parameters_etc_fstab);
+        mount_parameters_done(&m->parameters_proc_self_mountinfo);
+        mount_parameters_done(&m->parameters_fragment);
+
+        exec_context_done(&m->exec_context);
+        exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
+        m->control_command = NULL;
+
+        mount_unwatch_control_pid(m);
+
+        unit_unwatch_timer(u, &m->timer_watch);
+}
+
+static int mount_add_mount_links(Mount *m) {
+        Meta *other;
+        int r;
+
+        assert(m);
+
+        /* Adds in links to other mount points that might lie below or
+         * above us in the hierarchy */
+
+        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_MOUNT]) {
+                Mount *n = (Mount*) other;
+
+                if (n == m)
+                        continue;
+
+                if (n->meta.load_state != UNIT_LOADED)
+                        continue;
+
+                if (path_startswith(m->where, n->where)) {
+
+                        if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
+                                return r;
+
+                        if (n->from_etc_fstab || n->from_fragment)
+                                if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
+                                        return r;
+
+                } else if (path_startswith(n->where, m->where)) {
+
+                        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(n), true)) < 0)
+                                return r;
+
+                        if (m->from_etc_fstab || m->from_fragment)
+                                if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
+                                        return r;
+                }
+        }
+
+        return 0;
+}
+
+static int mount_add_swap_links(Mount *m) {
+        Meta *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SWAP])
+                if ((r = swap_add_one_mount_link((Swap*) other, m)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int mount_add_automount_links(Mount *m) {
+        Meta *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_AUTOMOUNT])
+                if ((r = automount_add_one_mount_link((Automount*) other, m)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int mount_add_socket_links(Mount *m) {
+        Meta *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SOCKET])
+                if ((r = socket_add_one_mount_link((Socket*) other, m)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static char* mount_test_option(const char *haystack, const char *needle) {
+        struct mntent me;
+
+        assert(needle);
+
+        /* Like glibc's hasmntopt(), but works on a string, not a
+         * struct mntent */
+
+        if (!haystack)
+                return false;
+
+        zero(me);
+        me.mnt_opts = (char*) haystack;
+
+        return hasmntopt(&me, needle);
+}
+
+static int mount_add_target_links(Mount *m) {
+        const char *target;
+        MountParameters *p;
+        Unit *tu;
+        int r;
+        bool noauto, handle, automount;
+
+        assert(m);
+
+        if (m->from_fragment)
+                p = &m->parameters_fragment;
+        else if (m->from_etc_fstab)
+                p = &m->parameters_etc_fstab;
+        else
+                return 0;
+
+        noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO);
+        handle = !!mount_test_option(p->options, "comment=systemd.mount");
+        automount = !!mount_test_option(p->options, "comment=systemd.automount");
+
+        if (mount_test_option(p->options, "_netdev") ||
+            fstype_is_network(p->fstype))
+                target = SPECIAL_REMOTE_FS_TARGET;
+        else
+                target = SPECIAL_LOCAL_FS_TARGET;
+
+        if ((r = manager_load_unit(UNIT(m)->meta.manager, target, NULL, &tu)) < 0)
+                return r;
+
+        if (automount) {
+                Unit *am;
+
+                if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0)
+                        return r;
+
+                if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(am), true)) < 0)
+                        return r;
+
+                return unit_add_dependency(UNIT(am), UNIT_BEFORE, tu, true);
+
+        } else {
+
+                if (!noauto && handle)
+                        if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0)
+                                return r;
+
+                return unit_add_dependency(UNIT(m), UNIT_BEFORE, tu, true);
+        }
+}
+
+static int mount_verify(Mount *m) {
+        bool b;
+        char *e;
+        assert(m);
+
+        if (UNIT(m)->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (!(e = unit_name_from_path(m->where, ".mount")))
+                return -ENOMEM;
+
+        b = unit_has_name(UNIT(m), e);
+        free(e);
+
+        if (!b) {
+                log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->meta.id);
+                return -EINVAL;
+        }
+
+        if (m->meta.fragment_path && !m->parameters_fragment.what) {
+                log_error("%s's What setting is missing. Refusing.", UNIT(m)->meta.id);
+                return -EBADMSG;
+        }
+
+        return 0;
+}
+
+static int mount_load(Unit *u) {
+        Mount *m = MOUNT(u);
+        int r;
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
+                return r;
+
+        /* This is a new unit? Then let's add in some extras */
+        if (u->meta.load_state == UNIT_LOADED) {
+                const char *what = NULL;
+
+                if (m->meta.fragment_path)
+                        m->from_fragment = true;
+
+                if (!m->where)
+                        if (!(m->where = unit_name_to_path(u->meta.id)))
+                                return -ENOMEM;
+
+                path_kill_slashes(m->where);
+
+                if (!m->meta.description)
+                        if ((r = unit_set_description(u, m->where)) < 0)
+                                return r;
+
+                if (m->from_fragment && m->parameters_fragment.what)
+                        what = m->parameters_fragment.what;
+                else if (m->from_etc_fstab && m->parameters_etc_fstab.what)
+                        what = m->parameters_etc_fstab.what;
+                else if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what)
+                        what = m->parameters_proc_self_mountinfo.what;
+
+                if (what)
+                        if ((r = unit_add_node_link(u, what,
+                                                    (u->meta.manager->running_as == MANAGER_INIT ||
+                                                     u->meta.manager->running_as == MANAGER_SYSTEM))) < 0)
+                                return r;
+
+                if ((r = mount_add_mount_links(m)) < 0)
+                        return r;
+
+                if ((r = mount_add_socket_links(m)) < 0)
+                        return r;
+
+                if ((r = mount_add_swap_links(m)) < 0)
+                        return r;
+
+                if ((r = mount_add_automount_links(m)) < 0)
+                        return r;
+
+                if ((r = mount_add_target_links(m)) < 0)
+                        return r;
+
+                if ((r = unit_add_default_cgroup(u)) < 0)
+                        return r;
+        }
+
+        return mount_verify(m);
+}
+
+static int mount_notify_automount(Mount *m, int status) {
+        Unit *p;
+        int r;
+
+        assert(m);
+
+        if ((r = unit_get_related_unit(UNIT(m), ".automount", &p)) < 0)
+                return r == -ENOENT ? 0 : r;
+
+        return automount_send_ready(AUTOMOUNT(p), status);
+}
+
+static void mount_set_state(Mount *m, MountState state) {
+        MountState old_state;
+        assert(m);
+
+        old_state = m->state;
+        m->state = state;
+
+        if (state != MOUNT_MOUNTING &&
+            state != MOUNT_MOUNTING_DONE &&
+            state != MOUNT_REMOUNTING &&
+            state != MOUNT_UNMOUNTING &&
+            state != MOUNT_MOUNTING_SIGTERM &&
+            state != MOUNT_MOUNTING_SIGKILL &&
+            state != MOUNT_UNMOUNTING_SIGTERM &&
+            state != MOUNT_UNMOUNTING_SIGKILL &&
+            state != MOUNT_REMOUNTING_SIGTERM &&
+            state != MOUNT_REMOUNTING_SIGKILL) {
+                unit_unwatch_timer(UNIT(m), &m->timer_watch);
+                mount_unwatch_control_pid(m);
+                m->control_command = NULL;
+                m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
+        }
+
+        if (state == MOUNT_MOUNTED ||
+            state == MOUNT_REMOUNTING)
+                mount_notify_automount(m, 0);
+        else if (state == MOUNT_DEAD ||
+                 state == MOUNT_UNMOUNTING ||
+                 state == MOUNT_MOUNTING_SIGTERM ||
+                 state == MOUNT_MOUNTING_SIGKILL ||
+                 state == MOUNT_REMOUNTING_SIGTERM ||
+                 state == MOUNT_REMOUNTING_SIGKILL ||
+                 state == MOUNT_UNMOUNTING_SIGTERM ||
+                 state == MOUNT_UNMOUNTING_SIGKILL ||
+                 state == MOUNT_MAINTAINANCE)
+                mount_notify_automount(m, -ENODEV);
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(m)->meta.id,
+                          mount_state_to_string(old_state),
+                          mount_state_to_string(state));
+
+        unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int mount_coldplug(Unit *u) {
+        Mount *m = MOUNT(u);
+        MountState new_state = MOUNT_DEAD;
+        int r;
+
+        assert(m);
+        assert(m->state == MOUNT_DEAD);
+
+        if (m->deserialized_state != m->state)
+                new_state = m->deserialized_state;
+        else if (m->from_proc_self_mountinfo)
+                new_state = MOUNT_MOUNTED;
+
+        if (new_state != m->state) {
+
+                if (new_state == MOUNT_MOUNTING ||
+                    new_state == MOUNT_MOUNTING_DONE ||
+                    new_state == MOUNT_REMOUNTING ||
+                    new_state == MOUNT_UNMOUNTING ||
+                    new_state == MOUNT_MOUNTING_SIGTERM ||
+                    new_state == MOUNT_MOUNTING_SIGKILL ||
+                    new_state == MOUNT_UNMOUNTING_SIGTERM ||
+                    new_state == MOUNT_UNMOUNTING_SIGKILL ||
+                    new_state == MOUNT_REMOUNTING_SIGTERM ||
+                    new_state == MOUNT_REMOUNTING_SIGKILL) {
+
+                        if (m->control_pid <= 0)
+                                return -EBADMSG;
+
+                        if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0)
+                                return r;
+
+                        if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
+                                return r;
+                }
+
+                mount_set_state(m, new_state);
+        }
+
+        return 0;
+}
+
+static void mount_dump(Unit *u, FILE *f, const char *prefix) {
+        Mount *m = MOUNT(u);
+        MountParameters *p;
+
+        assert(m);
+        assert(f);
+
+        if (m->from_proc_self_mountinfo)
+                p = &m->parameters_proc_self_mountinfo;
+        else if (m->from_fragment)
+                p = &m->parameters_fragment;
+        else
+                p = &m->parameters_etc_fstab;
+
+        fprintf(f,
+                "%sMount State: %s\n"
+                "%sWhere: %s\n"
+                "%sWhat: %s\n"
+                "%sFile System Type: %s\n"
+                "%sOptions: %s\n"
+                "%sFrom /etc/fstab: %s\n"
+                "%sFrom /proc/self/mountinfo: %s\n"
+                "%sFrom fragment: %s\n"
+                "%sKillMode: %s\n",
+                prefix, mount_state_to_string(m->state),
+                prefix, m->where,
+                prefix, strna(p->what),
+                prefix, strna(p->fstype),
+                prefix, strna(p->options),
+                prefix, yes_no(m->from_etc_fstab),
+                prefix, yes_no(m->from_proc_self_mountinfo),
+                prefix, yes_no(m->from_fragment),
+                prefix, kill_mode_to_string(m->kill_mode));
+
+        if (m->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %llu\n",
+                        prefix, (unsigned long long) m->control_pid);
+
+        exec_context_dump(&m->exec_context, f, prefix);
+}
+
+static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
+        pid_t pid;
+        int r;
+
+        assert(m);
+        assert(c);
+        assert(_pid);
+
+        if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
+                goto fail;
+
+        if ((r = exec_spawn(c,
+                            NULL,
+                            &m->exec_context,
+                            NULL, 0,
+                            m->meta.manager->environment,
+                            true,
+                            true,
+                            UNIT(m)->meta.manager->confirm_spawn,
+                            UNIT(m)->meta.cgroup_bondings,
+                            &pid)) < 0)
+                goto fail;
+
+        if ((r = unit_watch_pid(UNIT(m), pid)) < 0)
+                /* FIXME: we need to do something here */
+                goto fail;
+
+        *_pid = pid;
+
+        return 0;
+
+fail:
+        unit_unwatch_timer(UNIT(m), &m->timer_watch);
+
+        return r;
+}
+
+static void mount_enter_dead(Mount *m, bool success) {
+        assert(m);
+
+        if (!success)
+                m->failure = true;
+
+        mount_set_state(m, m->failure ? MOUNT_MAINTAINANCE : MOUNT_DEAD);
+}
+
+static void mount_enter_mounted(Mount *m, bool success) {
+        assert(m);
+
+        if (!success)
+                m->failure = true;
+
+        mount_set_state(m, MOUNT_MOUNTED);
+}
+
+static void mount_enter_signal(Mount *m, MountState state, bool success) {
+        int r;
+        bool sent = false;
+
+        assert(m);
+
+        if (!success)
+                m->failure = true;
+
+        if (m->kill_mode != KILL_NONE) {
+                int sig = (state == MOUNT_MOUNTING_SIGTERM ||
+                           state == MOUNT_UNMOUNTING_SIGTERM ||
+                           state == MOUNT_REMOUNTING_SIGTERM) ? SIGTERM : SIGKILL;
+
+                if (m->kill_mode == KILL_CONTROL_GROUP) {
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(m)->meta.cgroup_bondings, sig)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH)
+                                        goto fail;
+                        } else
+                                sent = true;
+                }
+
+                if (!sent && m->control_pid > 0)
+                        if (kill(m->kill_mode == KILL_PROCESS ? m->control_pid : -m->control_pid, sig) < 0 && errno != ESRCH) {
+                                r = -errno;
+                                goto fail;
+                        }
+        }
+
+        if (sent) {
+                if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
+                        goto fail;
+
+                mount_set_state(m, state);
+        } else if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
+                mount_enter_mounted(m, true);
+        else
+                mount_enter_dead(m, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", UNIT(m)->meta.id, strerror(-r));
+
+        if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
+                mount_enter_mounted(m, false);
+        else
+                mount_enter_dead(m, false);
+}
+
+static void mount_enter_unmounting(Mount *m, bool success) {
+        int r;
+
+        assert(m);
+
+        if (!success)
+                m->failure = true;
+
+        m->control_command_id = MOUNT_EXEC_UNMOUNT;
+        m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
+
+        if ((r = exec_command_set(
+                             m->control_command,
+                             "/bin/umount",
+                             m->where,
+                             NULL)) < 0)
+                goto fail;
+
+        mount_unwatch_control_pid(m);
+
+        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
+                goto fail;
+
+        mount_set_state(m, MOUNT_UNMOUNTING);
+
+        return;
+
+fail:
+        log_warning("%s failed to run umount exectuable: %s", UNIT(m)->meta.id, strerror(-r));
+        mount_enter_mounted(m, false);
+}
+
+static void mount_enter_mounting(Mount *m) {
+        int r;
+
+        assert(m);
+
+        m->control_command_id = MOUNT_EXEC_MOUNT;
+        m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
+
+        if (m->from_fragment)
+                r = exec_command_set(
+                                m->control_command,
+                                "/bin/mount",
+                                m->parameters_fragment.what,
+                                m->where,
+                                "-t", m->parameters_fragment.fstype,
+                                m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options,
+                                NULL);
+        else if (m->from_etc_fstab)
+                r = exec_command_set(
+                                m->control_command,
+                                "/bin/mount",
+                                m->where,
+                                NULL);
+        else
+                r = -ENOENT;
+
+        if (r < 0)
+                goto fail;
+
+        mount_unwatch_control_pid(m);
+
+        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
+                goto fail;
+
+        mount_set_state(m, MOUNT_MOUNTING);
+
+        return;
+
+fail:
+        log_warning("%s failed to run mount exectuable: %s", UNIT(m)->meta.id, strerror(-r));
+        mount_enter_dead(m, false);
+}
+
+static void mount_enter_mounting_done(Mount *m) {
+        assert(m);
+
+        mount_set_state(m, MOUNT_MOUNTING_DONE);
+}
+
+static void mount_enter_remounting(Mount *m, bool success) {
+        int r;
+
+        assert(m);
+
+        if (!success)
+                m->failure = true;
+
+        m->control_command_id = MOUNT_EXEC_REMOUNT;
+        m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
+
+        if (m->from_fragment) {
+                char *buf = NULL;
+                const char *o;
+
+                if (m->parameters_fragment.options) {
+                        if (!(buf = strappend("remount,", m->parameters_fragment.options))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        o = buf;
+                } else
+                        o = "remount";
+
+                r = exec_command_set(
+                                m->control_command,
+                                "/bin/mount",
+                                m->parameters_fragment.what,
+                                m->where,
+                                "-t", m->parameters_fragment.fstype,
+                                "-o", o,
+                                NULL);
+
+                free(buf);
+        } else if (m->from_etc_fstab)
+                r = exec_command_set(
+                                m->control_command,
+                                "/bin/mount",
+                                m->where,
+                                "-o", "remount",
+                                NULL);
+        else
+                r = -ENOENT;
+
+        if (r < 0) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        mount_unwatch_control_pid(m);
+
+        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
+                goto fail;
+
+        mount_set_state(m, MOUNT_REMOUNTING);
+
+        return;
+
+fail:
+        mount_enter_mounted(m, false);
+}
+
+static int mount_start(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        /* We cannot fulfill this request right now, try again later
+         * please! */
+        if (m->state == MOUNT_UNMOUNTING ||
+            m->state == MOUNT_UNMOUNTING_SIGTERM ||
+            m->state == MOUNT_UNMOUNTING_SIGKILL)
+                return -EAGAIN;
+
+        /* Already on it! */
+        if (m->state == MOUNT_MOUNTING ||
+            m->state == MOUNT_MOUNTING_SIGTERM ||
+            m->state == MOUNT_MOUNTING_SIGKILL)
+                return 0;
+
+        assert(m->state == MOUNT_DEAD || m->state == MOUNT_MAINTAINANCE);
+
+        m->failure = false;
+        mount_enter_mounting(m);
+        return 0;
+}
+
+static int mount_stop(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        /* Cann't do this right now. */
+        if (m->state == MOUNT_MOUNTING ||
+            m->state == MOUNT_MOUNTING_DONE ||
+            m->state == MOUNT_MOUNTING_SIGTERM ||
+            m->state == MOUNT_MOUNTING_SIGKILL ||
+            m->state == MOUNT_REMOUNTING ||
+            m->state == MOUNT_REMOUNTING_SIGTERM ||
+            m->state == MOUNT_REMOUNTING_SIGKILL)
+                return -EAGAIN;
+
+        /* Already on it */
+        if (m->state == MOUNT_UNMOUNTING ||
+            m->state == MOUNT_UNMOUNTING_SIGKILL ||
+            m->state == MOUNT_UNMOUNTING_SIGTERM)
+                return 0;
+
+        assert(m->state == MOUNT_MOUNTED);
+
+        mount_enter_unmounting(m, true);
+        return 0;
+}
+
+static int mount_reload(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        if (m->state == MOUNT_MOUNTING_DONE)
+                return -EAGAIN;
+
+        assert(m->state == MOUNT_MOUNTED);
+
+        mount_enter_remounting(m, true);
+        return 0;
+}
+
+static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", mount_state_to_string(m->state));
+        unit_serialize_item(u, f, "failure", yes_no(m->failure));
+
+        if (m->control_pid > 0)
+                unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) m->control_pid);
+
+        if (m->control_command_id >= 0)
+                unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id));
+
+        return 0;
+}
+
+static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Mount *m = MOUNT(u);
+        int r;
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                MountState state;
+
+                if ((state = mount_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        m->deserialized_state = state;
+        } else if (streq(key, "failure")) {
+                int b;
+
+                if ((b = parse_boolean(value)) < 0)
+                        log_debug("Failed to parse failure value %s", value);
+                else
+                        m->failure = b || m->failure;
+
+        } else if (streq(key, "control-pid")) {
+                unsigned pid;
+
+                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        m->control_pid = (pid_t) pid;
+        } else if (streq(key, "control-command")) {
+                MountExecCommand id;
+
+                if ((id = mount_exec_command_from_string(value)) < 0)
+                        log_debug("Failed to parse exec-command value %s", value);
+                else {
+                        m->control_command_id = id;
+                        m->control_command = m->exec_command + id;
+                }
+
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState mount_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[MOUNT(u)->state];
+}
+
+static const char *mount_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return mount_state_to_string(MOUNT(u)->state);
+}
+
+static bool mount_check_gc(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        return m->from_etc_fstab || m->from_proc_self_mountinfo;
+}
+
+static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+        Mount *m = MOUNT(u);
+        bool success;
+
+        assert(m);
+        assert(pid >= 0);
+
+        success = is_clean_exit(code, status);
+        m->failure = m->failure || !success;
+
+        assert(m->control_pid == pid);
+        m->control_pid = 0;
+
+        if (m->control_command) {
+                exec_status_fill(&m->control_command->exec_status, pid, code, status);
+                m->control_command = NULL;
+                m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
+        }
+
+        log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
+
+        /* Note that mount(8) returning and the kernel sending us a
+         * mount table change event might happen out-of-order. If an
+         * operation succeed we assume the kernel will follow soon too
+         * and already change into the resulting state.  If it fails
+         * we check if the kernel still knows about the mount. and
+         * change state accordingly. */
+
+        switch (m->state) {
+
+        case MOUNT_MOUNTING:
+        case MOUNT_MOUNTING_DONE:
+        case MOUNT_MOUNTING_SIGKILL:
+        case MOUNT_MOUNTING_SIGTERM:
+        case MOUNT_REMOUNTING:
+        case MOUNT_REMOUNTING_SIGKILL:
+        case MOUNT_REMOUNTING_SIGTERM:
+
+                if (success && m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, true);
+                else if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, false);
+                else
+                        mount_enter_dead(m, false);
+                break;
+
+        case MOUNT_UNMOUNTING:
+        case MOUNT_UNMOUNTING_SIGKILL:
+        case MOUNT_UNMOUNTING_SIGTERM:
+
+                if (success)
+                        mount_enter_dead(m, true);
+                else if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, false);
+                else
+                        mount_enter_dead(m, false);
+                break;
+
+        default:
+                assert_not_reached("Uh, control process died at wrong time.");
+        }
+}
+
+static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+        assert(elapsed == 1);
+        assert(w == &m->timer_watch);
+
+        switch (m->state) {
+
+        case MOUNT_MOUNTING:
+        case MOUNT_MOUNTING_DONE:
+                log_warning("%s mounting timed out. Stopping.", u->meta.id);
+                mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, false);
+                break;
+
+        case MOUNT_REMOUNTING:
+                log_warning("%s remounting timed out. Stopping.", u->meta.id);
+                mount_enter_signal(m, MOUNT_REMOUNTING_SIGTERM, false);
+                break;
+
+        case MOUNT_UNMOUNTING:
+                log_warning("%s unmounting timed out. Stopping.", u->meta.id);
+                mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, false);
+                break;
+
+        case MOUNT_MOUNTING_SIGTERM:
+                log_warning("%s mounting timed out. Killing.", u->meta.id);
+                mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, false);
+                break;
+
+        case MOUNT_REMOUNTING_SIGTERM:
+                log_warning("%s remounting timed out. Killing.", u->meta.id);
+                mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, false);
+                break;
+
+        case MOUNT_UNMOUNTING_SIGTERM:
+                log_warning("%s unmounting timed out. Killing.", u->meta.id);
+                mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, false);
+                break;
+
+        case MOUNT_MOUNTING_SIGKILL:
+        case MOUNT_REMOUNTING_SIGKILL:
+        case MOUNT_UNMOUNTING_SIGKILL:
+                log_warning("%s mount process still around after SIGKILL. Ignoring.", u->meta.id);
+
+                if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, false);
+                else
+                        mount_enter_dead(m, false);
+                break;
+
+        default:
+                assert_not_reached("Timeout at wrong time.");
+        }
+}
+
+static int mount_add_one(
+                Manager *m,
+                const char *what,
+                const char *where,
+                const char *options,
+                const char *fstype,
+                bool from_proc_self_mountinfo,
+                bool set_flags) {
+        int r;
+        Unit *u;
+        bool delete;
+        char *e, *w = NULL, *o = NULL, *f = NULL;
+        MountParameters *p;
+
+        assert(m);
+        assert(what);
+        assert(where);
+        assert(options);
+        assert(fstype);
+
+        assert(!set_flags || from_proc_self_mountinfo);
+
+        /* Ignore API mount points. They should never be referenced in
+         * dependencies ever. */
+        if (mount_point_is_api(where))
+                return 0;
+
+        if (streq(fstype, "autofs"))
+                return 0;
+
+        /* probably some kind of swap, ignore */
+        if (!is_path(where))
+                return 0;
+
+        if (!(e = unit_name_from_path(where, ".mount")))
+                return -ENOMEM;
+
+        if (!(u = manager_get_unit(m, e))) {
+                delete = true;
+
+                if (!(u = unit_new(m))) {
+                        free(e);
+                        return -ENOMEM;
+                }
+
+                r = unit_add_name(u, e);
+                free(e);
+
+                if (r < 0)
+                        goto fail;
+
+                if (!(MOUNT(u)->where = strdup(where))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                unit_add_to_load_queue(u);
+        } else {
+                delete = false;
+                free(e);
+        }
+
+        if (!(w = strdup(what)) ||
+            !(o = strdup(options)) ||
+            !(f = strdup(fstype))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (from_proc_self_mountinfo) {
+                p = &MOUNT(u)->parameters_proc_self_mountinfo;
+
+                if (set_flags) {
+                        MOUNT(u)->is_mounted = true;
+                        MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
+                        MOUNT(u)->just_changed = !streq_ptr(p->options, o);
+                }
+
+                MOUNT(u)->from_proc_self_mountinfo = true;
+        } else {
+                p = &MOUNT(u)->parameters_etc_fstab;
+                MOUNT(u)->from_etc_fstab = true;
+        }
+
+        free(p->what);
+        p->what = w;
+
+        free(p->options);
+        p->options = o;
+
+        free(p->fstype);
+        p->fstype = f;
+
+        unit_add_to_dbus_queue(u);
+
+        return 0;
+
+fail:
+        free(w);
+        free(o);
+        free(f);
+
+        if (delete && u)
+                unit_free(u);
+
+        return r;
+}
+
+static char *fstab_node_to_udev_node(char *p) {
+        char *dn, *t;
+        int r;
+
+        /* FIXME: to follow udev's logic 100% we need to leave valid
+         * UTF8 chars unescaped */
+
+        if (startswith(p, "LABEL=")) {
+
+                if (!(t = xescape(p+6, "/ ")))
+                        return NULL;
+
+                r = asprintf(&dn, "/dev/disk/by-label/%s", t);
+                free(t);
+
+                if (r < 0)
+                        return NULL;
+
+                return dn;
+        }
+
+        if (startswith(p, "UUID=")) {
+
+                if (!(t = xescape(p+5, "/ ")))
+                        return NULL;
+
+                r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t));
+                free(t);
+
+                if (r < 0)
+                        return NULL;
+
+                return dn;
+        }
+
+        return strdup(p);
+}
+
+static int mount_find_pri(char *options) {
+        char *end, *pri;
+        unsigned long r;
+
+        if (!(pri = mount_test_option(options, "pri=")))
+                return 0;
+
+        pri += 4;
+
+        errno = 0;
+        r = strtoul(pri, &end, 10);
+
+        if (errno != 0)
+                return -errno;
+
+        if (end == pri || (*end != ',' && *end != 0))
+                return -EINVAL;
+
+        return (int) r;
+}
+
+static int mount_load_etc_fstab(Manager *m) {
+        FILE *f;
+        int r;
+        struct mntent* me;
+
+        assert(m);
+
+        errno = 0;
+        if (!(f = setmntent("/etc/fstab", "r")))
+                return -errno;
+
+        while ((me = getmntent(f))) {
+                char *where, *what;
+
+                if (!(what = fstab_node_to_udev_node(me->mnt_fsname))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(where = strdup(me->mnt_dir))) {
+                        free(what);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (what[0] == '/')
+                        path_kill_slashes(what);
+
+                if (where[0] == '/')
+                        path_kill_slashes(where);
+
+                if (streq(me->mnt_type, "swap")) {
+                        int pri;
+
+                        if ((pri = mount_find_pri(me->mnt_opts)) < 0)
+                                r = pri;
+                        else
+                                r = swap_add_one(m,
+                                                 what,
+                                                 pri,
+                                                 !!mount_test_option(me->mnt_opts, MNTOPT_NOAUTO),
+                                                 !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"),
+                                                 false);
+                } else
+                        r = mount_add_one(m, what, where, me->mnt_opts, me->mnt_type, false, false);
+
+                free(what);
+                free(where);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = 0;
+finish:
+
+        endmntent(f);
+        return r;
+}
+
+static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
+        int r;
+        char *device, *path, *options, *fstype, *d, *p;
+
+        assert(m);
+
+        rewind(m->proc_self_mountinfo);
+
+        for (;;) {
+                int k;
+
+                device = path = options = fstype = d = p = NULL;
+
+                if ((k = fscanf(m->proc_self_mountinfo,
+                                "%*s "       /* (1) mount id */
+                                "%*s "       /* (2) parent id */
+                                "%*s "       /* (3) major:minor */
+                                "%*s "       /* (4) root */
+                                "%ms "       /* (5) mount point */
+                                "%ms"        /* (6) mount options */
+                                "%*[^-]"     /* (7) optional fields */
+                                "- "         /* (8) seperator */
+                                "%ms "       /* (9) file system type */
+                                "%ms"        /* (10) mount source */
+                                "%*[^\n]",   /* some rubbish at the end */
+                                &path,
+                                &options,
+                                &fstype,
+                                &device)) != 4) {
+
+                        if (k == EOF)
+                                break;
+
+                        r = -EBADMSG;
+                        goto finish;
+                }
+
+                if (!(d = cunescape(device)) ||
+                    !(p = cunescape(path))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if ((r = mount_add_one(m, d, p, options, fstype, true, set_flags)) < 0)
+                        goto finish;
+
+                free(device);
+                free(path);
+                free(options);
+                free(fstype);
+                free(d);
+                free(p);
+        }
+
+        r = 0;
+
+finish:
+        free(device);
+        free(path);
+        free(options);
+        free(fstype);
+        free(d);
+        free(p);
+
+        return r;
+}
+
+static void mount_shutdown(Manager *m) {
+        assert(m);
+
+        if (m->proc_self_mountinfo) {
+                fclose(m->proc_self_mountinfo);
+                m->proc_self_mountinfo = NULL;
+        }
+}
+
+static int mount_enumerate(Manager *m) {
+        int r;
+        struct epoll_event ev;
+        assert(m);
+
+        if (!m->proc_self_mountinfo) {
+                if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
+                        return -errno;
+
+                m->mount_watch.type = WATCH_MOUNT;
+                m->mount_watch.fd = fileno(m->proc_self_mountinfo);
+
+                zero(ev);
+                ev.events = EPOLLERR;
+                ev.data.ptr = &m->mount_watch;
+
+                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0)
+                        return -errno;
+        }
+
+        if ((r = mount_load_etc_fstab(m)) < 0)
+                goto fail;
+
+        if ((r = mount_load_proc_self_mountinfo(m, false)) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        mount_shutdown(m);
+        return r;
+}
+
+void mount_fd_event(Manager *m, int events) {
+        Meta *meta;
+        int r;
+
+        assert(m);
+        assert(events == EPOLLERR);
+
+        /* The manager calls this for every fd event happening on the
+         * /proc/self/mountinfo file, which informs us about mounting
+         * table changes */
+
+        if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) {
+                log_error("Failed to reread /proc/self/mountinfo: %s", strerror(errno));
+
+                /* Reset flags, just in case, for later calls */
+                LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) {
+                        Mount *mount = (Mount*) meta;
+
+                        mount->is_mounted = mount->just_mounted = mount->just_changed = false;
+                }
+
+                return;
+        }
+
+        manager_dispatch_load_queue(m);
+
+        LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) {
+                Mount *mount = (Mount*) meta;
+
+                if (!mount->is_mounted) {
+                        /* This has just been unmounted. */
+
+                        mount->from_proc_self_mountinfo = false;
+
+                        switch (mount->state) {
+
+                        case MOUNT_MOUNTED:
+                                mount_enter_dead(mount, true);
+                                break;
+
+                        default:
+                                mount_set_state(mount, mount->state);
+                                break;
+
+                        }
+
+                } else if (mount->just_mounted || mount->just_changed) {
+
+                        /* New or changed entrymount */
+
+                        switch (mount->state) {
+
+                        case MOUNT_DEAD:
+                        case MOUNT_MAINTAINANCE:
+                                mount_enter_mounted(mount, true);
+                                break;
+
+                        case MOUNT_MOUNTING:
+                                mount_enter_mounting_done(mount);
+                                break;
+
+                        default:
+                                /* Nothing really changed, but let's
+                                 * issue an notification call
+                                 * nonetheless, in case somebody is
+                                 * waiting for this. (e.g. file system
+                                 * ro/rw remounts.) */
+                                mount_set_state(mount, mount->state);
+                                break;
+                        }
+                }
+
+                /* Reset the flags for later calls */
+                mount->is_mounted = mount->just_mounted = mount->just_changed = false;
+        }
+}
+
+int mount_path_is_mounted(Manager *m, const char* path) {
+        char *t;
+        int r;
+
+        assert(m);
+        assert(path);
+
+        if (path[0] != '/')
+                return 1;
+
+        if (!(t = strdup(path)))
+                return -ENOMEM;
+
+        path_kill_slashes(t);
+
+        for (;;) {
+                char *e, *slash;
+                Unit *u;
+
+                if (!(e = unit_name_from_path(t, ".mount"))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                u = manager_get_unit(m, e);
+                free(e);
+
+                if (u &&
+                    (MOUNT(u)->from_etc_fstab || MOUNT(u)->from_fragment) &&
+                    MOUNT(u)->state != MOUNT_MOUNTED) {
+                        r = 0;
+                        goto finish;
+                }
+
+                assert_se(slash = strrchr(t, '/'));
+
+                if (slash == t) {
+                        r = 1;
+                        goto finish;
+                }
+
+                *slash = 0;
+        }
+
+        r = 1;
+
+finish:
+        free(t);
+        return r;
+}
+
+static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
+        [MOUNT_DEAD] = "dead",
+        [MOUNT_MOUNTING] = "mounting",
+        [MOUNT_MOUNTING_DONE] = "mounting-done",
+        [MOUNT_MOUNTED] = "mounted",
+        [MOUNT_REMOUNTING] = "remounting",
+        [MOUNT_UNMOUNTING] = "unmounting",
+        [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
+        [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
+        [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
+        [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
+        [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
+        [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
+        [MOUNT_MAINTAINANCE] = "maintainance"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
+
+static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
+        [MOUNT_EXEC_MOUNT] = "ExecMount",
+        [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
+        [MOUNT_EXEC_REMOUNT] = "ExecRemount",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
+
+const UnitVTable mount_vtable = {
+        .suffix = ".mount",
+
+        .no_alias = true,
+        .no_instances = true,
+        .no_isolate = true,
+
+        .init = mount_init,
+        .load = mount_load,
+        .done = mount_done,
+
+        .coldplug = mount_coldplug,
+
+        .dump = mount_dump,
+
+        .start = mount_start,
+        .stop = mount_stop,
+        .reload = mount_reload,
+
+        .serialize = mount_serialize,
+        .deserialize_item = mount_deserialize_item,
+
+        .active_state = mount_active_state,
+        .sub_state_to_string = mount_sub_state_to_string,
+
+        .check_gc = mount_check_gc,
+
+        .sigchld_event = mount_sigchld_event,
+        .timer_event = mount_timer_event,
+
+        .bus_message_handler = bus_mount_message_handler,
+
+        .enumerate = mount_enumerate,
+        .shutdown = mount_shutdown
+};
diff --git a/src/mount.h b/src/mount.h
new file mode 100644
index 0000000..3b28e89
--- /dev/null
+++ b/src/mount.h
@@ -0,0 +1,110 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foomounthfoo
+#define foomounthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Mount Mount;
+
+#include "unit.h"
+
+typedef enum MountState {
+        MOUNT_DEAD,
+        MOUNT_MOUNTING,               /* /bin/mount is running, but the mount is not done yet. */
+        MOUNT_MOUNTING_DONE,          /* /bin/mount is running, and the mount is done. */
+        MOUNT_MOUNTED,
+        MOUNT_REMOUNTING,
+        MOUNT_UNMOUNTING,
+        MOUNT_MOUNTING_SIGTERM,
+        MOUNT_MOUNTING_SIGKILL,
+        MOUNT_REMOUNTING_SIGTERM,
+        MOUNT_REMOUNTING_SIGKILL,
+        MOUNT_UNMOUNTING_SIGTERM,
+        MOUNT_UNMOUNTING_SIGKILL,
+        MOUNT_MAINTAINANCE,
+        _MOUNT_STATE_MAX,
+        _MOUNT_STATE_INVALID = -1
+} MountState;
+
+typedef enum MountExecCommand {
+        MOUNT_EXEC_MOUNT,
+        MOUNT_EXEC_UNMOUNT,
+        MOUNT_EXEC_REMOUNT,
+        _MOUNT_EXEC_COMMAND_MAX,
+        _MOUNT_EXEC_COMMAND_INVALID = -1
+} MountExecCommand;
+
+typedef struct MountParameters {
+        char *what;
+        char *options;
+        char *fstype;
+} MountParameters;
+
+struct Mount {
+        Meta meta;
+
+        char *where;
+
+        MountParameters parameters_etc_fstab;
+        MountParameters parameters_proc_self_mountinfo;
+        MountParameters parameters_fragment;
+
+        bool from_etc_fstab:1;
+        bool from_proc_self_mountinfo:1;
+        bool from_fragment:1;
+
+        /* Used while looking for mount points that vanished or got
+         * added from/to /proc/self/mountinfo */
+        bool is_mounted:1;
+        bool just_mounted:1;
+        bool just_changed:1;
+
+        bool failure:1;
+
+        usec_t timeout_usec;
+
+        ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        MountState state, deserialized_state;
+
+        KillMode kill_mode;
+
+        ExecCommand* control_command;
+        MountExecCommand control_command_id;
+        pid_t control_pid;
+
+        Watch timer_watch;
+};
+
+extern const UnitVTable mount_vtable;
+
+void mount_fd_event(Manager *m, int events);
+
+int mount_path_is_mounted(Manager *m, const char* path);
+
+const char* mount_state_to_string(MountState i);
+MountState mount_state_from_string(const char *s);
+
+const char* mount_exec_command_to_string(MountExecCommand i);
+MountExecCommand mount_exec_command_from_string(const char *s);
+
+#endif
diff --git a/src/namespace.c b/src/namespace.c
new file mode 100644
index 0000000..09bcaff
--- /dev/null
+++ b/src/namespace.c
@@ -0,0 +1,331 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <sys/mount.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <limits.h>
+#include <linux/fs.h>
+
+#include "strv.h"
+#include "util.h"
+#include "namespace.h"
+#include "missing.h"
+
+typedef enum PathMode {
+        /* This is ordered by priority! */
+        INACCESSIBLE,
+        READONLY,
+        PRIVATE,
+        READWRITE
+} PathMode;
+
+typedef struct Path {
+        const char *path;
+        PathMode mode;
+} Path;
+
+static int append_paths(Path **p, char **strv, PathMode mode) {
+        char **i;
+
+        STRV_FOREACH(i, strv) {
+
+                if (!path_is_absolute(*i))
+                        return -EINVAL;
+
+                (*p)->path = *i;
+                (*p)->mode = mode;
+                (*p)++;
+        }
+
+        return 0;
+}
+
+static int path_compare(const void *a, const void *b) {
+        const Path *p = a, *q = b;
+
+        if (path_equal(p->path, q->path)) {
+
+                /* If the paths are equal, check the mode */
+                if (p->mode < q->mode)
+                        return -1;
+
+                if (p->mode > q->mode)
+                        return 1;
+
+                return 0;
+        }
+
+        /* If the paths are not equal, then order prefixes first */
+        if (path_startswith(p->path, q->path))
+                return 1;
+
+        if (path_startswith(q->path, p->path))
+                return -1;
+
+        return 0;
+}
+
+static void drop_duplicates(Path *p, unsigned *n, bool *need_inaccessible, bool *need_private) {
+        Path *f, *t, *previous;
+
+        assert(p);
+        assert(n);
+        assert(need_inaccessible);
+        assert(need_private);
+
+        for (f = p, t = p, previous = NULL; f < p+*n; f++) {
+
+                if (previous && path_equal(f->path, previous->path))
+                        continue;
+
+                t->path = f->path;
+                t->mode = f->mode;
+
+                if (t->mode == PRIVATE)
+                        *need_private = true;
+
+                if (t->mode == INACCESSIBLE)
+                        *need_inaccessible = true;
+
+                previous = t;
+
+                t++;
+        }
+
+        *n = t - p;
+}
+
+static int apply_mount(Path *p, const char *root_dir, const char *inaccessible_dir, const char *private_dir, unsigned long flags) {
+        const char *what;
+        char *where;
+        int r;
+
+        assert(p);
+        assert(root_dir);
+        assert(inaccessible_dir);
+        assert(private_dir);
+
+        if (!(where = strappend(root_dir, p->path)))
+                return -ENOMEM;
+
+        switch (p->mode) {
+
+        case INACCESSIBLE:
+                what = inaccessible_dir;
+                flags |= MS_RDONLY;
+                break;
+
+        case READONLY:
+                flags |= MS_RDONLY;
+                /* Fall through */
+
+        case READWRITE:
+                what = p->path;
+                break;
+
+        case PRIVATE:
+                what = private_dir;
+                break;
+        }
+
+        if ((r = mount(what, where, NULL, MS_BIND|MS_REC, NULL)) >= 0) {
+                log_debug("Successfully mounted %s to %s", what, where);
+
+                /* The bind mount will always inherit the original
+                 * flags. If we want to set any flag we need
+                 * to do so in a second indepdant step. */
+                if (flags)
+                        r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_REC|flags, NULL);
+
+                /* Avoid expontial growth of trees */
+                if (r >= 0 && path_equal(p->path, "/"))
+                        r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_UNBINDABLE|flags, NULL);
+
+                if (r < 0) {
+                        r = -errno;
+                        umount2(where, MNT_DETACH);
+                }
+        }
+
+        free(where);
+        return r;
+}
+
+int setup_namespace(
+                char **writable,
+                char **readable,
+                char **inaccessible,
+                bool private_tmp,
+                unsigned long flags) {
+
+        char
+                tmp_dir[] = "/tmp/systemd-namespace-XXXXXX",
+                root_dir[] = "/tmp/systemd-namespace-XXXXXX/root",
+                old_root_dir[] = "/tmp/systemd-namespace-XXXXXX/root/tmp/old-root-XXXXXX",
+                inaccessible_dir[] = "/tmp/systemd-namespace-XXXXXX/inaccessible",
+                private_dir[] = "/tmp/systemd-namespace-XXXXXX/private";
+
+        Path *paths, *p;
+        unsigned n;
+        bool need_private = false, need_inaccessible = false;
+        bool remove_tmp = false, remove_root = false, remove_old_root = false, remove_inaccessible = false, remove_private = false;
+        int r;
+        const char *t;
+
+        n =
+                strv_length(writable) +
+                strv_length(readable) +
+                strv_length(inaccessible) +
+                (private_tmp ? 2 : 1);
+
+        if (!(paths = new(Path, n)))
+                return -ENOMEM;
+
+        p = paths;
+        if ((r = append_paths(&p, writable, READWRITE)) < 0 ||
+            (r = append_paths(&p, readable, READONLY)) < 0 ||
+            (r = append_paths(&p, inaccessible, INACCESSIBLE)) < 0)
+                goto fail;
+
+        if (private_tmp) {
+                p->path = "/tmp";
+                p->mode = PRIVATE;
+                p++;
+        }
+
+        p->path = "/";
+        p->mode = READWRITE;
+        p++;
+
+        assert(paths + n == p);
+
+        qsort(paths, n, sizeof(Path), path_compare);
+        drop_duplicates(paths, &n, &need_inaccessible, &need_private);
+
+        if (!mkdtemp(tmp_dir)) {
+                r = -errno;
+                goto fail;
+        }
+        remove_tmp = true;
+
+        memcpy(root_dir, tmp_dir, sizeof(tmp_dir)-1);
+        if (mkdir(root_dir, 0777) < 0) {
+                r = -errno;
+                goto fail;
+        }
+        remove_root = true;
+
+        if (need_inaccessible) {
+                memcpy(inaccessible_dir, tmp_dir, sizeof(tmp_dir)-1);
+                if (mkdir(inaccessible_dir, 0) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+                remove_inaccessible = true;
+        }
+
+        if (need_private) {
+                memcpy(private_dir, tmp_dir, sizeof(tmp_dir)-1);
+                if (mkdir(private_dir, 0777 + S_ISVTX) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+                remove_private = true;
+        }
+
+        if (unshare(CLONE_NEWNS) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* We assume that by default mount events from us won't be
+         * propagated to the root namespace. */
+
+        for (p = paths; p < paths + n; p++)
+                if ((r = apply_mount(p, root_dir, inaccessible_dir, private_dir, flags)) < 0)
+                        goto undo_mounts;
+
+        memcpy(old_root_dir, tmp_dir, sizeof(tmp_dir)-1);
+        if (!mkdtemp(old_root_dir)) {
+                r = -errno;
+                goto undo_mounts;
+        }
+        remove_old_root = true;
+
+        if (chdir(root_dir) < 0) {
+                r = -errno;
+                goto undo_mounts;
+        }
+
+        if (pivot_root(root_dir, old_root_dir) < 0) {
+                r = -errno;
+                goto undo_mounts;
+        }
+
+        t = old_root_dir + sizeof(root_dir) - 1;
+        if (umount2(t, MNT_DETACH) < 0)
+                /* At this point it's too late to turn anything back,
+                 * since we are already in the new root. */
+                return -errno;
+
+        if (rmdir(t) < 0)
+                return -errno;
+
+        return 0;
+
+undo_mounts:
+
+        for (p--; p >= paths; p--) {
+                char full_path[PATH_MAX];
+
+                snprintf(full_path, sizeof(full_path), "%s%s", root_dir, p->path);
+                char_array_0(full_path);
+
+                umount2(full_path, MNT_DETACH);
+        }
+
+fail:
+        if (remove_old_root)
+                rmdir(old_root_dir);
+
+        if (remove_inaccessible)
+                rmdir(inaccessible_dir);
+
+        if (remove_private)
+                rmdir(private_dir);
+
+        if (remove_root)
+                rmdir(root_dir);
+
+        if (remove_tmp)
+                rmdir(tmp_dir);
+
+             free(paths);
+
+        return r;
+}
diff --git a/src/namespace.h b/src/namespace.h
new file mode 100644
index 0000000..6128646
--- /dev/null
+++ b/src/namespace.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foonamespacehfoo
+#define foonamespacehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+int setup_namespace(
+                char **writable,
+                char **readable,
+                char **inaccessible,
+                bool private_tmp,
+                unsigned long flags);
+
+#endif
diff --git a/src/ratelimit.c b/src/ratelimit.c
new file mode 100644
index 0000000..1e5ed03
--- /dev/null
+++ b/src/ratelimit.c
@@ -0,0 +1,62 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+
+#include "ratelimit.h"
+#include "log.h"
+
+/* Modelled after Linux' lib/ratelimit.c by Dave Young
+ * <hidave.darkstar at gmail.com>, which is licensed GPLv2. */
+
+bool ratelimit_test(RateLimit *r) {
+        usec_t timestamp;
+
+        timestamp = now(CLOCK_MONOTONIC);
+
+        assert(r);
+        assert(r->interval > 0);
+        assert(r->burst > 0);
+
+        if (r->begin <= 0 ||
+            r->begin + r->interval < timestamp) {
+
+                if (r->n_missed > 0)
+                        log_warning("%u events suppressed", r->n_missed);
+
+                r->begin = timestamp;
+
+                /* Reset counters */
+                r->n_printed = 0;
+                r->n_missed = 0;
+                goto good;
+        }
+
+        if (r->n_printed <= r->burst)
+                goto good;
+
+        r->n_missed++;
+        return false;
+
+good:
+        r->n_printed++;
+        return true;
+}
diff --git a/src/ratelimit.h b/src/ratelimit.h
new file mode 100644
index 0000000..e7dffb8
--- /dev/null
+++ b/src/ratelimit.h
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooratelimithfoo
+#define fooratelimithfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+typedef struct RateLimit {
+        usec_t interval;
+        usec_t begin;
+        unsigned burst;
+        unsigned n_printed, n_missed;
+} RateLimit;
+
+#define RATELIMIT_DEFINE(_name, _interval, _burst)       \
+        RateLimit _name = {                              \
+                .interval = (_interval),                 \
+                .burst = (_burst),                       \
+                .n_printed = 0,                          \
+                .n_missed = 0,                           \
+                .begin = 0                               \
+        }
+
+#define RATELIMIT_INIT(v, _interval, _burst)             \
+        do {                                             \
+                RateLimit *_r = &(v);                    \
+                _r->interval = (_interval);              \
+                _r->burst = (_burst);                    \
+                _r->n_printed = 0;                       \
+                _r->n_missed = 0;                        \
+                _r->begin = 0;                           \
+        } while (false);
+
+bool ratelimit_test(RateLimit *r);
+
+#endif
diff --git a/src/sd-daemon.c b/src/sd-daemon.c
new file mode 100644
index 0000000..cc972da
--- /dev/null
+++ b/src/sd-daemon.c
@@ -0,0 +1,96 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  Copyright 2010 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+***/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sd-daemon.h"
+
+int sd_listen_fds(int unset_environment) {
+
+#ifdef DISABLE_SYSTEMD
+        return 0;
+#else
+        int r;
+        const char *e;
+        char *p = NULL;
+        unsigned long l;
+
+        if (!(e = getenv("LISTEN_PID"))) {
+                r = 0;
+                goto finish;
+        }
+
+        errno = 0;
+        l = strtoul(e, &p, 10);
+
+        if (errno != 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (!p || *p || l <= 0) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        /* Is this for us? */
+        if (getpid() != (pid_t) l) {
+                r = 0;
+                goto finish;
+        }
+
+        if (!(e = getenv("LISTEN_FDS"))) {
+                r = 0;
+                goto finish;
+        }
+
+        errno = 0;
+        l = strtoul(e, &p, 10);
+
+        if (errno != 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (!p || *p) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        r = (int) l;
+
+finish:
+        if (unset_environment) {
+                unsetenv("LISTEN_PID");
+                unsetenv("LISTEN_FDS");
+        }
+
+        return r;
+#endif
+}
diff --git a/src/sd-daemon.h b/src/sd-daemon.h
new file mode 100644
index 0000000..c7f5c1d
--- /dev/null
+++ b/src/sd-daemon.h
@@ -0,0 +1,61 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foosddaemonhfoo
+#define foosddaemonhfoo
+
+/***
+  Copyright 2010 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+***/
+
+/* Reference implementation of a few systemd related interfaces for
+ * writing daemons. These interfaces are trivial to implement, however
+ * to simplify porting we provide this reference
+ * implementation. Applications are free to reimplement the algorithms
+ * described here. */
+
+/*
+  Log levels for usage on stderr:
+
+          fprintf(stderr, SD_NOTICE "Hello World!");
+
+  This is similar to printk() usage in the kernel.
+*/
+
+#define SD_EMERG   "<0>"  /* system is unusable */
+#define SD_ALERT   "<1>"  /* action must be taken immediately */
+#define SD_CRIT    "<2>"  /* critical conditions */
+#define SD_ERR     "<3>"  /* error conditions */
+#define SD_WARNING "<4>"  /* warning conditions */
+#define SD_NOTICE  "<5>"  /* normal but significant condition */
+#define SD_INFO    "<6>"  /* informational */
+#define SD_DEBUG   "<7>"  /* debug-level messages */
+
+/* The first passed file descriptor is fd 3 */
+#define SD_LISTEN_FDS_START 3
+
+/* Returns how many file descriptors have been passed, or a negative
+ * errno code on failure. Optionally removes the $LISTEN_FDS and
+ * $LISTEN_PID file descriptors from the environment (recommended). */
+int sd_listen_fds(int unset_environment);
+
+#endif
diff --git a/src/securebits.h b/src/securebits.h
new file mode 100644
index 0000000..a5b99a3
--- /dev/null
+++ b/src/securebits.h
@@ -0,0 +1,45 @@
+#ifndef _LINUX_SECUREBITS_H
+#define _LINUX_SECUREBITS_H 1
+
+/* This is minimal version of Linux' linux/securebits.h header file,
+ * which is licensed GPL2 */
+
+#define SECUREBITS_DEFAULT 0x00000000
+
+/* When set UID 0 has no special privileges. When unset, we support
+   inheritance of root-permissions and suid-root executable under
+   compatibility mode. We raise the effective and inheritable bitmasks
+   *of the executable file* if the effective uid of the new process is
+   0. If the real uid is 0, we raise the effective (legacy) bit of the
+   executable file. */
+#define SECURE_NOROOT			0
+#define SECURE_NOROOT_LOCKED		1  /* make bit-0 immutable */
+
+/* When set, setuid to/from uid 0 does not trigger capability-"fixup".
+   When unset, to provide compatiblility with old programs relying on
+   set*uid to gain/lose privilege, transitions to/from uid 0 cause
+   capabilities to be gained/lost. */
+#define SECURE_NO_SETUID_FIXUP		2
+#define SECURE_NO_SETUID_FIXUP_LOCKED	3  /* make bit-2 immutable */
+
+/* When set, a process can retain its capabilities even after
+   transitioning to a non-root user (the set-uid fixup suppressed by
+   bit 2). Bit-4 is cleared when a process calls exec(); setting both
+   bit 4 and 5 will create a barrier through exec that no exec()'d
+   child can use this feature again. */
+#define SECURE_KEEP_CAPS		4
+#define SECURE_KEEP_CAPS_LOCKED		5  /* make bit-4 immutable */
+
+/* Each securesetting is implemented using two bits. One bit specifies
+   whether the setting is on or off. The other bit specify whether the
+   setting is locked or not. A setting which is locked cannot be
+   changed from user-level. */
+#define issecure_mask(X)	(1 << (X))
+#define issecure(X)		(issecure_mask(X) & current_cred_xxx(securebits))
+
+#define SECURE_ALL_BITS		(issecure_mask(SECURE_NOROOT) | \
+				 issecure_mask(SECURE_NO_SETUID_FIXUP) | \
+				 issecure_mask(SECURE_KEEP_CAPS))
+#define SECURE_ALL_LOCKS	(SECURE_ALL_BITS << 1)
+
+#endif /* !_LINUX_SECUREBITS_H */
diff --git a/src/service.c b/src/service.c
new file mode 100644
index 0000000..bf91561
--- /dev/null
+++ b/src/service.c
@@ -0,0 +1,2463 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include "unit.h"
+#include "service.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "log.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "dbus-service.h"
+
+#define COMMENTS "#;\n"
+#define NEWLINES "\n\r"
+#define LINE_MAX 4096
+
+typedef enum RunlevelType {
+        RUNLEVEL_UP,
+        RUNLEVEL_DOWN,
+        RUNLEVEL_BASIC
+} RunlevelType;
+
+static const struct {
+        const char *path;
+        const char *target;
+        const RunlevelType type;
+} rcnd_table[] = {
+        /* Standard SysV runlevels */
+        { "rc0.d",  SPECIAL_RUNLEVEL0_TARGET, RUNLEVEL_DOWN },
+        { "rc1.d",  SPECIAL_RUNLEVEL1_TARGET, RUNLEVEL_UP },
+        { "rc2.d",  SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
+        { "rc3.d",  SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
+        { "rc4.d",  SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
+        { "rc5.d",  SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
+        { "rc6.d",  SPECIAL_RUNLEVEL6_TARGET, RUNLEVEL_DOWN },
+
+        /* SuSE style boot.d */
+        { "boot.d", SPECIAL_BASIC_TARGET,     RUNLEVEL_BASIC },
+
+        /* Debian style rcS.d */
+        { "rcS.d",  SPECIAL_BASIC_TARGET,     RUNLEVEL_BASIC },
+};
+
+#define RUNLEVELS_UP "12345"
+/* #define RUNLEVELS_DOWN "06" */
+/* #define RUNLEVELS_BOOT "bBsS" */
+
+static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
+        [SERVICE_DEAD] = UNIT_INACTIVE,
+        [SERVICE_START_PRE] = UNIT_ACTIVATING,
+        [SERVICE_START] = UNIT_ACTIVATING,
+        [SERVICE_START_POST] = UNIT_ACTIVATING,
+        [SERVICE_RUNNING] = UNIT_ACTIVE,
+        [SERVICE_EXITED] = UNIT_ACTIVE,
+        [SERVICE_RELOAD] = UNIT_ACTIVE_RELOADING,
+        [SERVICE_STOP] = UNIT_DEACTIVATING,
+        [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
+        [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
+        [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
+        [SERVICE_MAINTAINANCE] = UNIT_INACTIVE,
+        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
+};
+
+static void service_init(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        s->restart_usec = DEFAULT_RESTART_USEC;
+        s->timer_watch.type = WATCH_INVALID;
+        s->sysv_start_priority = -1;
+        s->socket_fd = -1;
+
+        exec_context_init(&s->exec_context);
+
+        RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
+
+        s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+}
+
+static void service_unwatch_control_pid(Service *s) {
+        assert(s);
+
+        if (s->control_pid <= 0)
+                return;
+
+        unit_unwatch_pid(UNIT(s), s->control_pid);
+        s->control_pid = 0;
+}
+
+static void service_unwatch_main_pid(Service *s) {
+        assert(s);
+
+        if (s->main_pid <= 0)
+                return;
+
+        unit_unwatch_pid(UNIT(s), s->main_pid);
+        s->main_pid = 0;
+}
+
+static void service_close_socket_fd(Service *s) {
+        assert(s);
+
+        if (s->socket_fd < 0)
+                return;
+
+        close_nointr_nofail(s->socket_fd);
+        s->socket_fd = -1;
+}
+
+static void service_done(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        free(s->pid_file);
+        s->pid_file = NULL;
+
+        free(s->sysv_path);
+        s->sysv_path = NULL;
+
+        free(s->sysv_runlevels);
+        s->sysv_runlevels = NULL;
+
+        exec_context_done(&s->exec_context);
+        exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
+        s->control_command = NULL;
+
+        /* This will leak a process, but at least no memory or any of
+         * our resources */
+        service_unwatch_main_pid(s);
+        service_unwatch_control_pid(s);
+
+        if (s->bus_name)  {
+                unit_unwatch_bus_name(UNIT(u), s->bus_name);
+                free(s->bus_name);
+                s->bus_name = NULL;
+        }
+
+        service_close_socket_fd(s);
+
+        unit_unwatch_timer(u, &s->timer_watch);
+}
+
+static int sysv_translate_name(const char *name, char **_r) {
+
+        static const char * const table[] = {
+                "$local_fs",  SPECIAL_LOCAL_FS_TARGET,
+                "$network",   SPECIAL_NETWORK_TARGET,
+                "$named",     SPECIAL_NSS_LOOKUP_TARGET,
+                "$portmap",   SPECIAL_RPCBIND_TARGET,
+                "$remote_fs", SPECIAL_REMOTE_FS_TARGET,
+                "$syslog",    SPECIAL_SYSLOG_TARGET,
+                "$time",      SPECIAL_RTC_SET_TARGET
+        };
+
+        unsigned i;
+        char *r;
+
+        for (i = 0; i < ELEMENTSOF(table); i += 2)
+                if (streq(table[i], name)) {
+                        if (!(r = strdup(table[i+1])))
+                                return -ENOMEM;
+
+                        goto finish;
+                }
+
+        if (*name == '$')
+                return 0;
+
+        if (asprintf(&r, "%s.service", name) < 0)
+                return -ENOMEM;
+
+finish:
+
+        if (_r)
+                *_r = r;
+
+        return 1;
+}
+
+static int sysv_chkconfig_order(Service *s) {
+        Meta *other;
+        int r;
+
+        assert(s);
+
+        if (s->sysv_start_priority < 0)
+                return 0;
+
+        /* For each pair of services where at least one lacks a LSB
+         * header, we use the start priority value to order things. */
+
+        LIST_FOREACH(units_per_type, other, UNIT(s)->meta.manager->units_per_type[UNIT_SERVICE]) {
+                Service *t;
+                UnitDependency d;
+
+                t = (Service*) other;
+
+                if (s == t)
+                        continue;
+
+                if (t->sysv_start_priority < 0)
+                        continue;
+
+                /* If both units have modern headers we don't care
+                 * about the priorities */
+                if ((!s->sysv_path || s->sysv_has_lsb) &&
+                    (!t->sysv_path || t->sysv_has_lsb))
+                        continue;
+
+                if (t->sysv_start_priority < s->sysv_start_priority)
+                        d = UNIT_AFTER;
+                else if (t->sysv_start_priority > s->sysv_start_priority)
+                        d = UNIT_BEFORE;
+                else
+                        continue;
+
+                /* FIXME: Maybe we should compare the name here lexicographically? */
+
+                if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static ExecCommand *exec_command_new(const char *path, const char *arg1) {
+        ExecCommand *c;
+
+        if (!(c = new0(ExecCommand, 1)))
+                return NULL;
+
+        if (!(c->path = strdup(path))) {
+                free(c);
+                return NULL;
+        }
+
+        if (!(c->argv = strv_new(path, arg1, NULL))) {
+                free(c->path);
+                free(c);
+                return NULL;
+        }
+
+        return c;
+}
+
+static int sysv_exec_commands(Service *s) {
+        ExecCommand *c;
+
+        assert(s);
+        assert(s->sysv_path);
+
+        if (!(c = exec_command_new(s->sysv_path, "start")))
+                return -ENOMEM;
+        exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c);
+
+        if (!(c = exec_command_new(s->sysv_path, "stop")))
+                return -ENOMEM;
+        exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c);
+
+        if (!(c = exec_command_new(s->sysv_path, "reload")))
+                return -ENOMEM;
+        exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c);
+
+        return 0;
+}
+
+static int service_load_sysv_path(Service *s, const char *path) {
+        FILE *f;
+        Unit *u;
+        unsigned line = 0;
+        int r;
+        enum {
+                NORMAL,
+                DESCRIPTION,
+                LSB,
+                LSB_DESCRIPTION
+        } state = NORMAL;
+
+        assert(s);
+        assert(path);
+
+        u = UNIT(s);
+
+        if (!(f = fopen(path, "re"))) {
+                r = errno == ENOENT ? 0 : -errno;
+                goto finish;
+        }
+
+        s->type = SERVICE_FORKING;
+        s->restart = SERVICE_ONCE;
+
+        free(s->sysv_path);
+        if (!(s->sysv_path = strdup(path))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        while (!feof(f)) {
+                char l[LINE_MAX], *t;
+
+                if (!fgets(l, sizeof(l), f)) {
+                        if (feof(f))
+                                break;
+
+                        r = -errno;
+                        log_error("Failed to read configuration file '%s': %s", path, strerror(-r));
+                        goto finish;
+                }
+
+                line++;
+
+                t = strstrip(l);
+                if (*t != '#')
+                        continue;
+
+                if (state == NORMAL && streq(t, "### BEGIN INIT INFO")) {
+                        state = LSB;
+                        s->sysv_has_lsb = true;
+                        continue;
+                }
+
+                if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) {
+                        state = NORMAL;
+                        continue;
+                }
+
+                t++;
+                t += strspn(t, WHITESPACE);
+
+                if (state == NORMAL) {
+
+                        /* Try to parse Red Hat style chkconfig headers */
+
+                        if (startswith(t, "chkconfig:")) {
+                                int start_priority;
+                                char runlevels[16], *k;
+
+                                state = NORMAL;
+
+                                if (sscanf(t+10, "%15s %i %*i",
+                                           runlevels,
+                                           &start_priority) != 2) {
+
+                                        log_warning("[%s:%u] Failed to parse chkconfig line. Ignoring.", path, line);
+                                        continue;
+                                }
+
+                                /* A start priority gathered from the
+                                 * symlink farms is preferred over the
+                                 * data from the LSB header. */
+                                if (start_priority < 0 || start_priority > 99)
+                                        log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line);
+                                else if (s->sysv_start_priority < 0)
+                                        s->sysv_start_priority = start_priority;
+
+                                char_array_0(runlevels);
+                                k = delete_chars(runlevels, WHITESPACE "-");
+
+                                if (k[0]) {
+                                        char *d;
+
+                                        if (!(d = strdup(k))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        free(s->sysv_runlevels);
+                                        s->sysv_runlevels = d;
+                                }
+
+                        } else if (startswith(t, "description:")) {
+
+                                size_t k = strlen(t);
+                                char *d;
+
+                                if (t[k-1] == '\\') {
+                                        state = DESCRIPTION;
+                                        t[k-1] = 0;
+                                }
+
+                                if (!(d = strdup(strstrip(t+12)))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                free(u->meta.description);
+                                u->meta.description = d;
+
+                        } else if (startswith(t, "pidfile:")) {
+
+                                char *fn;
+
+                                state = NORMAL;
+
+                                fn = strstrip(t+8);
+                                if (!path_is_absolute(fn)) {
+                                        log_warning("[%s:%u] PID file not absolute. Ignoring.", path, line);
+                                        continue;
+                                }
+
+                                if (!(fn = strdup(fn))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                free(s->pid_file);
+                                s->pid_file = fn;
+                        }
+
+                } else if (state == DESCRIPTION) {
+
+                        /* Try to parse Red Hat style description
+                         * continuation */
+
+                        size_t k = strlen(t);
+                        char *d;
+
+                        if (t[k-1] == '\\')
+                                t[k-1] = 0;
+                        else
+                                state = NORMAL;
+
+                        assert(u->meta.description);
+                        if (asprintf(&d, "%s %s", u->meta.description, strstrip(t)) < 0) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        free(u->meta.description);
+                        u->meta.description = d;
+
+                } else if (state == LSB || state == LSB_DESCRIPTION) {
+
+                        if (startswith(t, "Provides:")) {
+                                char *i, *w;
+                                size_t z;
+
+                                state = LSB;
+
+                                FOREACH_WORD(w, z, t+9, i) {
+                                        char *n, *m;
+
+                                        if (!(n = strndup(w, z))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        r = sysv_translate_name(n, &m);
+                                        free(n);
+
+                                        if (r < 0)
+                                                goto finish;
+
+                                        if (r == 0)
+                                                continue;
+
+                                        if (unit_name_to_type(m) == UNIT_SERVICE)
+                                                r = unit_add_name(u, m);
+                                        else {
+                                                if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m, NULL, true)) >= 0)
+                                                        r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true);
+                                        }
+
+                                        free(m);
+
+                                        if (r < 0)
+                                                goto finish;
+                                }
+
+                        } else if (startswith(t, "Required-Start:") ||
+                                   startswith(t, "Should-Start:")) {
+                                char *i, *w;
+                                size_t z;
+
+                                state = LSB;
+
+                                FOREACH_WORD(w, z, strchr(t, ':')+1, i) {
+                                        char *n, *m;
+
+                                        if (!(n = strndup(w, z))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        r = sysv_translate_name(n, &m);
+                                        free(n);
+
+                                        if (r < 0)
+                                                goto finish;
+
+                                        if (r == 0)
+                                                continue;
+
+                                        r = unit_add_dependency_by_name(u, UNIT_AFTER, m, NULL, true);
+                                        free(m);
+
+                                        if (r < 0)
+                                                goto finish;
+                                }
+                        } else if (startswith(t, "Default-Start:")) {
+                                char *k, *d;
+
+                                state = LSB;
+
+                                k = delete_chars(t+14, WHITESPACE "-");
+
+                                if (k[0] != 0) {
+                                        if (!(d = strdup(k))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        free(s->sysv_runlevels);
+                                        s->sysv_runlevels = d;
+                                }
+
+                        } else if (startswith(t, "Description:")) {
+                                char *d;
+
+                                state = LSB_DESCRIPTION;
+
+                                if (!(d = strdup(strstrip(t+12)))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                free(u->meta.description);
+                                u->meta.description = d;
+
+                        } else if (startswith(t, "Short-Description:") &&
+                                   !u->meta.description) {
+                                char *d;
+
+                                /* We use the short description only
+                                 * if no long description is set. */
+
+                                state = LSB;
+
+                                if (!(d = strdup(strstrip(t+18)))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                u->meta.description = d;
+
+                        } else if (state == LSB_DESCRIPTION) {
+
+                                if (startswith(l, "#\t") || startswith(l, "#  ")) {
+                                        char *d;
+
+                                        assert(u->meta.description);
+                                        if (asprintf(&d, "%s %s", u->meta.description, t) < 0) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        free(u->meta.description);
+                                        u->meta.description = d;
+                                } else
+                                        state = LSB;
+                        }
+                }
+        }
+
+        if ((r = sysv_exec_commands(s)) < 0)
+                goto finish;
+
+        if (!s->sysv_runlevels || chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
+                /* If there a runlevels configured for this service
+                 * but none of the standard ones, then we assume this
+                 * is some special kind of service (which might be
+                 * needed for early boot) and don't create any links
+                 * to it. */
+
+                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0 ||
+                    (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
+                        goto finish;
+
+        } else
+                /* Don't timeout special services during boot (like fsck) */
+                s->timeout_usec = 0;
+
+        /* Special setting for all SysV services */
+        s->valid_no_process = true;
+        s->kill_mode = KILL_PROCESS_GROUP;
+
+        u->meta.load_state = UNIT_LOADED;
+        r = 0;
+
+finish:
+
+        if (f)
+                fclose(f);
+
+        return r;
+}
+
+static int service_load_sysv_name(Service *s, const char *name) {
+        char **p;
+
+        assert(s);
+        assert(name);
+
+        STRV_FOREACH(p, UNIT(s)->meta.manager->sysvinit_path) {
+                char *path;
+                int r;
+
+                if (asprintf(&path, "%s/%s", *p, name) < 0)
+                        return -ENOMEM;
+
+                assert(endswith(path, ".service"));
+                path[strlen(path)-8] = 0;
+
+                r = service_load_sysv_path(s, path);
+
+                if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
+                        /* Try Debian style .sh source'able init scripts */
+                        strcat(path, ".sh");
+                        r = service_load_sysv_path(s, path);
+                }
+
+                free(path);
+
+                if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
+                        /* Try Suse style boot.xxxx init scripts */
+
+                        if (asprintf(&path, "%s/boot.%s", *p, name) < 0)
+                                return -ENOMEM;
+
+                        path[strlen(path)-8] = 0;
+                        r = service_load_sysv_path(s, path);
+                        free(path);
+                }
+
+                if (r < 0)
+                        return r;
+
+                if ((UNIT(s)->meta.load_state != UNIT_STUB))
+                        break;
+        }
+
+        return 0;
+}
+
+static int service_load_sysv(Service *s) {
+        const char *t;
+        Iterator i;
+        int r;
+
+        assert(s);
+
+        /* Load service data from SysV init scripts, preferably with
+         * LSB headers ... */
+
+        if (strv_isempty(UNIT(s)->meta.manager->sysvinit_path))
+                return 0;
+
+        if ((t = UNIT(s)->meta.id))
+                if ((r = service_load_sysv_name(s, t)) < 0)
+                        return r;
+
+        if (UNIT(s)->meta.load_state == UNIT_STUB)
+                SET_FOREACH(t, UNIT(s)->meta.names, i) {
+                        if (t == UNIT(s)->meta.id)
+                                continue;
+
+                        if ((r == service_load_sysv_name(s, t)) < 0)
+                                return r;
+
+                        if (UNIT(s)->meta.load_state != UNIT_STUB)
+                                break;
+                }
+
+        return 0;
+}
+
+static int service_add_bus_name(Service *s) {
+        char *n;
+        int r;
+
+        assert(s);
+        assert(s->bus_name);
+
+        if (asprintf(&n, "dbus-%s.service", s->bus_name) < 0)
+                return 0;
+
+        r = unit_merge_by_name(UNIT(s), n);
+        free(n);
+
+        return r;
+}
+
+static int service_verify(Service *s) {
+        assert(s);
+
+        if (UNIT(s)->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (!s->exec_command[SERVICE_EXEC_START]) {
+                log_error("%s lacks ExecStart setting. Refusing.", UNIT(s)->meta.id);
+                return -EINVAL;
+        }
+
+        if (s->type == SERVICE_DBUS && !s->bus_name) {
+                log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->meta.id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int service_load(Unit *u) {
+        int r;
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        /* Load a .service file */
+        if ((r = unit_load_fragment(u)) < 0)
+                return r;
+
+        /* Load a classic init script as a fallback, if we couldn't find anything */
+        if (u->meta.load_state == UNIT_STUB)
+                if ((r = service_load_sysv(s)) < 0)
+                        return r;
+
+        /* Still nothing found? Then let's give up */
+        if (u->meta.load_state == UNIT_STUB)
+                return -ENOENT;
+
+        /* We were able to load something, then let's add in the
+         * dropin directories. */
+        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
+                return r;
+
+        /* This is a new unit? Then let's add in some extras */
+        if (u->meta.load_state == UNIT_LOADED) {
+                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
+                        return r;
+
+                if ((r = unit_add_default_cgroup(u)) < 0)
+                        return r;
+
+                if ((r = sysv_chkconfig_order(s)) < 0)
+                        return r;
+
+                if (s->bus_name) {
+                        if ((r = service_add_bus_name(s)) < 0)
+                                return r;
+
+                        if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
+                            return r;
+                }
+        }
+
+        return service_verify(s);
+}
+
+static void service_dump(Unit *u, FILE *f, const char *prefix) {
+
+        ServiceExecCommand c;
+        Service *s = SERVICE(u);
+        const char *prefix2;
+        char *p2;
+
+        assert(s);
+
+        p2 = strappend(prefix, "\t");
+        prefix2 = p2 ? p2 : prefix;
+
+        fprintf(f,
+                "%sService State: %s\n"
+                "%sPermissionsStartOnly: %s\n"
+                "%sRootDirectoryStartOnly: %s\n"
+                "%sValidNoProcess: %s\n"
+                "%sKillMode: %s\n"
+                "%sType: %s\n",
+                prefix, service_state_to_string(s->state),
+                prefix, yes_no(s->permissions_start_only),
+                prefix, yes_no(s->root_directory_start_only),
+                prefix, yes_no(s->valid_no_process),
+                prefix, kill_mode_to_string(s->kill_mode),
+                prefix, service_type_to_string(s->type));
+
+        if (s->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %llu\n",
+                        prefix, (unsigned long long) s->control_pid);
+
+        if (s->main_pid > 0)
+                fprintf(f,
+                        "%sMain PID: %llu\n",
+                        prefix, (unsigned long long) s->main_pid);
+
+        if (s->pid_file)
+                fprintf(f,
+                        "%sPIDFile: %s\n",
+                        prefix, s->pid_file);
+
+        if (s->bus_name)
+                fprintf(f,
+                        "%sBusName: %s\n"
+                        "%sBus Name Good: %s\n",
+                        prefix, s->bus_name,
+                        prefix, yes_no(s->bus_name_good));
+
+        exec_context_dump(&s->exec_context, f, prefix);
+
+        for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) {
+
+                if (!s->exec_command[c])
+                        continue;
+
+                fprintf(f, "%s-> %s:\n",
+                        prefix, service_exec_command_to_string(c));
+
+                exec_command_dump_list(s->exec_command[c], f, prefix2);
+        }
+
+        if (s->sysv_path)
+                fprintf(f,
+                        "%sSysV Init Script Path: %s\n"
+                        "%sSysV Init Script has LSB Header: %s\n",
+                        prefix, s->sysv_path,
+                        prefix, yes_no(s->sysv_has_lsb));
+
+        if (s->sysv_start_priority >= 0)
+                fprintf(f,
+                        "%sSysVStartPriority: %i\n",
+                        prefix, s->sysv_start_priority);
+
+        if (s->sysv_runlevels)
+                fprintf(f, "%sSysVRunLevels: %s\n",
+                        prefix, s->sysv_runlevels);
+
+        free(p2);
+}
+
+static int service_load_pid_file(Service *s) {
+        char *k;
+        unsigned long p;
+        int r;
+
+        assert(s);
+
+        if (s->main_pid_known)
+                return 0;
+
+        assert(s->main_pid <= 0);
+
+        if (!s->pid_file)
+                return -ENOENT;
+
+        if ((r = read_one_line_file(s->pid_file, &k)) < 0)
+                return r;
+
+        if ((r = safe_atolu(k, &p)) < 0) {
+                free(k);
+                return r;
+        }
+
+        if ((unsigned long) (pid_t) p != p)
+                return -ERANGE;
+
+        if (kill((pid_t) p, 0) < 0 && errno != EPERM) {
+                log_warning("PID %llu read from file %s does not exist. Your service or init script might be broken.",
+                            (unsigned long long) p, s->pid_file);
+                return -ESRCH;
+        }
+
+        if ((r = unit_watch_pid(UNIT(s), (pid_t) p)) < 0)
+                /* FIXME: we need to do something here */
+                return r;
+
+        s->main_pid = (pid_t) p;
+        s->main_pid_known = true;
+
+        return 0;
+}
+
+static int service_get_sockets(Service *s, Set **_set) {
+        Set *set;
+        Iterator i;
+        char *t;
+        int r;
+
+        assert(s);
+        assert(_set);
+
+        /* Collects all Socket objects that belong to this
+         * service. Note that a service might have multiple sockets
+         * via multiple names. */
+
+        if (!(set = set_new(NULL, NULL)))
+                return -ENOMEM;
+
+        SET_FOREACH(t, UNIT(s)->meta.names, i) {
+                char *k;
+                Unit *p;
+
+                /* Look for all socket objects that go by any of our
+                 * units and collect their fds */
+
+                if (!(k = unit_name_change_suffix(t, ".socket"))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                p = manager_get_unit(UNIT(s)->meta.manager, k);
+                free(k);
+
+                if (!p)
+                        continue;
+
+                if ((r = set_put(set, p)) < 0)
+                        goto fail;
+        }
+
+        *_set = set;
+        return 0;
+
+fail:
+        set_free(set);
+        return r;
+}
+
+static int service_notify_sockets_dead(Service *s) {
+        Iterator i;
+        Set *set;
+        Socket *sock;
+        int r;
+
+        assert(s);
+
+        /* Notifies all our sockets when we die */
+        if ((r = service_get_sockets(s, &set)) < 0)
+                return r;
+
+        SET_FOREACH(sock, set, i)
+                socket_notify_service_dead(sock);
+
+        set_free(set);
+
+        return 0;
+}
+
+static void service_set_state(Service *s, ServiceState state) {
+        ServiceState old_state;
+        assert(s);
+
+        old_state = s->state;
+        s->state = state;
+
+        if (state != SERVICE_START_PRE &&
+            state != SERVICE_START &&
+            state != SERVICE_START_POST &&
+            state != SERVICE_RELOAD &&
+            state != SERVICE_STOP &&
+            state != SERVICE_STOP_SIGTERM &&
+            state != SERVICE_STOP_SIGKILL &&
+            state != SERVICE_STOP_POST &&
+            state != SERVICE_FINAL_SIGTERM &&
+            state != SERVICE_FINAL_SIGKILL &&
+            state != SERVICE_AUTO_RESTART)
+                unit_unwatch_timer(UNIT(s), &s->timer_watch);
+
+        if (state != SERVICE_START &&
+            state != SERVICE_START_POST &&
+            state != SERVICE_RUNNING &&
+            state != SERVICE_RELOAD &&
+            state != SERVICE_STOP &&
+            state != SERVICE_STOP_SIGTERM &&
+            state != SERVICE_STOP_SIGKILL)
+                service_unwatch_main_pid(s);
+
+        if (state != SERVICE_START_PRE &&
+            state != SERVICE_START &&
+            state != SERVICE_START_POST &&
+            state != SERVICE_RELOAD &&
+            state != SERVICE_STOP &&
+            state != SERVICE_STOP_SIGTERM &&
+            state != SERVICE_STOP_SIGKILL &&
+            state != SERVICE_STOP_POST &&
+            state != SERVICE_FINAL_SIGTERM &&
+            state != SERVICE_FINAL_SIGKILL) {
+                service_unwatch_control_pid(s);
+                s->control_command = NULL;
+                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+        }
+
+        if (state == SERVICE_DEAD ||
+            state == SERVICE_STOP ||
+            state == SERVICE_STOP_SIGTERM ||
+            state == SERVICE_STOP_SIGKILL ||
+            state == SERVICE_STOP_POST ||
+            state == SERVICE_FINAL_SIGTERM ||
+            state == SERVICE_FINAL_SIGKILL ||
+            state == SERVICE_MAINTAINANCE ||
+            state == SERVICE_AUTO_RESTART)
+                service_notify_sockets_dead(s);
+
+        if (state != SERVICE_START_PRE &&
+            state != SERVICE_START &&
+            !(state == SERVICE_DEAD && UNIT(s)->meta.job))
+                service_close_socket_fd(s);
+
+        if (old_state != state)
+                log_debug("%s changed %s -> %s", UNIT(s)->meta.id, service_state_to_string(old_state), service_state_to_string(state));
+
+        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int service_coldplug(Unit *u) {
+        Service *s = SERVICE(u);
+        int r;
+
+        assert(s);
+        assert(s->state == SERVICE_DEAD);
+
+        if (s->deserialized_state != s->state) {
+
+                if (s->deserialized_state == SERVICE_START_PRE ||
+                    s->deserialized_state == SERVICE_START ||
+                    s->deserialized_state == SERVICE_START_POST ||
+                    s->deserialized_state == SERVICE_RELOAD ||
+                    s->deserialized_state == SERVICE_STOP ||
+                    s->deserialized_state == SERVICE_STOP_SIGTERM ||
+                    s->deserialized_state == SERVICE_STOP_SIGKILL ||
+                    s->deserialized_state == SERVICE_STOP_POST ||
+                    s->deserialized_state == SERVICE_FINAL_SIGTERM ||
+                    s->deserialized_state == SERVICE_FINAL_SIGKILL ||
+                    s->deserialized_state == SERVICE_AUTO_RESTART) {
+
+                        if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) {
+                                usec_t k;
+
+                                k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec;
+
+                                if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0)
+                                        return r;
+                        }
+                }
+
+                if ((s->deserialized_state == SERVICE_START &&
+                     (s->type == SERVICE_FORKING ||
+                      s->type == SERVICE_DBUS)) ||
+                    s->deserialized_state == SERVICE_START_POST ||
+                    s->deserialized_state == SERVICE_RUNNING ||
+                    s->deserialized_state == SERVICE_RELOAD ||
+                    s->deserialized_state == SERVICE_STOP ||
+                    s->deserialized_state == SERVICE_STOP_SIGTERM ||
+                    s->deserialized_state == SERVICE_STOP_SIGKILL)
+                        if (s->main_pid > 0)
+                                if ((r = unit_watch_pid(UNIT(s), s->main_pid)) < 0)
+                                        return r;
+
+                if (s->deserialized_state == SERVICE_START_PRE ||
+                    s->deserialized_state == SERVICE_START ||
+                    s->deserialized_state == SERVICE_START_POST ||
+                    s->deserialized_state == SERVICE_RELOAD ||
+                    s->deserialized_state == SERVICE_STOP ||
+                    s->deserialized_state == SERVICE_STOP_SIGTERM ||
+                    s->deserialized_state == SERVICE_STOP_SIGKILL ||
+                    s->deserialized_state == SERVICE_STOP_POST ||
+                    s->deserialized_state == SERVICE_FINAL_SIGTERM ||
+                    s->deserialized_state == SERVICE_FINAL_SIGKILL)
+                        if (s->control_pid > 0)
+                                if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
+                                        return r;
+
+                service_set_state(s, s->deserialized_state);
+        }
+
+        return 0;
+}
+
+static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
+        Iterator i;
+        int r;
+        int *rfds = NULL;
+        unsigned rn_fds = 0;
+        Set *set;
+        Socket *sock;
+
+        assert(s);
+        assert(fds);
+        assert(n_fds);
+
+        if ((r = service_get_sockets(s, &set)) < 0)
+                return r;
+
+        SET_FOREACH(sock, set, i) {
+                int *cfds;
+                unsigned cn_fds;
+
+                if ((r = socket_collect_fds(sock, &cfds, &cn_fds)) < 0)
+                        goto fail;
+
+                if (!cfds)
+                        continue;
+
+                if (!rfds) {
+                        rfds = cfds;
+                        rn_fds = cn_fds;
+                } else {
+                        int *t;
+
+                        if (!(t = new(int, rn_fds+cn_fds))) {
+                                free(cfds);
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        memcpy(t, rfds, rn_fds);
+                        memcpy(t+rn_fds, cfds, cn_fds);
+                        free(rfds);
+                        free(cfds);
+
+                        rfds = t;
+                        rn_fds = rn_fds+cn_fds;
+                }
+        }
+
+        *fds = rfds;
+        *n_fds = rn_fds;
+
+        set_free(set);
+
+        return 0;
+
+fail:
+        set_free(set);
+        free(rfds);
+
+        return r;
+}
+
+static int service_spawn(
+                Service *s,
+                ExecCommand *c,
+                bool timeout,
+                bool pass_fds,
+                bool apply_permissions,
+                bool apply_chroot,
+                pid_t *_pid) {
+
+        pid_t pid;
+        int r;
+        int *fds = NULL;
+        unsigned n_fds = 0;
+        char **argv;
+
+        assert(s);
+        assert(c);
+        assert(_pid);
+
+        if (pass_fds) {
+                if (s->socket_fd >= 0) {
+                        fds = &s->socket_fd;
+                        n_fds = 1;
+                } else if ((r = service_collect_fds(s, &fds, &n_fds)) < 0)
+                        goto fail;
+        }
+
+        if (timeout && s->timeout_usec) {
+                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                        goto fail;
+        } else
+                unit_unwatch_timer(UNIT(s), &s->timer_watch);
+
+        if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = exec_spawn(c,
+                       argv,
+                       &s->exec_context,
+                       fds, n_fds,
+                       s->meta.manager->environment,
+                       apply_permissions,
+                       apply_chroot,
+                       UNIT(s)->meta.manager->confirm_spawn,
+                       UNIT(s)->meta.cgroup_bondings,
+                       &pid);
+
+        strv_free(argv);
+        if (r < 0)
+                goto fail;
+
+        if (fds) {
+                if (s->socket_fd >= 0)
+                        service_close_socket_fd(s);
+                else
+                        free(fds);
+        }
+
+        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
+                /* FIXME: we need to do something here */
+                goto fail;
+
+        *_pid = pid;
+
+        return 0;
+
+fail:
+        free(fds);
+
+        if (timeout)
+                unit_unwatch_timer(UNIT(s), &s->timer_watch);
+
+        return r;
+}
+
+static int main_pid_good(Service *s) {
+        assert(s);
+
+        /* Returns 0 if the pid is dead, 1 if it is good, -1 if we
+         * don't know */
+
+        /* If we know the pid file, then lets just check if it is
+         * still valid */
+        if (s->main_pid_known)
+                return s->main_pid > 0;
+
+        /* We don't know the pid */
+        return -EAGAIN;
+}
+
+static int control_pid_good(Service *s) {
+        assert(s);
+
+        return s->control_pid > 0;
+}
+
+static int cgroup_good(Service *s) {
+        int r;
+
+        assert(s);
+
+        if (s->valid_no_process)
+                return -EAGAIN;
+
+        if ((r = cgroup_bonding_is_empty_list(UNIT(s)->meta.cgroup_bondings)) < 0)
+                return r;
+
+        return !r;
+}
+
+static void service_enter_dead(Service *s, bool success, bool allow_restart) {
+        int r;
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        if (allow_restart &&
+            s->allow_restart &&
+            (s->restart == SERVICE_RESTART_ALWAYS ||
+             (s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure))) {
+
+                if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_AUTO_RESTART);
+        } else
+                service_set_state(s, s->failure ? SERVICE_MAINTAINANCE : SERVICE_DEAD);
+
+        return;
+
+fail:
+        log_warning("%s failed to run install restart timer: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_dead(s, false, false);
+}
+
+static void service_enter_signal(Service *s, ServiceState state, bool success);
+
+static void service_enter_stop_post(Service *s, bool success) {
+        int r;
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        service_unwatch_control_pid(s);
+
+        s->control_command_id = SERVICE_EXEC_STOP_POST;
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+
+                service_set_state(s, SERVICE_STOP_POST);
+        } else
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to run stop-post executable: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+}
+
+static void service_enter_signal(Service *s, ServiceState state, bool success) {
+        int r;
+        bool sent = false;
+
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        if (s->kill_mode != KILL_NONE) {
+                int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
+
+                if (s->kill_mode == KILL_CONTROL_GROUP) {
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH)
+                                        goto fail;
+                        } else
+                                sent = true;
+                }
+
+                if (!sent) {
+                        r = 0;
+
+                        if (s->main_pid > 0) {
+                                if (kill(s->kill_mode == KILL_PROCESS ? s->main_pid : -s->main_pid, sig) < 0 && errno != ESRCH)
+                                        r = -errno;
+                                else
+                                        sent = true;
+                        }
+
+                        if (s->control_pid > 0) {
+                                if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH)
+                                        r = -errno;
+                                else
+                                        sent = true;
+                        }
+
+                        if (r < 0)
+                                goto fail;
+                }
+        }
+
+        if (sent && (s->main_pid > 0 || s->control_pid > 0)) {
+                if (s->timeout_usec > 0)
+                        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                                goto fail;
+
+                service_set_state(s, state);
+        } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
+                service_enter_stop_post(s, true);
+        else
+                service_enter_dead(s, true, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", UNIT(s)->meta.id, strerror(-r));
+
+        if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
+                service_enter_stop_post(s, false);
+        else
+                service_enter_dead(s, false, true);
+}
+
+static void service_enter_stop(Service *s, bool success) {
+        int r;
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        service_unwatch_control_pid(s);
+
+        s->control_command_id = SERVICE_EXEC_STOP;
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_STOP);
+        } else
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to run stop executable: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
+}
+
+static void service_enter_running(Service *s, bool success) {
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        if (main_pid_good(s) != 0 &&
+            cgroup_good(s) != 0 &&
+            (s->bus_name_good || s->type != SERVICE_DBUS))
+                service_set_state(s, SERVICE_RUNNING);
+        else if (s->valid_no_process)
+                service_set_state(s, SERVICE_EXITED);
+        else
+                service_enter_stop(s, true);
+}
+
+static void service_enter_start_post(Service *s) {
+        int r;
+        assert(s);
+
+        service_unwatch_control_pid(s);
+
+        s->control_command_id = SERVICE_EXEC_START_POST;
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+
+                service_set_state(s, SERVICE_START_POST);
+        } else
+                service_enter_running(s, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to run start-post executable: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_stop(s, false);
+}
+
+static void service_enter_start(Service *s) {
+        pid_t pid;
+        int r;
+
+        assert(s);
+
+        assert(s->exec_command[SERVICE_EXEC_START]);
+        assert(!s->exec_command[SERVICE_EXEC_START]->command_next);
+
+        if (s->type == SERVICE_FORKING)
+                service_unwatch_control_pid(s);
+        else
+                service_unwatch_main_pid(s);
+
+        if ((r = service_spawn(s,
+                               s->exec_command[SERVICE_EXEC_START],
+                               s->type == SERVICE_FORKING || s->type == SERVICE_DBUS,
+                               true,
+                               true,
+                               true,
+                               &pid)) < 0)
+                goto fail;
+
+        if (s->type == SERVICE_SIMPLE) {
+                /* For simple services we immediately start
+                 * the START_POST binaries. */
+
+                s->main_pid = pid;
+                s->main_pid_known = true;
+
+                service_enter_start_post(s);
+
+        } else  if (s->type == SERVICE_FORKING) {
+
+                /* For forking services we wait until the start
+                 * process exited. */
+
+                s->control_pid = pid;
+
+                s->control_command_id = SERVICE_EXEC_START;
+                s->control_command = s->exec_command[SERVICE_EXEC_START];
+                service_set_state(s, SERVICE_START);
+
+        } else if (s->type == SERVICE_FINISH ||
+                   s->type == SERVICE_DBUS) {
+
+                /* For finishing services we wait until the start
+                 * process exited, too, but it is our main process. */
+
+                /* For D-Bus services we know the main pid right away,
+                 * but wait for the bus name to appear on the bus. */
+
+                s->main_pid = pid;
+                s->main_pid_known = true;
+
+                service_set_state(s, SERVICE_START);
+        } else
+                assert_not_reached("Unknown service type");
+
+        return;
+
+fail:
+        log_warning("%s failed to run start exectuable: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+}
+
+static void service_enter_start_pre(Service *s) {
+        int r;
+
+        assert(s);
+
+        service_unwatch_control_pid(s);
+
+        s->control_command_id = SERVICE_EXEC_START_PRE;
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_START_PRE);
+        } else
+                service_enter_start(s);
+
+        return;
+
+fail:
+        log_warning("%s failed to run start-pre executable: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_dead(s, false, true);
+}
+
+static void service_enter_restart(Service *s) {
+        int r;
+        assert(s);
+
+        service_enter_dead(s, true, false);
+
+        if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s), JOB_FAIL, false, NULL)) < 0)
+                goto fail;
+
+        log_debug("%s scheduled restart job.", UNIT(s)->meta.id);
+        return;
+
+fail:
+
+        log_warning("%s failed to schedule restart job: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_dead(s, false, false);
+}
+
+static void service_enter_reload(Service *s) {
+        int r;
+
+        assert(s);
+
+        service_unwatch_control_pid(s);
+
+        s->control_command_id = SERVICE_EXEC_RELOAD;
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_RELOAD);
+        } else
+                service_enter_running(s, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to run reload executable: %s", UNIT(s)->meta.id, strerror(-r));
+        service_enter_stop(s, false);
+}
+
+static void service_run_next(Service *s, bool success) {
+        int r;
+
+        assert(s);
+        assert(s->control_command);
+        assert(s->control_command->command_next);
+
+        if (!success)
+                s->failure = true;
+
+        s->control_command = s->control_command->command_next;
+
+        service_unwatch_control_pid(s);
+
+        if ((r = service_spawn(s,
+                               s->control_command,
+                               true,
+                               false,
+                               !s->permissions_start_only,
+                               !s->root_directory_start_only,
+                               &s->control_pid)) < 0)
+                goto fail;
+
+        return;
+
+fail:
+        log_warning("%s failed to run spawn next executable: %s", UNIT(s)->meta.id, strerror(-r));
+
+        if (s->state == SERVICE_START_PRE)
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+        else if (s->state == SERVICE_STOP)
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
+        else if (s->state == SERVICE_STOP_POST)
+                service_enter_dead(s, false, true);
+        else
+                service_enter_stop(s, false);
+}
+
+static int service_start(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        /* We cannot fulfill this request right now, try again later
+         * please! */
+        if (s->state == SERVICE_STOP ||
+            s->state == SERVICE_STOP_SIGTERM ||
+            s->state == SERVICE_STOP_SIGKILL ||
+            s->state == SERVICE_STOP_POST ||
+            s->state == SERVICE_FINAL_SIGTERM ||
+            s->state == SERVICE_FINAL_SIGKILL)
+                return -EAGAIN;
+
+        /* Already on it! */
+        if (s->state == SERVICE_START_PRE ||
+            s->state == SERVICE_START ||
+            s->state == SERVICE_START_POST)
+                return 0;
+
+        assert(s->state == SERVICE_DEAD || s->state == SERVICE_MAINTAINANCE || s->state == SERVICE_AUTO_RESTART);
+
+        /* Make sure we don't enter a busy loop of some kind. */
+        if (!ratelimit_test(&s->ratelimit)) {
+                log_warning("%s start request repeated too quickly, refusing to start.", u->meta.id);
+                return -EAGAIN;
+        }
+
+        s->failure = false;
+        s->main_pid_known = false;
+        s->allow_restart = true;
+
+        service_enter_start_pre(s);
+        return 0;
+}
+
+static int service_stop(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        /* Cannot do this now */
+        if (s->state == SERVICE_START_PRE ||
+            s->state == SERVICE_START ||
+            s->state == SERVICE_START_POST ||
+            s->state == SERVICE_RELOAD)
+                return -EAGAIN;
+
+        /* Already on it */
+        if (s->state == SERVICE_STOP ||
+            s->state == SERVICE_STOP_SIGTERM ||
+            s->state == SERVICE_STOP_SIGKILL ||
+            s->state == SERVICE_STOP_POST ||
+            s->state == SERVICE_FINAL_SIGTERM ||
+            s->state == SERVICE_FINAL_SIGKILL)
+                return 0;
+
+        if (s->state == SERVICE_AUTO_RESTART) {
+                service_set_state(s, SERVICE_DEAD);
+                return 0;
+        }
+
+        assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
+
+        /* This is a user request, so don't do restarts on this
+         * shutdown. */
+        s->allow_restart = false;
+
+        service_enter_stop(s, true);
+        return 0;
+}
+
+static int service_reload(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
+
+        service_enter_reload(s);
+        return 0;
+}
+
+static bool service_can_reload(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        return !!s->exec_command[SERVICE_EXEC_RELOAD];
+}
+
+static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Service *s = SERVICE(u);
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", service_state_to_string(s->state));
+        unit_serialize_item(u, f, "failure", yes_no(s->failure));
+
+        if (s->control_pid > 0)
+                unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) (s->control_pid));
+
+        if (s->main_pid > 0)
+                unit_serialize_item_format(u, f, "main-pid", "%u", (unsigned) (s->main_pid));
+
+        unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
+
+        /* There's a minor uncleanliness here: if there are multiple
+         * commands attached here, we will start from the first one
+         * again */
+        if (s->control_command_id >= 0)
+                unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
+
+        if (s->socket_fd >= 0) {
+                int copy;
+
+                if ((copy = fdset_put_dup(fds, s->socket_fd)) < 0)
+                        return copy;
+
+                unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
+        }
+
+        return 0;
+}
+
+static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Service *s = SERVICE(u);
+        int r;
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                ServiceState state;
+
+                if ((state = service_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        s->deserialized_state = state;
+        } else if (streq(key, "failure")) {
+                int b;
+
+                if ((b = parse_boolean(value)) < 0)
+                        log_debug("Failed to parse failure value %s", value);
+                else
+                        s->failure = b || s->failure;
+        } else if (streq(key, "control-pid")) {
+                unsigned pid;
+
+                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        s->control_pid = (pid_t) pid;
+        } else if (streq(key, "main-pid")) {
+                unsigned pid;
+
+                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
+                        log_debug("Failed to parse main-pid value %s", value);
+                else
+                        s->main_pid = (pid_t) pid;
+        } else if (streq(key, "main-pid-known")) {
+                int b;
+
+                if ((b = parse_boolean(value)) < 0)
+                        log_debug("Failed to parse main-pid-known value %s", value);
+                else
+                        s->main_pid_known = b;
+        } else if (streq(key, "control-command")) {
+                ServiceExecCommand id;
+
+                if ((id = service_exec_command_from_string(value)) < 0)
+                        log_debug("Failed to parse exec-command value %s", value);
+                else {
+                        s->control_command_id = id;
+                        s->control_command = s->exec_command[id];
+                }
+        } else if (streq(key, "socket-fd")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                        log_debug("Failed to parse socket-fd value %s", value);
+                else {
+
+                        if (s->socket_fd >= 0)
+                                close_nointr_nofail(s->socket_fd);
+                        s->socket_fd = fdset_remove(fds, fd);
+                }
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState service_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[SERVICE(u)->state];
+}
+
+static const char *service_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return service_state_to_string(SERVICE(u)->state);
+}
+
+static bool service_check_gc(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        return !!s->sysv_path;
+}
+
+static bool service_check_snapshot(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        return !s->got_socket_fd;
+}
+
+static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+        Service *s = SERVICE(u);
+        bool success;
+
+        assert(s);
+        assert(pid >= 0);
+
+        success = is_clean_exit(code, status);
+        s->failure = s->failure || !success;
+
+        if (s->main_pid == pid) {
+
+                exec_status_fill(&s->main_exec_status, pid, code, status);
+                s->main_pid = 0;
+
+                if (s->type == SERVICE_SIMPLE || s->type == SERVICE_FINISH) {
+                        assert(s->exec_command[SERVICE_EXEC_START]);
+                        s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status;
+                }
+
+                log_debug("%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
+
+                /* The service exited, so the service is officially
+                 * gone. */
+
+                switch (s->state) {
+
+                case SERVICE_START_POST:
+                case SERVICE_RELOAD:
+                case SERVICE_STOP:
+                        /* Need to wait until the operation is
+                         * done */
+                        break;
+
+                case SERVICE_START:
+                        assert(s->type == SERVICE_FINISH);
+
+                        /* This was our main goal, so let's go on */
+                        if (success)
+                                service_enter_start_post(s);
+                        else
+                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+                        break;
+
+                case SERVICE_RUNNING:
+                        service_enter_running(s, success);
+                        break;
+
+                case SERVICE_STOP_SIGTERM:
+                case SERVICE_STOP_SIGKILL:
+
+                        if (!control_pid_good(s))
+                                service_enter_stop_post(s, success);
+
+                        /* If there is still a control process, wait for that first */
+                        break;
+
+                default:
+                        assert_not_reached("Uh, main process died at wrong time.");
+                }
+
+        } else if (s->control_pid == pid) {
+
+                if (s->control_command)
+                        exec_status_fill(&s->control_command->exec_status, pid, code, status);
+
+                s->control_pid = 0;
+
+                log_debug("%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
+
+                /* If we are shutting things down anyway we
+                 * don't care about failing commands. */
+
+                if (s->control_command && s->control_command->command_next && success) {
+
+                        /* There is another command to *
+                         * execute, so let's do that. */
+
+                        log_debug("%s running next command for state %s", u->meta.id, service_state_to_string(s->state));
+                        service_run_next(s, success);
+
+                } else {
+                        /* No further commands for this step, so let's
+                         * figure out what to do next */
+
+                        s->control_command = NULL;
+                        s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+
+                        log_debug("%s got final SIGCHLD for state %s", u->meta.id, service_state_to_string(s->state));
+
+                        switch (s->state) {
+
+                        case SERVICE_START_PRE:
+                                if (success)
+                                        service_enter_start(s);
+                                else
+                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+                                break;
+
+                        case SERVICE_START:
+                                assert(s->type == SERVICE_FORKING);
+
+                                /* Let's try to load the pid
+                                 * file here if we can. We
+                                 * ignore the return value,
+                                 * since the PID file might
+                                 * actually be created by a
+                                 * START_POST script */
+
+                                if (success) {
+                                        if (s->pid_file)
+                                                service_load_pid_file(s);
+
+                                        service_enter_start_post(s);
+                                } else
+                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+
+                                break;
+
+                        case SERVICE_START_POST:
+                                if (success && s->pid_file && !s->main_pid_known) {
+                                        int r;
+
+                                        /* Hmm, let's see if we can
+                                         * load the pid now after the
+                                         * start-post scripts got
+                                         * executed. */
+
+                                        if ((r = service_load_pid_file(s)) < 0)
+                                                log_warning("%s: failed to load PID file %s: %s", UNIT(s)->meta.id, s->pid_file, strerror(-r));
+                                }
+
+                                /* Fall through */
+
+                        case SERVICE_RELOAD:
+                                if (success)
+                                        service_enter_running(s, true);
+                                else
+                                        service_enter_stop(s, false);
+
+                                break;
+
+                        case SERVICE_STOP:
+                                service_enter_signal(s, SERVICE_STOP_SIGTERM, success);
+                                break;
+
+                        case SERVICE_STOP_SIGTERM:
+                        case SERVICE_STOP_SIGKILL:
+                                if (main_pid_good(s) <= 0)
+                                        service_enter_stop_post(s, success);
+
+                                /* If there is still a service
+                                 * process around, wait until
+                                 * that one quit, too */
+                                break;
+
+                        case SERVICE_STOP_POST:
+                        case SERVICE_FINAL_SIGTERM:
+                        case SERVICE_FINAL_SIGKILL:
+                                service_enter_dead(s, success, true);
+                                break;
+
+                        default:
+                                assert_not_reached("Uh, control process died at wrong time.");
+                        }
+                }
+        } else
+                assert_not_reached("Got SIGCHLD for unkown PID");
+}
+
+static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+        assert(elapsed == 1);
+
+        assert(w == &s->timer_watch);
+
+        switch (s->state) {
+
+        case SERVICE_START_PRE:
+        case SERVICE_START:
+                log_warning("%s operation timed out. Terminating.", u->meta.id);
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+                break;
+
+        case SERVICE_START_POST:
+        case SERVICE_RELOAD:
+                log_warning("%s operation timed out. Stopping.", u->meta.id);
+                service_enter_stop(s, false);
+                break;
+
+        case SERVICE_STOP:
+                log_warning("%s stopping timed out. Terminating.", u->meta.id);
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
+                break;
+
+        case SERVICE_STOP_SIGTERM:
+                log_warning("%s stopping timed out. Killing.", u->meta.id);
+                service_enter_signal(s, SERVICE_STOP_SIGKILL, false);
+                break;
+
+        case SERVICE_STOP_SIGKILL:
+                /* Uh, wie sent a SIGKILL and it is still not gone?
+                 * Must be something we cannot kill, so let's just be
+                 * weirded out and continue */
+
+                log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id);
+                service_enter_stop_post(s, false);
+                break;
+
+        case SERVICE_STOP_POST:
+                log_warning("%s stopping timed out (2). Terminating.", u->meta.id);
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+                break;
+
+        case SERVICE_FINAL_SIGTERM:
+                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
+                service_enter_signal(s, SERVICE_FINAL_SIGKILL, false);
+                break;
+
+        case SERVICE_FINAL_SIGKILL:
+                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", u->meta.id);
+                service_enter_dead(s, false, true);
+                break;
+
+        case SERVICE_AUTO_RESTART:
+                log_debug("%s holdoff time over, scheduling restart.", u->meta.id);
+                service_enter_restart(s);
+                break;
+
+        default:
+                assert_not_reached("Timeout at wrong time.");
+        }
+}
+
+static void service_cgroup_notify_event(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(u);
+
+        log_debug("%s: cgroup is empty", u->meta.id);
+
+        switch (s->state) {
+
+                /* Waiting for SIGCHLD is usually more interesting,
+                 * because it includes return codes/signals. Which is
+                 * why we ignore the cgroup events for most cases,
+                 * except when we don't know pid which to expect the
+                 * SIGCHLD for. */
+
+        case SERVICE_RUNNING:
+                service_enter_running(s, true);
+                break;
+
+        default:
+                ;
+        }
+}
+
+static int service_enumerate(Manager *m) {
+        char **p;
+        unsigned i;
+        DIR *d = NULL;
+        char *path = NULL, *fpath = NULL, *name = NULL;
+        int r;
+
+        assert(m);
+
+        STRV_FOREACH(p, m->sysvrcnd_path)
+                for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
+                        struct dirent *de;
+
+                        free(path);
+                        path = NULL;
+                        if (asprintf(&path, "%s/%s", *p, rcnd_table[i].path) < 0) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        if (d)
+                                closedir(d);
+
+                        if (!(d = opendir(path))) {
+                                if (errno != ENOENT)
+                                        log_warning("opendir() failed on %s: %s", path, strerror(errno));
+
+                                continue;
+                        }
+
+                        while ((de = readdir(d))) {
+                                Unit *service;
+                                int a, b;
+
+                                if (ignore_file(de->d_name))
+                                        continue;
+
+                                if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
+                                        continue;
+
+                                if (strlen(de->d_name) < 4)
+                                        continue;
+
+                                a = undecchar(de->d_name[1]);
+                                b = undecchar(de->d_name[2]);
+
+                                if (a < 0 || b < 0)
+                                        continue;
+
+                                free(fpath);
+                                fpath = NULL;
+                                if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i].path, de->d_name) < 0) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                if (access(fpath, X_OK) < 0) {
+
+                                        if (errno != ENOENT)
+                                                log_warning("access() failed on %s: %s", fpath, strerror(errno));
+
+                                        continue;
+                                }
+
+                                free(name);
+                                if (!(name = new(char, strlen(de->d_name) - 3 + 8 + 1))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                if (startswith(de->d_name+3, "boot."))
+                                        /* Drop SuSE-style boot. prefix */
+                                        strcpy(stpcpy(name, de->d_name + 3 + 5), ".service");
+                                else if (endswith(de->d_name+3, ".sh"))
+                                        /* Drop Debian-style .sh suffix */
+                                        strcpy(stpcpy(name, de->d_name + 3) - 3, ".service");
+                                else
+                                        /* Normal init scripts */
+                                        strcpy(stpcpy(name, de->d_name + 3), ".service");
+
+                                if ((r = manager_load_unit_prepare(m, name, NULL, &service)) < 0) {
+                                        log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
+                                        continue;
+                                }
+
+                                if (de->d_name[0] == 'S' &&
+                                    (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_BASIC))
+                                        SERVICE(service)->sysv_start_priority =
+                                                MAX(a*10 + b, SERVICE(service)->sysv_start_priority);
+
+                                manager_dispatch_load_queue(m);
+                                service = unit_follow_merge(service);
+
+                                if (de->d_name[0] == 'S') {
+                                        Unit *runlevel_target;
+
+                                        if ((r = manager_load_unit(m, rcnd_table[i].target, NULL, &runlevel_target)) < 0)
+                                                goto finish;
+
+                                        if ((r = unit_add_dependency(runlevel_target, UNIT_WANTS, service, true)) < 0)
+                                                goto finish;
+
+                                        if ((r = unit_add_dependency(service, UNIT_BEFORE, runlevel_target, true)) < 0)
+                                                goto finish;
+
+                                } else if (de->d_name[0] == 'K' && rcnd_table[i].type == RUNLEVEL_DOWN) {
+                                        Unit *shutdown_target;
+
+                                        /* We honour K links only for
+                                         * halt/reboot. For the normal
+                                         * runlevels we assume the
+                                         * stop jobs will be
+                                         * implicitly added by the
+                                         * core logic. Also, we don't
+                                         * really distuingish here
+                                         * between the runlevels 0 and
+                                         * 6 and just add them to the
+                                         * special shutdown target. */
+
+                                        if ((r = manager_load_unit(m, SPECIAL_SHUTDOWN_TARGET, NULL, &shutdown_target)) < 0)
+                                                goto finish;
+
+                                        if ((r = unit_add_dependency(service, UNIT_CONFLICTS, shutdown_target, true)) < 0)
+                                                goto finish;
+
+                                        if ((r = unit_add_dependency(service, UNIT_BEFORE, shutdown_target, true)) < 0)
+                                                goto finish;
+                                }
+                        }
+                }
+
+        r = 0;
+
+finish:
+        free(path);
+        free(fpath);
+        free(name);
+
+        if (d)
+                closedir(d);
+
+        return r;
+}
+
+static void service_bus_name_owner_change(
+                Unit *u,
+                const char *name,
+                const char *old_owner,
+                const char *new_owner) {
+
+        Service *s = SERVICE(u);
+
+        assert(s);
+        assert(name);
+
+        assert(streq(s->bus_name, name));
+        assert(old_owner || new_owner);
+
+        if (old_owner && new_owner)
+                log_debug("%s's D-Bus name %s changed owner from %s to %s", u->meta.id, name, old_owner, new_owner);
+        else if (old_owner)
+                log_debug("%s's D-Bus name %s no longer registered by %s", u->meta.id, name, old_owner);
+        else
+                log_debug("%s's D-Bus name %s now registered by %s", u->meta.id, name, new_owner);
+
+        s->bus_name_good = !!new_owner;
+
+        if (s->type == SERVICE_DBUS) {
+
+                /* service_enter_running() will figure out what to
+                 * do */
+                if (s->state == SERVICE_RUNNING)
+                        service_enter_running(s, true);
+                else if (s->state == SERVICE_START && new_owner)
+                        service_enter_start_post(s);
+
+        } else if (new_owner &&
+                   s->main_pid <= 0 &&
+                   (s->state == SERVICE_START ||
+                    s->state == SERVICE_START_POST ||
+                    s->state == SERVICE_RUNNING ||
+                    s->state == SERVICE_RELOAD)) {
+
+                /* Try to acquire PID from bus service */
+                log_debug("Trying to acquire PID from D-Bus name...");
+
+                bus_query_pid(u->meta.manager, name);
+        }
+}
+
+static void service_bus_query_pid_done(
+                Unit *u,
+                const char *name,
+                pid_t pid) {
+
+        Service *s = SERVICE(u);
+
+        assert(s);
+        assert(name);
+
+        log_debug("%s's D-Bus name %s is now owned by process %u", u->meta.id, name, (unsigned) pid);
+
+        if (s->main_pid <= 0 &&
+            (s->state == SERVICE_START ||
+             s->state == SERVICE_START_POST ||
+             s->state == SERVICE_RUNNING ||
+             s->state == SERVICE_RELOAD))
+                s->main_pid = pid;
+}
+
+int service_set_socket_fd(Service *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        /* This is called by the socket code when instantiating a new
+         * service for a stream socket and the socket needs to be
+         * configured. */
+
+        if (UNIT(s)->meta.load_state != UNIT_LOADED)
+                return -EINVAL;
+
+        if (s->socket_fd >= 0)
+                return -EBUSY;
+
+        if (s->state != SERVICE_DEAD)
+                return -EAGAIN;
+
+        s->socket_fd = fd;
+        s->got_socket_fd = true;
+        return 0;
+}
+
+static const char* const service_state_table[_SERVICE_STATE_MAX] = {
+        [SERVICE_DEAD] = "dead",
+        [SERVICE_START_PRE] = "start-pre",
+        [SERVICE_START] = "start",
+        [SERVICE_START_POST] = "start-post",
+        [SERVICE_RUNNING] = "running",
+        [SERVICE_EXITED] = "exited",
+        [SERVICE_RELOAD] = "reload",
+        [SERVICE_STOP] = "stop",
+        [SERVICE_STOP_SIGTERM] = "stop-sigterm",
+        [SERVICE_STOP_SIGKILL] = "stop-sigkill",
+        [SERVICE_STOP_POST] = "stop-post",
+        [SERVICE_FINAL_SIGTERM] = "final-sigterm",
+        [SERVICE_FINAL_SIGKILL] = "final-sigkill",
+        [SERVICE_MAINTAINANCE] = "maintainance",
+        [SERVICE_AUTO_RESTART] = "auto-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
+
+static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
+        [SERVICE_ONCE] = "once",
+        [SERVICE_RESTART_ON_SUCCESS] = "restart-on-success",
+        [SERVICE_RESTART_ALWAYS] = "restart-always",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
+
+static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
+        [SERVICE_FORKING] = "forking",
+        [SERVICE_SIMPLE] = "simple",
+        [SERVICE_FINISH] = "finish",
+        [SERVICE_DBUS] = "dbus"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
+
+static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
+        [SERVICE_EXEC_START_PRE] = "ExecStartPre",
+        [SERVICE_EXEC_START] = "ExecStart",
+        [SERVICE_EXEC_START_POST] = "ExecStartPost",
+        [SERVICE_EXEC_RELOAD] = "ExecReload",
+        [SERVICE_EXEC_STOP] = "ExecStop",
+        [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
+
+const UnitVTable service_vtable = {
+        .suffix = ".service",
+
+        .init = service_init,
+        .done = service_done,
+        .load = service_load,
+
+        .coldplug = service_coldplug,
+
+        .dump = service_dump,
+
+        .start = service_start,
+        .stop = service_stop,
+        .reload = service_reload,
+
+        .can_reload = service_can_reload,
+
+        .serialize = service_serialize,
+        .deserialize_item = service_deserialize_item,
+
+        .active_state = service_active_state,
+        .sub_state_to_string = service_sub_state_to_string,
+
+        .check_gc = service_check_gc,
+        .check_snapshot = service_check_snapshot,
+
+        .sigchld_event = service_sigchld_event,
+        .timer_event = service_timer_event,
+
+        .cgroup_notify_empty = service_cgroup_notify_event,
+
+        .bus_name_owner_change = service_bus_name_owner_change,
+        .bus_query_pid_done = service_bus_query_pid_done,
+
+        .bus_message_handler = bus_service_message_handler,
+
+        .enumerate = service_enumerate
+};
diff --git a/src/service.h b/src/service.h
new file mode 100644
index 0000000..40bd57e
--- /dev/null
+++ b/src/service.h
@@ -0,0 +1,147 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooservicehfoo
+#define fooservicehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Service Service;
+
+#include "unit.h"
+#include "ratelimit.h"
+
+typedef enum ServiceState {
+        SERVICE_DEAD,
+        SERVICE_START_PRE,
+        SERVICE_START,
+        SERVICE_START_POST,
+        SERVICE_RUNNING,
+        SERVICE_EXITED,            /* Nothing is running anymore, but ValidNoProcess is true, ehnce this is OK */
+        SERVICE_RELOAD,
+        SERVICE_STOP,              /* No STOP_PRE state, instead just register multiple STOP executables */
+        SERVICE_STOP_SIGTERM,
+        SERVICE_STOP_SIGKILL,
+        SERVICE_STOP_POST,
+        SERVICE_FINAL_SIGTERM,     /* In case the STOP_POST executable hangs, we shoot that down, too */
+        SERVICE_FINAL_SIGKILL,
+        SERVICE_MAINTAINANCE,
+        SERVICE_AUTO_RESTART,
+        _SERVICE_STATE_MAX,
+        _SERVICE_STATE_INVALID = -1
+} ServiceState;
+
+typedef enum ServiceRestart {
+        SERVICE_ONCE,
+        SERVICE_RESTART_ON_SUCCESS,
+        SERVICE_RESTART_ALWAYS,
+        _SERVICE_RESTART_MAX,
+        _SERVICE_RESTART_INVALID = -1
+} ServiceRestart;
+
+typedef enum ServiceType {
+        SERVICE_FORKING,  /* forks by itself (i.e. traditional daemons) */
+        SERVICE_SIMPLE,   /* we fork and go on right-away (i.e. modern socket activated daemons) */
+        SERVICE_FINISH,   /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
+        SERVICE_DBUS,     /* we fork and wait until a specific D-Bus name appears on the bus */
+        _SERVICE_TYPE_MAX,
+        _SERVICE_TYPE_INVALID = -1
+} ServiceType;
+
+typedef enum ServiceExecCommand {
+        SERVICE_EXEC_START_PRE,
+        SERVICE_EXEC_START,
+        SERVICE_EXEC_START_POST,
+        SERVICE_EXEC_RELOAD,
+        SERVICE_EXEC_STOP,
+        SERVICE_EXEC_STOP_POST,
+        _SERVICE_EXEC_COMMAND_MAX,
+        _SERVICE_EXEC_COMMAND_INVALID = -1
+} ServiceExecCommand;
+
+struct Service {
+        Meta meta;
+
+        ServiceType type;
+        ServiceRestart restart;
+
+        /* If set we'll read the main daemon PID from this file */
+        char *pid_file;
+
+        usec_t restart_usec;
+        usec_t timeout_usec;
+
+        ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        bool permissions_start_only;
+        bool root_directory_start_only;
+        bool valid_no_process;
+
+        ServiceState state, deserialized_state;
+
+        KillMode kill_mode;
+
+        ExecStatus main_exec_status;
+
+        ExecCommand *control_command;
+        ServiceExecCommand control_command_id;
+        pid_t main_pid, control_pid;
+        bool main_pid_known:1;
+
+        /* If we shut down, remember why */
+        bool failure:1;
+
+        bool bus_name_good:1;
+
+        bool allow_restart:1;
+
+        bool got_socket_fd:1;
+
+        bool sysv_has_lsb:1;
+        char *sysv_path;
+        int sysv_start_priority;
+        char *sysv_runlevels;
+
+        char *bus_name;
+
+        RateLimit ratelimit;
+
+        int socket_fd;
+
+        Watch timer_watch;
+};
+
+extern const UnitVTable service_vtable;
+
+int service_set_socket_fd(Service *s, int fd);
+
+const char* service_state_to_string(ServiceState i);
+ServiceState service_state_from_string(const char *s);
+
+const char* service_restart_to_string(ServiceRestart i);
+ServiceRestart service_restart_from_string(const char *s);
+
+const char* service_type_to_string(ServiceType i);
+ServiceType service_type_from_string(const char *s);
+
+const char* service_exec_command_to_string(ServiceExecCommand i);
+ServiceExecCommand service_exec_command_from_string(const char *s);
+
+#endif
diff --git a/src/set.c b/src/set.c
new file mode 100644
index 0000000..efd20db
--- /dev/null
+++ b/src/set.c
@@ -0,0 +1,114 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+
+#include "set.h"
+#include "hashmap.h"
+
+#define MAKE_SET(h) ((Set*) (h))
+#define MAKE_HASHMAP(s) ((Hashmap*) (s))
+
+/* For now this is not much more than a wrapper around a hashmap */
+
+Set *set_new(hash_func_t hash_func, compare_func_t compare_func) {
+        return MAKE_SET(hashmap_new(hash_func, compare_func));
+}
+
+void set_free(Set* s) {
+        hashmap_free(MAKE_HASHMAP(s));
+}
+
+int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) {
+        return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func);
+}
+
+int set_put(Set *s, void *value) {
+        return hashmap_put(MAKE_HASHMAP(s), value, value);
+}
+
+int set_replace(Set *s, void *value) {
+        return hashmap_replace(MAKE_HASHMAP(s), value, value);
+}
+
+void *set_get(Set *s, void *value) {
+        return hashmap_get(MAKE_HASHMAP(s), value);
+}
+
+void *set_remove(Set *s, void *value) {
+        return hashmap_remove(MAKE_HASHMAP(s), value);
+}
+
+int set_remove_and_put(Set *s, void *old_value, void *new_value) {
+        return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value);
+}
+
+unsigned set_size(Set *s) {
+        return hashmap_size(MAKE_HASHMAP(s));
+}
+
+bool set_isempty(Set *s) {
+        return hashmap_isempty(MAKE_HASHMAP(s));
+}
+
+void *set_iterate(Set *s, Iterator *i) {
+        return hashmap_iterate(MAKE_HASHMAP(s), i, NULL);
+}
+
+void *set_iterate_backwards(Set *s, Iterator *i) {
+        return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL);
+}
+
+void *set_iterate_skip(Set *s, void *value, Iterator *i) {
+        return hashmap_iterate_skip(MAKE_HASHMAP(s), value, i);
+}
+
+void *set_steal_first(Set *s) {
+        return hashmap_steal_first(MAKE_HASHMAP(s));
+}
+
+void* set_first(Set *s) {
+        return hashmap_first(MAKE_HASHMAP(s));
+}
+
+void* set_last(Set *s) {
+        return hashmap_last(MAKE_HASHMAP(s));
+}
+
+int set_merge(Set *s, Set *other) {
+        return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
+}
+
+void set_move(Set *s, Set *other) {
+        return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
+}
+
+int set_move_one(Set *s, Set *other, void *value) {
+        return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value);
+}
+
+Set* set_copy(Set *s) {
+        return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s)));
+}
+
+void set_clear(Set *s) {
+        hashmap_clear(MAKE_HASHMAP(s));
+}
diff --git a/src/set.h b/src/set.h
new file mode 100644
index 0000000..dd2e91d
--- /dev/null
+++ b/src/set.h
@@ -0,0 +1,68 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foosethfoo
+#define foosethfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+/* Pretty straightforward set implementation. Internally based on the
+ * hashmap. That means that as a minor optimization a NULL set
+ * object will be treated as empty set for all read
+ * operations. That way it is not necessary to instantiate an object
+ * for each set use. */
+
+#include "hashmap.h"
+
+typedef struct Set Set;
+
+Set *set_new(hash_func_t hash_func, compare_func_t compare_func);
+void set_free(Set* s);
+Set* set_copy(Set *s);
+int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func);
+
+int set_put(Set *s, void *value);
+int set_replace(Set *s, void *value);
+void *set_get(Set *s, void *value);
+void *set_remove(Set *s, void *value);
+int set_remove_and_put(Set *s, void *old_value, void *new_value);
+
+int set_merge(Set *s, Set *other);
+void set_move(Set *s, Set *other);
+int set_move_one(Set *s, Set *other, void *value);
+
+unsigned set_size(Set *s);
+bool set_isempty(Set *s);
+
+void *set_iterate(Set *s, Iterator *i);
+void *set_iterate_backwards(Set *s, Iterator *i);
+void *set_iterate_skip(Set *s, void *value, Iterator *i);
+
+void set_clear(Set *s);
+void *set_steal_first(Set *s);
+void* set_first(Set *s);
+void* set_last(Set *s);
+
+#define SET_FOREACH(e, s, i) \
+        for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i)))
+
+#define SET_FOREACH_BACKWARDS(e, s, i) \
+        for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i)))
+
+#endif
diff --git a/src/snapshot.c b/src/snapshot.c
new file mode 100644
index 0000000..513bf66
--- /dev/null
+++ b/src/snapshot.c
@@ -0,0 +1,276 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "unit.h"
+#include "snapshot.h"
+#include "unit-name.h"
+#include "dbus-snapshot.h"
+
+static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
+        [SNAPSHOT_DEAD] = UNIT_INACTIVE,
+        [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
+};
+
+static void snapshot_set_state(Snapshot *s, SnapshotState state) {
+        SnapshotState old_state;
+        assert(s);
+
+        old_state = s->state;
+        s->state = state;
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(s)->meta.id,
+                          snapshot_state_to_string(old_state),
+                          snapshot_state_to_string(state));
+
+        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int snapshot_coldplug(Unit *u) {
+        Snapshot *s = SNAPSHOT(u);
+
+        assert(s);
+        assert(s->state == SNAPSHOT_DEAD);
+
+        if (s->deserialized_state != s->state)
+                snapshot_set_state(s, s->deserialized_state);
+
+        return 0;
+}
+
+static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
+        Snapshot *s = SNAPSHOT(u);
+
+        assert(s);
+        assert(f);
+
+        fprintf(f,
+                "%sSnapshot State: %s\n"
+                "%sClean Up: %s\n",
+                prefix, snapshot_state_to_string(s->state),
+                prefix, yes_no(s->cleanup));
+}
+
+static int snapshot_start(Unit *u) {
+        Snapshot *s = SNAPSHOT(u);
+
+        assert(s);
+        assert(s->state == SNAPSHOT_DEAD);
+
+        snapshot_set_state(s, SNAPSHOT_ACTIVE);
+
+        if (s->cleanup)
+                unit_add_to_cleanup_queue(u);
+
+        return 0;
+}
+
+static int snapshot_stop(Unit *u) {
+        Snapshot *s = SNAPSHOT(u);
+
+        assert(s);
+        assert(s->state == SNAPSHOT_ACTIVE);
+
+        snapshot_set_state(s, SNAPSHOT_DEAD);
+        return 0;
+}
+
+static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Snapshot *s = SNAPSHOT(u);
+        Unit *other;
+        Iterator i;
+
+        assert(s);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
+        unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
+                unit_serialize_item(u, f, "requires", other->meta.id);
+
+        return 0;
+}
+
+static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Snapshot *s = SNAPSHOT(u);
+        int r;
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                SnapshotState state;
+
+                if ((state = snapshot_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        s->deserialized_state = state;
+
+        } else if (streq(key, "cleanup")) {
+
+                if ((r = parse_boolean(value)) < 0)
+                        log_debug("Failed to parse cleanup value %s", value);
+                else
+                        s->cleanup = r;
+
+        } else if (streq(key, "requires")) {
+
+                if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, value, NULL, true)) < 0)
+                        return r;
+
+                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, value, NULL, true)) < 0)
+                        return r;
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState snapshot_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[SNAPSHOT(u)->state];
+}
+
+static const char *snapshot_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return snapshot_state_to_string(SNAPSHOT(u)->state);
+}
+
+int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **_s) {
+        Iterator i;
+        Unit *other, *u = NULL;
+        char *n = NULL;
+        int r;
+        const char *k;
+
+        assert(m);
+        assert(_s);
+
+        if (name) {
+                if (!unit_name_is_valid(name))
+                        return -EINVAL;
+
+                if (unit_name_to_type(name) != UNIT_SNAPSHOT)
+                        return -EINVAL;
+
+                if (manager_get_unit(m, name))
+                        return -EEXIST;
+
+        } else {
+
+                for (;;) {
+                        if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
+                                return -ENOMEM;
+
+                        if (!manager_get_unit(m, n))
+                                break;
+
+                        free(n);
+                }
+
+                name = n;
+        }
+
+        r = manager_load_unit(m, name, NULL, &u);
+        free(n);
+
+        if (r < 0)
+                goto fail;
+
+        HASHMAP_FOREACH_KEY(other, k, m->units, i) {
+
+                if (UNIT_VTABLE(other)->no_snapshots)
+                        continue;
+
+                if (k != other->meta.id)
+                        continue;
+
+                if (UNIT_VTABLE(other)->check_snapshot)
+                        if (!UNIT_VTABLE(other)->check_snapshot(other))
+                            continue;
+
+                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        continue;
+
+                if ((r = unit_add_dependency(u, UNIT_REQUIRES, other, true)) < 0)
+                        goto fail;
+
+                if ((r = unit_add_dependency(u, UNIT_AFTER, other, true)) < 0)
+                        goto fail;
+        }
+
+        SNAPSHOT(u)->cleanup = cleanup;
+        *_s = SNAPSHOT(u);
+
+        return 0;
+
+fail:
+        if (u)
+                unit_add_to_cleanup_queue(u);
+
+        return r;
+}
+
+void snapshot_remove(Snapshot *s) {
+        assert(s);
+
+        unit_add_to_cleanup_queue(UNIT(s));
+}
+
+static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
+        [SNAPSHOT_DEAD] = "dead",
+        [SNAPSHOT_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
+
+const UnitVTable snapshot_vtable = {
+        .suffix = ".snapshot",
+
+        .no_alias = true,
+        .no_instances = true,
+        .no_snapshots = true,
+        .no_gc = true,
+
+        .load = unit_load_nop,
+        .coldplug = snapshot_coldplug,
+
+        .dump = snapshot_dump,
+
+        .start = snapshot_start,
+        .stop = snapshot_stop,
+
+        .serialize = snapshot_serialize,
+        .deserialize_item = snapshot_deserialize_item,
+
+        .active_state = snapshot_active_state,
+        .sub_state_to_string = snapshot_sub_state_to_string,
+
+        .bus_message_handler = bus_snapshot_message_handler
+};
diff --git a/src/snapshot.h b/src/snapshot.h
new file mode 100644
index 0000000..959a509
--- /dev/null
+++ b/src/snapshot.h
@@ -0,0 +1,52 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foosnapshothfoo
+#define foosnapshothfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Snapshot Snapshot;
+
+#include "unit.h"
+
+typedef enum SnapshotState {
+        SNAPSHOT_DEAD,
+        SNAPSHOT_ACTIVE,
+        _SNAPSHOT_STATE_MAX,
+        _SNAPSHOT_STATE_INVALID = -1
+} SnapshotState;
+
+struct Snapshot {
+        Meta meta;
+
+        SnapshotState state, deserialized_state;
+
+        bool cleanup;
+};
+
+extern const UnitVTable snapshot_vtable;
+
+int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **s);
+void snapshot_remove(Snapshot *s);
+
+const char* snapshot_state_to_string(SnapshotState i);
+SnapshotState snapshot_state_from_string(const char *s);
+
+#endif
diff --git a/src/socket-util.c b/src/socket-util.c
new file mode 100644
index 0000000..32f6bcb
--- /dev/null
+++ b/src/socket-util.c
@@ -0,0 +1,468 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "macro.h"
+#include "util.h"
+#include "socket-util.h"
+
+int socket_address_parse(SocketAddress *a, const char *s) {
+        int r;
+        char *e, *n;
+        unsigned u;
+
+        assert(a);
+        assert(s);
+
+        zero(*a);
+        a->type = SOCK_STREAM;
+
+        if (*s == '[') {
+                /* IPv6 in [x:.....:z]:p notation */
+
+                if (!(e = strchr(s+1, ']')))
+                        return -EINVAL;
+
+                if (!(n = strndup(s+1, e-s-1)))
+                        return -ENOMEM;
+
+                errno = 0;
+                if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
+                        free(n);
+                        return errno != 0 ? -errno : -EINVAL;
+                }
+
+                free(n);
+
+                e++;
+                if (*e != ':')
+                        return -EINVAL;
+
+                e++;
+                if ((r = safe_atou(e, &u)) < 0)
+                        return r;
+
+                if (u <= 0 || u > 0xFFFF)
+                        return -EINVAL;
+
+                a->sockaddr.in6.sin6_family = AF_INET6;
+                a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+                a->size = sizeof(struct sockaddr_in6);
+
+        } else if (*s == '/') {
+                /* AF_UNIX socket */
+
+                size_t l;
+
+                l = strlen(s);
+                if (l >= sizeof(a->sockaddr.un.sun_path))
+                        return -EINVAL;
+
+                a->sockaddr.un.sun_family = AF_UNIX;
+                memcpy(a->sockaddr.un.sun_path, s, l);
+                a->size = sizeof(sa_family_t) + l + 1;
+
+        } else if (*s == '@') {
+                /* Abstract AF_UNIX socket */
+                size_t l;
+
+                l = strlen(s+1);
+                if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
+                        return -EINVAL;
+
+                a->sockaddr.un.sun_family = AF_UNIX;
+                memcpy(a->sockaddr.un.sun_path+1, s+1, l);
+                a->size = sizeof(struct sockaddr_un);
+
+        } else {
+
+                if ((e = strchr(s, ':'))) {
+
+                        if ((r = safe_atou(e+1, &u)) < 0)
+                                return r;
+
+                        if (u <= 0 || u > 0xFFFF)
+                                return -EINVAL;
+
+                        if (!(n = strndup(s, e-s)))
+                                return -ENOMEM;
+
+                        /* IPv4 in w.x.y.z:p notation? */
+                        if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
+                                free(n);
+                                return -errno;
+                        }
+
+                        if (r > 0) {
+                                /* Gotcha, it's a traditional IPv4 address */
+                                free(n);
+
+                                a->sockaddr.in4.sin_family = AF_INET;
+                                a->sockaddr.in4.sin_port = htons((uint16_t) u);
+                                a->size = sizeof(struct sockaddr_in);
+                        } else {
+                                unsigned idx;
+
+                                if (strlen(n) > IF_NAMESIZE-1) {
+                                        free(n);
+                                        return -EINVAL;
+                                }
+
+                                /* Uh, our last resort, an interface name */
+                                idx = if_nametoindex(n);
+                                free(n);
+
+                                if (idx == 0)
+                                        return -EINVAL;
+
+                                a->sockaddr.in6.sin6_family = AF_INET6;
+                                a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+                                a->sockaddr.in6.sin6_scope_id = idx;
+                                a->sockaddr.in6.sin6_addr = in6addr_any;
+                                a->size = sizeof(struct sockaddr_in6);
+
+                        }
+                } else {
+
+                        /* Just a port */
+                        if ((r = safe_atou(s, &u)) < 0)
+                                return r;
+
+                        if (u <= 0 || u > 0xFFFF)
+                                return -EINVAL;
+
+                        a->sockaddr.in6.sin6_family = AF_INET6;
+                        a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+                        a->sockaddr.in6.sin6_addr = in6addr_any;
+                        a->size = sizeof(struct sockaddr_in6);
+                }
+        }
+
+        return 0;
+}
+
+int socket_address_verify(const SocketAddress *a) {
+        assert(a);
+
+        switch (socket_address_family(a)) {
+                case AF_INET:
+                        if (a->size != sizeof(struct sockaddr_in))
+                                return -EINVAL;
+
+                        if (a->sockaddr.in4.sin_port == 0)
+                                return -EINVAL;
+
+                        return 0;
+
+                case AF_INET6:
+                        if (a->size != sizeof(struct sockaddr_in6))
+                                return -EINVAL;
+
+                        if (a->sockaddr.in6.sin6_port == 0)
+                                return -EINVAL;
+
+                        return 0;
+
+                case AF_UNIX:
+                        if (a->size < sizeof(sa_family_t))
+                                return -EINVAL;
+
+                        if (a->size > sizeof(sa_family_t)) {
+
+                                if (a->sockaddr.un.sun_path[0] == 0) {
+                                        /* abstract */
+                                        if (a->size != sizeof(struct sockaddr_un))
+                                                return -EINVAL;
+                                } else {
+                                        char *e;
+
+                                        /* path */
+                                        if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
+                                                return -EINVAL;
+
+                                        if (a->size != sizeof(sa_family_t) + (e - a->sockaddr.un.sun_path) + 1)
+                                                return -EINVAL;
+                                }
+                        }
+
+                        return 0;
+
+                default:
+                        return -EAFNOSUPPORT;
+        }
+}
+
+int socket_address_print(const SocketAddress *a, char **p) {
+        int r;
+        assert(a);
+        assert(p);
+
+        if ((r = socket_address_verify(a)) < 0)
+                return r;
+
+        switch (socket_address_family(a)) {
+                case AF_INET: {
+                        char *ret;
+
+                        if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
+                                return -ENOMEM;
+
+                        if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
+                                free(ret);
+                                return -errno;
+                        }
+
+                        sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
+                        *p = ret;
+                        return 0;
+                }
+
+                case AF_INET6: {
+                        char *ret;
+
+                        if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
+                                return -ENOMEM;
+
+                        ret[0] = '[';
+                        if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
+                                free(ret);
+                                return -errno;
+                        }
+
+                        sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
+                        *p = ret;
+                        return 0;
+                }
+
+                case AF_UNIX: {
+                        char *ret;
+
+                        if (a->size <= sizeof(sa_family_t)) {
+
+                                if (!(ret = strdup("<unamed>")))
+                                        return -ENOMEM;
+
+                        } else if (a->sockaddr.un.sun_path[0] == 0) {
+                                /* abstract */
+
+                                /* FIXME: We assume we can print the
+                                 * socket path here and that it hasn't
+                                 * more than one NUL byte. That is
+                                 * actually an invalid assumption */
+
+                                if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
+                                        return -ENOMEM;
+
+                                ret[0] = '@';
+                                memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
+                                ret[sizeof(a->sockaddr.un.sun_path)] = 0;
+
+                        } else {
+
+                                if (!(ret = strdup(a->sockaddr.un.sun_path)))
+                                        return -ENOMEM;
+                        }
+
+                        *p = ret;
+                        return 0;
+                }
+
+                default:
+                        return -EINVAL;
+        }
+}
+
+int socket_address_listen(
+                const SocketAddress *a,
+                int backlog,
+                SocketAddressBindIPv6Only only,
+                const char *bind_to_device,
+                mode_t directory_mode,
+                mode_t socket_mode,
+                int *ret) {
+
+        int r, fd, one;
+        assert(a);
+        assert(ret);
+
+        if ((r = socket_address_verify(a)) < 0)
+                return r;
+
+        if ((fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)) < 0)
+                return -errno;
+
+        if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
+                int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
+
+                if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
+                        goto fail;
+        }
+
+        if (bind_to_device)
+                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
+                        goto fail;
+
+        one = 1;
+        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
+                goto fail;
+
+        if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
+                mode_t old_mask;
+
+                /* Create parents */
+                mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
+
+                /* Enforce the right access mode for the socket*/
+                old_mask = umask(~ socket_mode);
+
+                /* Include the original umask in our mask */
+                umask(~socket_mode | old_mask);
+
+                r = bind(fd, &a->sockaddr.sa, a->size);
+
+                if (r < 0 && errno == EADDRINUSE) {
+                        /* Unlink and try again */
+                        unlink(a->sockaddr.un.sun_path);
+                        r = bind(fd, &a->sockaddr.sa, a->size);
+                }
+
+                umask(old_mask);
+        } else
+                r = bind(fd, &a->sockaddr.sa, a->size);
+
+        if (r < 0)
+                goto fail;
+
+        if (a->type == SOCK_STREAM)
+                if (listen(fd, backlog) < 0)
+                        goto fail;
+
+        *ret = fd;
+        return 0;
+
+fail:
+        r = -errno;
+        close_nointr_nofail(fd);
+        return r;
+}
+
+bool socket_address_can_accept(const SocketAddress *a) {
+        assert(a);
+
+        return
+                a->type == SOCK_STREAM ||
+                a->type == SOCK_SEQPACKET;
+}
+
+bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
+        assert(a);
+        assert(b);
+
+        /* Invalid addresses are unequal to all */
+        if (socket_address_verify(a) < 0 ||
+            socket_address_verify(b) < 0)
+                return false;
+
+        if (a->type != b->type)
+                return false;
+
+        if (a->size != b->size)
+                return false;
+
+        if (socket_address_family(a) != socket_address_family(b))
+                return false;
+
+        switch (socket_address_family(a)) {
+
+        case AF_INET:
+                if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
+                        return false;
+
+                if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
+                        return false;
+
+                break;
+
+        case AF_INET6:
+                if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
+                        return false;
+
+                if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
+                        return false;
+
+                break;
+
+        case AF_UNIX:
+
+                if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
+                        return false;
+
+                if (a->sockaddr.un.sun_path[0]) {
+                        if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
+                                return false;
+                } else {
+                        if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
+                                return false;
+                }
+
+                break;
+
+        default:
+                /* Cannot compare, so we assume the addresses are different */
+                return false;
+        }
+
+        return true;
+}
+
+bool socket_address_is(const SocketAddress *a, const char *s) {
+        struct SocketAddress b;
+
+        assert(a);
+        assert(s);
+
+        if (socket_address_parse(&b, s) < 0)
+                return false;
+
+        return socket_address_equal(a, &b);
+}
+
+bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
+        assert(a);
+
+        if (socket_address_family(a) != AF_UNIX)
+                return false;
+
+        if (a->sockaddr.un.sun_path[0] == 0)
+                return false;
+
+        return path_startswith(a->sockaddr.un.sun_path, prefix);
+}
diff --git a/src/socket-util.h b/src/socket-util.h
new file mode 100644
index 0000000..1419216
--- /dev/null
+++ b/src/socket-util.h
@@ -0,0 +1,79 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foosocketutilhfoo
+#define foosocketutilhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <net/if.h>
+
+#include "macro.h"
+#include "util.h"
+
+typedef struct SocketAddress {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_in in4;
+                struct sockaddr_in6 in6;
+                struct sockaddr_un un;
+                struct sockaddr_storage storage;
+        } sockaddr;
+
+        /* We store the size here explicitly due to the weird
+         * sockaddr_un semantics for abstract sockets */
+        socklen_t size;
+
+        /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */
+        int type;
+} SocketAddress;
+
+typedef enum SocketAddressBindIPv6Only {
+        SOCKET_ADDRESS_DEFAULT,
+        SOCKET_ADDRESS_BOTH,
+        SOCKET_ADDRESS_IPV6_ONLY
+} SocketAddressBindIPv6Only;
+
+#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
+
+int socket_address_parse(SocketAddress *a, const char *s);
+int socket_address_print(const SocketAddress *a, char **p);
+int socket_address_verify(const SocketAddress *a);
+
+bool socket_address_can_accept(const SocketAddress *a);
+
+int socket_address_listen(
+                const SocketAddress *a,
+                int backlog,
+                SocketAddressBindIPv6Only only,
+                const char *bind_to_device,
+                mode_t directory_mode,
+                mode_t socket_mode,
+                int *ret);
+
+bool socket_address_is(const SocketAddress *a, const char *s);
+
+bool socket_address_equal(const SocketAddress *a, const SocketAddress *b);
+
+bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);
+
+#endif
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..259f273
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,1411 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <arpa/inet.h>
+
+#include "unit.h"
+#include "socket.h"
+#include "log.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "dbus-socket.h"
+
+static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
+        [SOCKET_DEAD] = UNIT_INACTIVE,
+        [SOCKET_START_PRE] = UNIT_ACTIVATING,
+        [SOCKET_START_POST] = UNIT_ACTIVATING,
+        [SOCKET_LISTENING] = UNIT_ACTIVE,
+        [SOCKET_RUNNING] = UNIT_ACTIVE,
+        [SOCKET_STOP_PRE] = UNIT_DEACTIVATING,
+        [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING,
+        [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING,
+        [SOCKET_STOP_POST] = UNIT_DEACTIVATING,
+        [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING,
+        [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING,
+        [SOCKET_MAINTAINANCE] = UNIT_INACTIVE,
+};
+
+static void socket_init(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        s->timer_watch.type = WATCH_INVALID;
+        s->backlog = SOMAXCONN;
+        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        s->directory_mode = 0755;
+        s->socket_mode = 0666;
+
+        exec_context_init(&s->exec_context);
+
+        s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
+}
+
+static void socket_unwatch_control_pid(Socket *s) {
+        assert(s);
+
+        if (s->control_pid <= 0)
+                return;
+
+        unit_unwatch_pid(UNIT(s), s->control_pid);
+        s->control_pid = 0;
+}
+
+static void socket_done(Unit *u) {
+        Socket *s = SOCKET(u);
+        SocketPort *p;
+
+        assert(s);
+
+        while ((p = s->ports)) {
+                LIST_REMOVE(SocketPort, port, s->ports, p);
+
+                if (p->fd >= 0) {
+                        unit_unwatch_fd(UNIT(s), &p->fd_watch);
+                        close_nointr_nofail(p->fd);
+                }
+
+                free(p->path);
+                free(p);
+        }
+
+        exec_context_done(&s->exec_context);
+        exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
+        s->control_command = NULL;
+
+        socket_unwatch_control_pid(s);
+
+        s->service = NULL;
+
+        free(s->bind_to_device);
+        s->bind_to_device = NULL;
+
+        unit_unwatch_timer(u, &s->timer_watch);
+}
+
+static bool have_non_accept_socket(Socket *s) {
+        SocketPort *p;
+
+        assert(s);
+
+        if (!s->accept)
+                return true;
+
+        LIST_FOREACH(port, p, s->ports) {
+
+                if (p->type != SOCKET_SOCKET)
+                        return true;
+
+                if (!socket_address_can_accept(&p->address))
+                        return true;
+        }
+
+        return false;
+}
+
+static int socket_verify(Socket *s) {
+        assert(s);
+
+        if (UNIT(s)->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (!s->ports) {
+                log_error("%s lacks Listen setting. Refusing.", UNIT(s)->meta.id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static bool socket_needs_mount(Socket *s, const char *prefix) {
+        SocketPort *p;
+
+        assert(s);
+
+        LIST_FOREACH(port, p, s->ports) {
+
+                if (p->type == SOCKET_SOCKET) {
+                        if (socket_address_needs_mount(&p->address, prefix))
+                                return true;
+                } else {
+                        assert(p->type == SOCKET_FIFO);
+                        if (path_startswith(p->path, prefix))
+                                return true;
+                }
+        }
+
+        return false;
+}
+
+int socket_add_one_mount_link(Socket *s, Mount *m) {
+        int r;
+
+        assert(s);
+        assert(m);
+
+        if (s->meta.load_state != UNIT_LOADED ||
+            m->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (!socket_needs_mount(s, m->where))
+                return 0;
+
+        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
+                return r;
+
+        if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
+                return r;
+
+        return 0;
+}
+
+static int socket_add_mount_links(Socket *s) {
+        Meta *other;
+        int r;
+
+        assert(s);
+
+        LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_MOUNT])
+                if ((r = socket_add_one_mount_link(s, (Mount*) other)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int socket_add_device_link(Socket *s) {
+        char *t;
+        int r;
+
+        assert(s);
+
+        if (!s->bind_to_device)
+                return 0;
+
+        if (asprintf(&t, "/sys/subsystem/net/devices/%s", s->bind_to_device) < 0)
+                return -ENOMEM;
+
+        r = unit_add_node_link(UNIT(s), t, false);
+        free(t);
+
+        return r;
+}
+
+static int socket_load(Unit *u) {
+        Socket *s = SOCKET(u);
+        int r;
+
+        assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        if ((r = unit_load_fragment_and_dropin(u)) < 0)
+                return r;
+
+        /* This is a new unit? Then let's add in some extras */
+        if (u->meta.load_state == UNIT_LOADED) {
+
+                if (have_non_accept_socket(s)) {
+                        if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service)))
+                                return r;
+
+                        if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service), true)) < 0)
+                                return r;
+                }
+
+                if ((r = socket_add_mount_links(s)) < 0)
+                        return r;
+
+                if ((r = socket_add_device_link(s)) < 0)
+                        return r;
+
+                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
+                        return r;
+
+                if ((r = unit_add_default_cgroup(u)) < 0)
+                        return r;
+        }
+
+        return socket_verify(s);
+}
+
+static const char* listen_lookup(int type) {
+
+        if (type == SOCK_STREAM)
+                return "ListenStream";
+        else if (type == SOCK_DGRAM)
+                return "ListenDatagram";
+        else if (type == SOCK_SEQPACKET)
+                return "ListenSequentialPacket";
+
+        assert_not_reached("Unknown socket type");
+        return NULL;
+}
+
+static void socket_dump(Unit *u, FILE *f, const char *prefix) {
+
+        SocketExecCommand c;
+        Socket *s = SOCKET(u);
+        SocketPort *p;
+        const char *prefix2;
+        char *p2;
+
+        assert(s);
+        assert(f);
+
+        p2 = strappend(prefix, "\t");
+        prefix2 = p2 ? p2 : prefix;
+
+        fprintf(f,
+                "%sSocket State: %s\n"
+                "%sBindIPv6Only: %s\n"
+                "%sBacklog: %u\n"
+                "%sKillMode: %s\n"
+                "%sSocketMode: %04o\n"
+                "%sDirectoryMode: %04o\n",
+                prefix, socket_state_to_string(s->state),
+                prefix, yes_no(s->bind_ipv6_only),
+                prefix, s->backlog,
+                prefix, kill_mode_to_string(s->kill_mode),
+                prefix, s->socket_mode,
+                prefix, s->directory_mode);
+
+        if (s->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %llu\n",
+                        prefix, (unsigned long long) s->control_pid);
+
+        if (s->bind_to_device)
+                fprintf(f,
+                        "%sBindToDevice: %s\n",
+                        prefix, s->bind_to_device);
+
+        if (s->accept)
+                fprintf(f,
+                        "%sAccepted: %u\n",
+                        prefix, s->n_accepted);
+
+        LIST_FOREACH(port, p, s->ports) {
+
+                if (p->type == SOCKET_SOCKET) {
+                        const char *t;
+                        int r;
+                        char *k;
+
+                        if ((r = socket_address_print(&p->address, &k)) < 0)
+                                t = strerror(-r);
+                        else
+                                t = k;
+
+                        fprintf(f, "%s%s: %s\n", prefix, listen_lookup(p->address.type), k);
+                        free(k);
+                } else
+                        fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
+        }
+
+        exec_context_dump(&s->exec_context, f, prefix);
+
+        for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
+                if (!s->exec_command[c])
+                        continue;
+
+                fprintf(f, "%s-> %s:\n",
+                        prefix, socket_exec_command_to_string(c));
+
+                exec_command_dump_list(s->exec_command[c], f, prefix2);
+        }
+
+        free(p2);
+}
+
+static int instance_from_socket(int fd, unsigned nr, char **instance) {
+        socklen_t l;
+        char *r;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_un un;
+                struct sockaddr_in in;
+                struct sockaddr_in6 in6;
+                struct sockaddr_storage storage;
+        } local, remote;
+
+        assert(fd >= 0);
+        assert(instance);
+
+        l = sizeof(local);
+        if (getsockname(fd, &local.sa, &l) < 0)
+                return -errno;
+
+        l = sizeof(remote);
+        if (getpeername(fd, &remote.sa, &l) < 0)
+                return -errno;
+
+        switch (local.sa.sa_family) {
+
+        case AF_INET: {
+                uint32_t
+                        a = ntohl(local.in.sin_addr.s_addr),
+                        b = ntohl(remote.in.sin_addr.s_addr);
+
+                if (asprintf(&r,
+                             "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
+                             nr,
+                             a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
+                             ntohs(local.in.sin_port),
+                             b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
+                             ntohs(remote.in.sin_port)) < 0)
+                        return -ENOMEM;
+
+                break;
+        }
+
+        case AF_INET6: {
+                char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN];
+
+                if (asprintf(&r,
+                             "%u-%s:%u-%s:%u",
+                             nr,
+                             inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)),
+                             ntohs(local.in6.sin6_port),
+                             inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)),
+                             ntohs(remote.in6.sin6_port)) < 0)
+                        return -ENOMEM;
+
+                break;
+        }
+
+        case AF_UNIX: {
+                struct ucred ucred;
+
+                l = sizeof(ucred);
+                if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
+                        return -errno;
+
+                if (asprintf(&r,
+                             "%u-%llu-%llu",
+                             nr,
+                             (unsigned long long) ucred.pid,
+                             (unsigned long long) ucred.uid) < 0)
+                        return -ENOMEM;
+
+                break;
+        }
+
+        default:
+                assert_not_reached("Unhandled socket type.");
+        }
+
+        *instance = r;
+        return 0;
+}
+
+static void socket_close_fds(Socket *s) {
+        SocketPort *p;
+
+        assert(s);
+
+        LIST_FOREACH(port, p, s->ports) {
+                if (p->fd < 0)
+                        continue;
+
+                unit_unwatch_fd(UNIT(s), &p->fd_watch);
+                close_nointr_nofail(p->fd);
+
+                /* One little note: we should never delete any sockets
+                 * in the file system here! After all some other
+                 * process we spawned might still have a reference of
+                 * this fd and wants to continue to use it. Therefore
+                 * we delete sockets in the file system before we
+                 * create a new one, not after we stopped using
+                 * one! */
+
+                p->fd = -1;
+        }
+}
+
+static int socket_open_fds(Socket *s) {
+        SocketPort *p;
+        int r;
+
+        assert(s);
+
+        LIST_FOREACH(port, p, s->ports) {
+
+                if (p->fd >= 0)
+                        continue;
+
+                if (p->type == SOCKET_SOCKET) {
+
+                        if ((r = socket_address_listen(
+                                             &p->address,
+                                             s->backlog,
+                                             s->bind_ipv6_only,
+                                             s->bind_to_device,
+                                             s->directory_mode,
+                                             s->socket_mode,
+                                             &p->fd)) < 0)
+                                goto rollback;
+
+                } else {
+                        struct stat st;
+                        assert(p->type == SOCKET_FIFO);
+
+                        mkdir_parents(p->path, s->directory_mode);
+
+                        if (mkfifo(p->path, s->socket_mode) < 0 && errno != EEXIST) {
+                                r = -errno;
+                                goto rollback;
+                        }
+
+                        if ((p->fd = open(p->path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
+                                r = -errno;
+                                goto rollback;
+                        }
+
+                        if (fstat(p->fd, &st) < 0) {
+                                r = -errno;
+                                goto rollback;
+                        }
+
+                        /* FIXME verify user, access mode */
+
+                        if (!S_ISFIFO(st.st_mode)) {
+                                r = -EEXIST;
+                                goto rollback;
+                        }
+                }
+        }
+
+        return 0;
+
+rollback:
+        socket_close_fds(s);
+        return r;
+}
+
+static void socket_unwatch_fds(Socket *s) {
+        SocketPort *p;
+
+        assert(s);
+
+        LIST_FOREACH(port, p, s->ports) {
+                if (p->fd < 0)
+                        continue;
+
+                unit_unwatch_fd(UNIT(s), &p->fd_watch);
+        }
+}
+
+static int socket_watch_fds(Socket *s) {
+        SocketPort *p;
+        int r;
+
+        assert(s);
+
+        LIST_FOREACH(port, p, s->ports) {
+                if (p->fd < 0)
+                        continue;
+
+                p->fd_watch.socket_accept =
+                        s->accept &&
+                        p->type == SOCKET_SOCKET &&
+                        socket_address_can_accept(&p->address);
+
+                if ((r = unit_watch_fd(UNIT(s), p->fd, EPOLLIN, &p->fd_watch)) < 0)
+                        goto fail;
+        }
+
+        return 0;
+
+fail:
+        socket_unwatch_fds(s);
+        return r;
+}
+
+static void socket_set_state(Socket *s, SocketState state) {
+        SocketState old_state;
+        assert(s);
+
+        old_state = s->state;
+        s->state = state;
+
+        if (state != SOCKET_START_PRE &&
+            state != SOCKET_START_POST &&
+            state != SOCKET_STOP_PRE &&
+            state != SOCKET_STOP_PRE_SIGTERM &&
+            state != SOCKET_STOP_PRE_SIGKILL &&
+            state != SOCKET_STOP_POST &&
+            state != SOCKET_FINAL_SIGTERM &&
+            state != SOCKET_FINAL_SIGKILL) {
+                unit_unwatch_timer(UNIT(s), &s->timer_watch);
+                socket_unwatch_control_pid(s);
+                s->control_command = NULL;
+                s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
+        }
+
+        if (state != SOCKET_LISTENING)
+                socket_unwatch_fds(s);
+
+        if (state != SOCKET_START_POST &&
+            state != SOCKET_LISTENING &&
+            state != SOCKET_RUNNING &&
+            state != SOCKET_STOP_PRE &&
+            state != SOCKET_STOP_PRE_SIGTERM &&
+            state != SOCKET_STOP_PRE_SIGKILL)
+                socket_close_fds(s);
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          s->meta.id,
+                          socket_state_to_string(old_state),
+                          socket_state_to_string(state));
+
+        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int socket_coldplug(Unit *u) {
+        Socket *s = SOCKET(u);
+        int r;
+
+        assert(s);
+        assert(s->state == SOCKET_DEAD);
+
+        if (s->deserialized_state != s->state) {
+
+                if (s->deserialized_state == SOCKET_START_PRE ||
+                    s->deserialized_state == SOCKET_START_POST ||
+                    s->deserialized_state == SOCKET_STOP_PRE ||
+                    s->deserialized_state == SOCKET_STOP_PRE_SIGTERM ||
+                    s->deserialized_state == SOCKET_STOP_PRE_SIGKILL ||
+                    s->deserialized_state == SOCKET_STOP_POST ||
+                    s->deserialized_state == SOCKET_FINAL_SIGTERM ||
+                    s->deserialized_state == SOCKET_FINAL_SIGKILL) {
+
+                        if (s->control_pid <= 0)
+                                return -EBADMSG;
+
+                        if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
+                                return r;
+
+                        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                                return r;
+                }
+
+                if (s->deserialized_state == SOCKET_START_POST ||
+                    s->deserialized_state == SOCKET_LISTENING ||
+                    s->deserialized_state == SOCKET_RUNNING ||
+                    s->deserialized_state == SOCKET_STOP_PRE ||
+                    s->deserialized_state == SOCKET_STOP_PRE_SIGTERM ||
+                    s->deserialized_state == SOCKET_STOP_PRE_SIGKILL)
+                        if ((r = socket_open_fds(s)) < 0)
+                                return r;
+
+                if (s->deserialized_state == SOCKET_LISTENING)
+                        if ((r = socket_watch_fds(s)) < 0)
+                                return r;
+
+                socket_set_state(s, s->deserialized_state);
+        }
+
+        return 0;
+}
+
+static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
+        pid_t pid;
+        int r;
+        char **argv;
+
+        assert(s);
+        assert(c);
+        assert(_pid);
+
+        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                goto fail;
+
+        if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = exec_spawn(c,
+                       argv,
+                       &s->exec_context,
+                       NULL, 0,
+                       s->meta.manager->environment,
+                       true,
+                       true,
+                       UNIT(s)->meta.manager->confirm_spawn,
+                       UNIT(s)->meta.cgroup_bondings,
+                       &pid);
+
+        strv_free(argv);
+        if (r < 0)
+                goto fail;
+
+        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
+                /* FIXME: we need to do something here */
+                goto fail;
+
+        *_pid = pid;
+
+        return 0;
+
+fail:
+        unit_unwatch_timer(UNIT(s), &s->timer_watch);
+
+        return r;
+}
+
+static void socket_enter_dead(Socket *s, bool success) {
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        socket_set_state(s, s->failure ? SOCKET_MAINTAINANCE : SOCKET_DEAD);
+}
+
+static void socket_enter_signal(Socket *s, SocketState state, bool success);
+
+static void socket_enter_stop_post(Socket *s, bool success) {
+        int r;
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        socket_unwatch_control_pid(s);
+
+        s->control_command_id = SOCKET_EXEC_STOP_POST;
+
+        if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) {
+                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+                        goto fail;
+
+                socket_set_state(s, SOCKET_STOP_POST);
+        } else
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to run stop-post executable: %s", s->meta.id, strerror(-r));
+        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+}
+
+static void socket_enter_signal(Socket *s, SocketState state, bool success) {
+        int r;
+        bool sent = false;
+
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        if (s->kill_mode != KILL_NONE) {
+                int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
+
+                if (s->kill_mode == KILL_CONTROL_GROUP) {
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH)
+                                        goto fail;
+                        } else
+                                sent = true;
+                }
+
+                if (!sent && s->control_pid > 0)
+                        if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) {
+                                r = -errno;
+                                goto fail;
+                        }
+        }
+
+        if (sent && s->control_pid > 0) {
+                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                        goto fail;
+
+                socket_set_state(s, state);
+        } else if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
+                socket_enter_stop_post(s, true);
+        else
+                socket_enter_dead(s, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r));
+
+        if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
+                socket_enter_stop_post(s, false);
+        else
+                socket_enter_dead(s, false);
+}
+
+static void socket_enter_stop_pre(Socket *s, bool success) {
+        int r;
+        assert(s);
+
+        if (!success)
+                s->failure = true;
+
+        socket_unwatch_control_pid(s);
+
+        s->control_command_id = SOCKET_EXEC_STOP_PRE;
+
+        if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) {
+                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+                        goto fail;
+
+                socket_set_state(s, SOCKET_STOP_PRE);
+        } else
+                socket_enter_stop_post(s, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to run stop-pre executable: %s", s->meta.id, strerror(-r));
+        socket_enter_stop_post(s, false);
+}
+
+static void socket_enter_listening(Socket *s) {
+        int r;
+        assert(s);
+
+        if ((r = socket_watch_fds(s)) < 0) {
+                log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r));
+                goto fail;
+        }
+
+        socket_set_state(s, SOCKET_LISTENING);
+        return;
+
+fail:
+        socket_enter_stop_pre(s, false);
+}
+
+static void socket_enter_start_post(Socket *s) {
+        int r;
+        assert(s);
+
+        if ((r = socket_open_fds(s)) < 0) {
+                log_warning("%s failed to listen on sockets: %s", s->meta.id, strerror(-r));
+                goto fail;
+        }
+
+        socket_unwatch_control_pid(s);
+
+        s->control_command_id = SOCKET_EXEC_START_POST;
+
+        if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) {
+                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) {
+                        log_warning("%s failed to run start-post executable: %s", s->meta.id, strerror(-r));
+                        goto fail;
+                }
+
+                socket_set_state(s, SOCKET_START_POST);
+        } else
+                socket_enter_listening(s);
+
+        return;
+
+fail:
+        socket_enter_stop_pre(s, false);
+}
+
+static void socket_enter_start_pre(Socket *s) {
+        int r;
+        assert(s);
+
+        socket_unwatch_control_pid(s);
+
+        s->control_command_id = SOCKET_EXEC_START_PRE;
+
+        if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) {
+                if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+                        goto fail;
+
+                socket_set_state(s, SOCKET_START_PRE);
+        } else
+                socket_enter_start_post(s);
+
+        return;
+
+fail:
+        log_warning("%s failed to run start-pre exectuable: %s", s->meta.id, strerror(-r));
+        socket_enter_dead(s, false);
+}
+
+static void socket_enter_running(Socket *s, int cfd) {
+        int r;
+
+        assert(s);
+
+        if (cfd < 0) {
+                if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0)
+                        goto fail;
+
+                socket_set_state(s, SOCKET_RUNNING);
+        } else {
+                Unit *u;
+                char *prefix, *instance, *name;
+
+                if ((r = instance_from_socket(cfd, s->n_accepted++, &instance)))
+                        goto fail;
+
+                if (!(prefix = unit_name_to_prefix(UNIT(s)->meta.id))) {
+                        free(instance);
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                name = unit_name_build(prefix, instance, ".service");
+                free(prefix);
+                free(instance);
+
+                if (!name)
+                        r = -ENOMEM;
+
+                r = manager_load_unit(UNIT(s)->meta.manager, name, NULL, &u);
+                free(name);
+
+                if (r < 0)
+                        goto fail;
+
+                if ((r = service_set_socket_fd(SERVICE(u), cfd) < 0))
+                        goto fail;
+
+                cfd = -1;
+
+                if ((r = manager_add_job(u->meta.manager, JOB_START, u, JOB_REPLACE, true, NULL)) < 0)
+                        goto fail;
+        }
+
+        return;
+
+fail:
+        log_warning("%s failed to queue socket startup job: %s", s->meta.id, strerror(-r));
+        socket_enter_stop_pre(s, false);
+
+        if (cfd >= 0)
+                close_nointr_nofail(cfd);
+}
+
+static void socket_run_next(Socket *s, bool success) {
+        int r;
+
+        assert(s);
+        assert(s->control_command);
+        assert(s->control_command->command_next);
+
+        if (!success)
+                s->failure = true;
+
+        socket_unwatch_control_pid(s);
+
+        s->control_command = s->control_command->command_next;
+
+        if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+                goto fail;
+
+        return;
+
+fail:
+        log_warning("%s failed to run spawn next executable: %s", s->meta.id, strerror(-r));
+
+        if (s->state == SOCKET_START_POST)
+                socket_enter_stop_pre(s, false);
+        else if (s->state == SOCKET_STOP_POST)
+                socket_enter_dead(s, false);
+        else
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+}
+
+static int socket_start(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+
+        /* We cannot fulfill this request right now, try again later
+         * please! */
+        if (s->state == SOCKET_STOP_PRE ||
+            s->state == SOCKET_STOP_PRE_SIGKILL ||
+            s->state == SOCKET_STOP_PRE_SIGTERM ||
+            s->state == SOCKET_STOP_POST ||
+            s->state == SOCKET_FINAL_SIGTERM ||
+            s->state == SOCKET_FINAL_SIGKILL)
+                return -EAGAIN;
+
+        if (s->state == SOCKET_START_PRE ||
+            s->state == SOCKET_START_POST)
+                return 0;
+
+        /* Cannot run this without the service being around */
+        if (s->service) {
+                if (s->service->meta.load_state != UNIT_LOADED)
+                        return -ENOENT;
+
+                /* If the service is alredy actvie we cannot start the
+                 * socket */
+                if (s->service->state != SERVICE_DEAD &&
+                    s->service->state != SERVICE_MAINTAINANCE &&
+                    s->service->state != SERVICE_AUTO_RESTART)
+                        return -EBUSY;
+        }
+
+        assert(s->state == SOCKET_DEAD || s->state == SOCKET_MAINTAINANCE);
+
+        s->failure = false;
+        socket_enter_start_pre(s);
+        return 0;
+}
+
+static int socket_stop(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+
+        /* We cannot fulfill this request right now, try again later
+         * please! */
+        if (s->state == SOCKET_START_PRE ||
+            s->state == SOCKET_START_POST)
+                return -EAGAIN;
+
+        /* Already on it */
+        if (s->state == SOCKET_STOP_PRE ||
+            s->state == SOCKET_STOP_PRE_SIGTERM ||
+            s->state == SOCKET_STOP_PRE_SIGKILL ||
+            s->state == SOCKET_STOP_POST ||
+            s->state == SOCKET_FINAL_SIGTERM ||
+            s->state == SOCKET_FINAL_SIGTERM)
+                return 0;
+
+        assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
+
+        socket_enter_stop_pre(s, true);
+        return 0;
+}
+
+static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Socket *s = SOCKET(u);
+        SocketPort *p;
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", socket_state_to_string(s->state));
+        unit_serialize_item(u, f, "failure", yes_no(s->failure));
+        unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted);
+
+        if (s->control_pid > 0)
+                unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) s->control_pid);
+
+        if (s->control_command_id >= 0)
+                unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id));
+
+        LIST_FOREACH(port, p, s->ports) {
+                int copy;
+
+                if (p->fd < 0)
+                        continue;
+
+                if ((copy = fdset_put_dup(fds, p->fd)) < 0)
+                        return copy;
+
+                if (p->type == SOCKET_SOCKET) {
+                        char *t;
+
+                        if ((r = socket_address_print(&p->address, &t)) < 0)
+                                return r;
+
+                        unit_serialize_item_format(u, f, "socket", "%i %s", copy, t);
+                        free(t);
+                } else {
+                        assert(p->type == SOCKET_FIFO);
+                        unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path);
+                }
+        }
+
+        return 0;
+}
+
+static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Socket *s = SOCKET(u);
+        int r;
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                SocketState state;
+
+                if ((state = socket_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        s->deserialized_state = state;
+        } else if (streq(key, "failure")) {
+                int b;
+
+                if ((b = parse_boolean(value)) < 0)
+                        log_debug("Failed to parse failure value %s", value);
+                else
+                        s->failure = b || s->failure;
+
+        } else if (streq(key, "n-accepted")) {
+                unsigned k;
+
+                if ((r = safe_atou(value, &k)) < 0)
+                        log_debug("Failed to parse n-accepted value %s", value);
+                else
+                        s->n_accepted += k;
+        } else if (streq(key, "control-pid")) {
+                unsigned pid;
+
+                if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        s->control_pid = (pid_t) pid;
+        } else if (streq(key, "control-command")) {
+                SocketExecCommand id;
+
+                if ((id = socket_exec_command_from_string(value)) < 0)
+                        log_debug("Failed to parse exec-command value %s", value);
+                else {
+                        s->control_command_id = id;
+                        s->control_command = s->exec_command[id];
+                }
+        } else if (streq(key, "fifo")) {
+                int fd, skip = 0;
+                SocketPort *p;
+
+                if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
+                        log_debug("Failed to parse fifo value %s", value);
+                else {
+
+                        LIST_FOREACH(port, p, s->ports)
+                                if (streq(p->path, value+skip))
+                                        break;
+
+                        if (p) {
+                                if (p->fd >= 0)
+                                        close_nointr_nofail(p->fd);
+                                p->fd = fdset_remove(fds, fd);
+                        }
+                }
+
+        } else if (streq(key, "socket")) {
+                int fd, skip = 0;
+                SocketPort *p;
+
+                if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
+                        log_debug("Failed to parse socket value %s", value);
+                else {
+
+                        LIST_FOREACH(port, p, s->ports)
+                                if (socket_address_is(&p->address, value+skip))
+                                        break;
+
+                        if (p) {
+                                if (p->fd >= 0)
+                                        close_nointr_nofail(p->fd);
+                                p->fd = fdset_remove(fds, fd);
+                        }
+                }
+
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState socket_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[SOCKET(u)->state];
+}
+
+static const char *socket_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return socket_state_to_string(SOCKET(u)->state);
+}
+
+static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
+        Socket *s = SOCKET(u);
+        int cfd = -1;
+
+        assert(s);
+        assert(fd >= 0);
+
+        log_debug("Incoming traffic on %s", u->meta.id);
+
+        if (events != EPOLLIN) {
+                log_error("Got invalid poll event on socket.");
+                goto fail;
+        }
+
+        if (w->socket_accept) {
+                for (;;) {
+
+                        if ((cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK)) < 0) {
+
+                                if (errno == EINTR)
+                                        continue;
+
+                                log_error("Failed to accept socket: %m");
+                                goto fail;
+                        }
+
+                        break;
+                }
+        }
+
+        socket_enter_running(s, cfd);
+        return;
+
+fail:
+        socket_enter_stop_pre(s, false);
+}
+
+static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+        Socket *s = SOCKET(u);
+        bool success;
+
+        assert(s);
+        assert(pid >= 0);
+
+        success = is_clean_exit(code, status);
+        s->failure = s->failure || !success;
+
+        assert(s->control_pid == pid);
+        s->control_pid = 0;
+
+        if (s->control_command)
+                exec_status_fill(&s->control_command->exec_status, pid, code, status);
+
+        log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
+
+        if (s->control_command && s->control_command->command_next && success) {
+                log_debug("%s running next command for state %s", u->meta.id, socket_state_to_string(s->state));
+                socket_run_next(s, success);
+        } else {
+                s->control_command = NULL;
+                s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
+
+                /* No further commands for this step, so let's figure
+                 * out what to do next */
+
+                log_debug("%s got final SIGCHLD for state %s", u->meta.id, socket_state_to_string(s->state));
+
+                switch (s->state) {
+
+                case SOCKET_START_PRE:
+                        if (success)
+                                socket_enter_start_post(s);
+                        else
+                                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+                        break;
+
+                case SOCKET_START_POST:
+                        if (success)
+                                socket_enter_listening(s);
+                        else
+                                socket_enter_stop_pre(s, false);
+                        break;
+
+                case SOCKET_STOP_PRE:
+                case SOCKET_STOP_PRE_SIGTERM:
+                case SOCKET_STOP_PRE_SIGKILL:
+                        socket_enter_stop_post(s, success);
+                        break;
+
+                case SOCKET_STOP_POST:
+                case SOCKET_FINAL_SIGTERM:
+                case SOCKET_FINAL_SIGKILL:
+                        socket_enter_dead(s, success);
+                        break;
+
+                default:
+                        assert_not_reached("Uh, control process died at wrong time.");
+                }
+        }
+}
+
+static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+        assert(elapsed == 1);
+        assert(w == &s->timer_watch);
+
+        switch (s->state) {
+
+        case SOCKET_START_PRE:
+                log_warning("%s starting timed out. Terminating.", u->meta.id);
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+
+        case SOCKET_START_POST:
+                log_warning("%s starting timed out. Stopping.", u->meta.id);
+                socket_enter_stop_pre(s, false);
+                break;
+
+        case SOCKET_STOP_PRE:
+                log_warning("%s stopping timed out. Terminating.", u->meta.id);
+                socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, false);
+                break;
+
+        case SOCKET_STOP_PRE_SIGTERM:
+                log_warning("%s stopping timed out. Killing.", u->meta.id);
+                socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false);
+                break;
+
+        case SOCKET_STOP_PRE_SIGKILL:
+                log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id);
+                socket_enter_stop_post(s, false);
+                break;
+
+        case SOCKET_STOP_POST:
+                log_warning("%s stopping timed out (2). Terminating.", u->meta.id);
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+                break;
+
+        case SOCKET_FINAL_SIGTERM:
+                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
+                socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false);
+                break;
+
+        case SOCKET_FINAL_SIGKILL:
+                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", u->meta.id);
+                socket_enter_dead(s, false);
+                break;
+
+        default:
+                assert_not_reached("Timeout at wrong time.");
+        }
+}
+
+int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
+        int *rfds;
+        unsigned rn_fds, k;
+        SocketPort *p;
+
+        assert(s);
+        assert(fds);
+        assert(n_fds);
+
+        /* Called from the service code for requesting our fds */
+
+        rn_fds = 0;
+        LIST_FOREACH(port, p, s->ports)
+                if (p->fd >= 0)
+                        rn_fds++;
+
+        if (!(rfds = new(int, rn_fds)) < 0)
+                return -ENOMEM;
+
+        k = 0;
+        LIST_FOREACH(port, p, s->ports)
+                if (p->fd >= 0)
+                        rfds[k++] = p->fd;
+
+        assert(k == rn_fds);
+
+        *fds = rfds;
+        *n_fds = rn_fds;
+
+        return 0;
+}
+
+void socket_notify_service_dead(Socket *s) {
+        assert(s);
+
+        /* The service is dead. Dang. */
+
+        if (s->state == SOCKET_RUNNING) {
+                log_debug("%s got notified about service death.", s->meta.id);
+                socket_enter_listening(s);
+        }
+}
+
+static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
+        [SOCKET_DEAD] = "dead",
+        [SOCKET_START_PRE] = "start-pre",
+        [SOCKET_START_POST] = "start-post",
+        [SOCKET_LISTENING] = "listening",
+        [SOCKET_RUNNING] = "running",
+        [SOCKET_STOP_PRE] = "stop-pre",
+        [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
+        [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
+        [SOCKET_STOP_POST] = "stop-post",
+        [SOCKET_FINAL_SIGTERM] = "final-sigterm",
+        [SOCKET_FINAL_SIGKILL] = "final-sigkill",
+        [SOCKET_MAINTAINANCE] = "maintainance"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
+
+static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
+        [SOCKET_EXEC_START_PRE] = "StartPre",
+        [SOCKET_EXEC_START_POST] = "StartPost",
+        [SOCKET_EXEC_STOP_PRE] = "StopPre",
+        [SOCKET_EXEC_STOP_POST] = "StopPost"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
+
+const UnitVTable socket_vtable = {
+        .suffix = ".socket",
+
+        .init = socket_init,
+        .done = socket_done,
+        .load = socket_load,
+
+        .coldplug = socket_coldplug,
+
+        .dump = socket_dump,
+
+        .start = socket_start,
+        .stop = socket_stop,
+
+        .serialize = socket_serialize,
+        .deserialize_item = socket_deserialize_item,
+
+        .active_state = socket_active_state,
+        .sub_state_to_string = socket_sub_state_to_string,
+
+        .fd_event = socket_fd_event,
+        .sigchld_event = socket_sigchld_event,
+        .timer_event = socket_timer_event,
+
+        .bus_message_handler = bus_socket_message_handler
+};
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..43d28d7
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,132 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foosockethfoo
+#define foosockethfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Socket Socket;
+
+#include "manager.h"
+#include "unit.h"
+#include "socket-util.h"
+#include "mount.h"
+
+typedef enum SocketState {
+        SOCKET_DEAD,
+        SOCKET_START_PRE,
+        SOCKET_START_POST,
+        SOCKET_LISTENING,
+        SOCKET_RUNNING,
+        SOCKET_STOP_PRE,
+        SOCKET_STOP_PRE_SIGTERM,
+        SOCKET_STOP_PRE_SIGKILL,
+        SOCKET_STOP_POST,
+        SOCKET_FINAL_SIGTERM,
+        SOCKET_FINAL_SIGKILL,
+        SOCKET_MAINTAINANCE,
+        _SOCKET_STATE_MAX,
+        _SOCKET_STATE_INVALID = -1
+} SocketState;
+
+typedef enum SocketExecCommand {
+        SOCKET_EXEC_START_PRE,
+        SOCKET_EXEC_START_POST,
+        SOCKET_EXEC_STOP_PRE,
+        SOCKET_EXEC_STOP_POST,
+        _SOCKET_EXEC_COMMAND_MAX,
+        _SOCKET_EXEC_COMMAND_INVALID = -1
+} SocketExecCommand;
+
+typedef enum SocketType {
+        SOCKET_SOCKET,
+        SOCKET_FIFO,
+        _SOCKET_FIFO_MAX,
+        _SOCKET_FIFO_INVALID = -1
+} SocketType;
+
+typedef struct SocketPort SocketPort;
+
+struct SocketPort {
+        SocketType type;
+        int fd;
+
+        SocketAddress address;
+        char *path;
+
+        Watch fd_watch;
+
+        LIST_FIELDS(SocketPort, port);
+};
+
+struct Socket {
+        Meta meta;
+
+        LIST_HEAD(SocketPort, ports);
+
+        /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
+        bool bind_ipv6_only;
+        unsigned backlog;
+
+        usec_t timeout_usec;
+
+        ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        Service *service;
+
+        SocketState state, deserialized_state;
+
+        KillMode kill_mode;
+
+        ExecCommand* control_command;
+        SocketExecCommand control_command_id;
+        pid_t control_pid;
+
+        char *bind_to_device;
+        mode_t directory_mode;
+        mode_t socket_mode;
+
+        bool accept;
+        unsigned n_accepted;
+
+        bool failure;
+        Watch timer_watch;
+};
+
+/* Called from the service code when collecting fds */
+int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
+
+/* Called from the service when it shut down */
+void socket_notify_service_dead(Socket *s);
+
+/* Called from the mount code figure out if a mount is a dependency of
+ * any of the sockets of this socket */
+int socket_add_one_mount_link(Socket *s, Mount *m);
+
+extern const UnitVTable socket_vtable;
+
+const char* socket_state_to_string(SocketState i);
+SocketState socket_state_from_string(const char *s);
+
+const char* socket_exec_command_to_string(SocketExecCommand i);
+SocketExecCommand socket_exec_command_from_string(const char *s);
+
+#endif
diff --git a/src/specifier.c b/src/specifier.c
new file mode 100644
index 0000000..d8472e9
--- /dev/null
+++ b/src/specifier.c
@@ -0,0 +1,110 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "macro.h"
+#include "util.h"
+#include "specifier.h"
+
+/*
+ * Generic infrastructure for replacing %x style specifiers in
+ * strings. Will call a callback for each replacement.
+ *
+ */
+
+char *specifier_printf(const char *text, const Specifier table[], void *userdata) {
+        char *r, *t;
+        const char *f;
+        bool percent = false;
+        size_t l;
+
+        assert(text);
+        assert(table);
+
+        l = strlen(text);
+        if (!(r = new(char, l+1)))
+                return NULL;
+
+        t = r;
+
+        for (f = text; *f; f++, l--) {
+
+                if (percent) {
+                        if (*f == '%')
+                                *(t++) = '%';
+                        else {
+                                const Specifier *i;
+
+                                for (i = table; i->specifier; i++)
+                                        if (i->specifier == *f)
+                                                break;
+
+                                if (i->lookup) {
+                                        char *n, *w;
+                                        size_t k, j;
+
+                                        if (!(w = i->lookup(i->specifier, i->data, userdata))) {
+                                                free(r);
+                                                return NULL;
+                                        }
+
+                                        j = t - r;
+                                        k = strlen(w);
+
+                                        if (!(n = new(char, j + k + l + 1))) {
+                                                free(r);
+                                                free(w);
+                                                return NULL;
+                                        }
+
+                                        memcpy(n, r, j);
+                                        memcpy(n + j, w, k);
+
+                                        free(r);
+                                        free(w);
+
+                                        r = n;
+                                        t = n + j + k;
+                                } else {
+                                        *(t++) = '%';
+                                        *(t++) = *f;
+                                }
+                        }
+
+                        percent = false;
+                } else if (*f == '%')
+                        percent = true;
+                else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+        return r;
+}
+
+/* Generic handler for simple string replacements */
+
+char* specifier_string(char specifier, void *data, void *userdata) {
+        assert(data);
+
+        return strdup(strempty(data));
+}
diff --git a/src/specifier.h b/src/specifier.h
new file mode 100644
index 0000000..4b3b94c
--- /dev/null
+++ b/src/specifier.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foospecifierhfoo
+#define foospecifierhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata);
+
+typedef struct Specifier {
+        const char specifier;
+        const SpecifierCallback lookup;
+        void *data;
+} Specifier;
+
+char *specifier_printf(const char *text, const Specifier table[], void *userdata);
+
+char* specifier_string(char specifier, void *data, void *userdata);
+
+#endif
diff --git a/src/strv.c b/src/strv.c
new file mode 100644
index 0000000..a749096
--- /dev/null
+++ b/src/strv.c
@@ -0,0 +1,503 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "strv.h"
+
+char *strv_find(char **l, const char *name) {
+        char **i;
+
+        assert(l);
+        assert(name);
+
+        STRV_FOREACH(i, l)
+                if (streq(*i, name))
+                        return *i;
+
+        return NULL;
+}
+
+void strv_free(char **l) {
+        char **k;
+
+        if (!l)
+                return;
+
+        for (k = l; *k; k++)
+                free(*k);
+
+        free(l);
+}
+
+char **strv_copy(char **l) {
+        char **r, **k;
+
+        if (!(r = new(char*, strv_length(l)+1)))
+                return NULL;
+
+        for (k = r; *l; k++, l++)
+                if (!(*k = strdup(*l)))
+                        goto fail;
+
+        *k = NULL;
+        return r;
+
+fail:
+        for (k--, l--; k >= r; k--, l--)
+                free(*k);
+
+        return NULL;
+}
+
+unsigned strv_length(char **l) {
+        unsigned n = 0;
+
+        if (!l)
+                return 0;
+
+        for (; *l; l++)
+                n++;
+
+        return n;
+}
+
+char **strv_new_ap(const char *x, va_list ap) {
+        const char *s;
+        char **a;
+        unsigned n = 0, i = 0;
+        va_list aq;
+
+
+        if (x) {
+                n = 1;
+
+                va_copy(aq, ap);
+                while (va_arg(aq, const char*))
+                        n++;
+                va_end(aq);
+        }
+
+        if (!(a = new(char*, n+1)))
+                return NULL;
+
+        if (x) {
+                if (!(a[i] = strdup(x))) {
+                        free(a);
+                        return NULL;
+                }
+
+                i++;
+
+                while ((s = va_arg(ap, const char*))) {
+                        if (!(a[i] = strdup(s)))
+                                goto fail;
+
+                        i++;
+                }
+        }
+
+        a[i] = NULL;
+
+        return a;
+
+fail:
+
+        for (; i > 0; i--)
+                if (a[i-1])
+                        free(a[i-1]);
+
+        free(a);
+
+        return NULL;
+}
+
+char **strv_new(const char *x, ...) {
+        char **r;
+        va_list ap;
+
+        va_start(ap, x);
+        r = strv_new_ap(x, ap);
+        va_end(ap);
+
+        return r;
+}
+
+char **strv_merge(char **a, char **b) {
+        char **r, **k;
+
+        if (!a)
+                return strv_copy(b);
+
+        if (!b)
+                return strv_copy(a);
+
+        if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
+                return NULL;
+
+        for (k = r; *a; k++, a++)
+                if (!(*k = strdup(*a)))
+                        goto fail;
+        for (; *b; k++, b++)
+                if (!(*k = strdup(*b)))
+                        goto fail;
+
+        *k = NULL;
+        return r;
+
+fail:
+        for (k--; k >= r; k--)
+                free(*k);
+
+        free(r);
+
+        return NULL;
+}
+
+char **strv_merge_concat(char **a, char **b, const char *suffix) {
+        char **r, **k;
+
+        /* Like strv_merge(), but appends suffix to all strings in b, before adding */
+
+        if (!b)
+                return strv_copy(a);
+
+        if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
+                return NULL;
+
+        for (k = r; *a; k++, a++)
+                if (!(*k = strdup(*a)))
+                        goto fail;
+        for (; *b; k++, b++)
+                if (!(*k = strappend(*b, suffix)))
+                        goto fail;
+
+        *k = NULL;
+        return r;
+
+fail:
+        for (k--; k >= r; k--)
+                free(*k);
+
+        free(r);
+
+        return NULL;
+
+}
+
+char **strv_split(const char *s, const char *separator) {
+        char *state;
+        char *w;
+        size_t l;
+        unsigned n, i;
+        char **r;
+
+        assert(s);
+
+        n = 0;
+        FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
+                n++;
+
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        i = 0;
+        FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
+                if (!(r[i++] = strndup(w, l))) {
+                        strv_free(r);
+                        return NULL;
+                }
+
+        r[i] = NULL;
+        return r;
+}
+
+char **strv_split_quoted(const char *s) {
+        char *state;
+        char *w;
+        size_t l;
+        unsigned n, i;
+        char **r;
+
+        assert(s);
+
+        n = 0;
+        FOREACH_WORD_QUOTED(w, l, s, state)
+                n++;
+
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        i = 0;
+        FOREACH_WORD_QUOTED(w, l, s, state)
+                if (!(r[i++] = strndup(w, l))) {
+                        strv_free(r);
+                        return NULL;
+                }
+
+        r[i] = NULL;
+        return r;
+}
+
+char *strv_join(char **l, const char *separator) {
+        char *r, *e;
+        char **s;
+        size_t n, k;
+
+        if (!separator)
+                separator = " ";
+
+        k = strlen(separator);
+
+        n = 0;
+        STRV_FOREACH(s, l) {
+                if (n != 0)
+                        n += k;
+                n += strlen(*s);
+        }
+
+        if (!(r = new(char, n+1)))
+                return NULL;
+
+        e = r;
+        STRV_FOREACH(s, l) {
+                if (e != r)
+                        e = stpcpy(e, separator);
+
+                e = stpcpy(e, *s);
+        }
+
+        *e = 0;
+
+        return r;
+}
+
+char **strv_append(char **l, const char *s) {
+        char **r, **k;
+
+        if (!l)
+                return strv_new(s, NULL);
+
+        if (!s)
+                return strv_copy(l);
+
+        if (!(r = new(char*, strv_length(l)+2)))
+                return NULL;
+
+        for (k = r; *l; k++, l++)
+                if (!(*k = strdup(*l)))
+                        goto fail;
+
+        if (!(*(k++) = strdup(s)))
+                goto fail;
+
+        *k = NULL;
+        return r;
+
+fail:
+        for (k--; k >= r; k--)
+                free(*k);
+
+        free(r);
+
+        return NULL;
+}
+
+char **strv_uniq(char **l) {
+        char **i;
+
+        /* Drops duplicate entries. The first identical string will be
+         * kept, the others dropped */
+
+        STRV_FOREACH(i, l)
+                strv_remove(i+1, *i);
+
+        return l;
+}
+
+char **strv_remove(char **l, const char *s) {
+        char **f, **t;
+
+        if (!l)
+                return NULL;
+
+        /* Drops every occurence of s in the string list */
+
+        for (f = t = l; *f; f++) {
+
+                if (streq(*f, s)) {
+                        free(*f);
+                        continue;
+                }
+
+                *(t++) = *f;
+        }
+
+        *t = NULL;
+        return l;
+}
+
+static int env_append(char **r, char ***k, char **a) {
+        assert(r);
+        assert(k);
+        assert(a);
+
+        /* Add the entries of a to *k unless they already exist in *r
+         * in which case they are overriden instead. This assumes
+         * there is enough space in the r */
+
+        for (; *a; a++) {
+                char **j;
+                size_t n = strcspn(*a, "=") + 1;
+
+                for (j = r; j < *k; j++)
+                        if (strncmp(*j, *a, n) == 0)
+                                break;
+
+                if (j >= *k)
+                        (*k)++;
+                else
+                        free(*j);
+
+                if (!(*j = strdup(*a)))
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
+char **strv_env_merge(char **x, ...) {
+        size_t n = 0;
+        char **l, **k, **r;
+        va_list ap;
+
+        /* Merges an arbitrary number of environment sets */
+
+        if (x) {
+                n += strv_length(x);
+
+                va_start(ap, x);
+                while ((l = va_arg(ap, char**)))
+                        n += strv_length(l);
+                va_end(ap);
+        }
+
+
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        k = r;
+
+        if (x) {
+                if (env_append(r, &k, x) < 0)
+                        goto fail;
+
+                va_start(ap, x);
+                while ((l = va_arg(ap, char**)))
+                        if (env_append(r, &k, l) < 0)
+                                goto fail;
+                va_end(ap);
+        }
+
+        *k = NULL;
+
+        return r;
+
+fail:
+        for (k--; k >= r; k--)
+                free(*k);
+
+        free(r);
+
+        return NULL;
+}
+
+static bool env_match(const char *t, const char *pattern) {
+        assert(t);
+        assert(pattern);
+
+        /* pattern a matches string a
+         *         a matches a=
+         *         a matches a=b
+         *         a= matches a=
+         *         a=b matches a=b
+         *         a= does not match a
+         *         a=b does not match a=
+         *         a=b does not match a
+         *         a=b does not match a=c */
+
+        if (streq(t, pattern))
+                return true;
+
+        if (!strchr(pattern, '=')) {
+                size_t l = strlen(pattern);
+
+                return strncmp(t, pattern, l) == 0 && t[l] == '=';
+        }
+
+        return false;
+}
+
+char **strv_env_delete(char **x, ...) {
+        size_t n = 0, i = 0;
+        char **l, **k, **r, **j;
+        va_list ap;
+
+        /* Deletes every entry fromx that is mentioned in the other
+         * string lists */
+
+        n = strv_length(x);
+
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        STRV_FOREACH(k, x) {
+                va_start(ap, x);
+
+                while ((l = va_arg(ap, char**)))
+                        STRV_FOREACH(j, l)
+                                if (env_match(*k, *j))
+                                        goto delete;
+
+                va_end(ap);
+
+                if (!(r[i++] = strdup(*k))) {
+                        strv_free(r);
+                        return NULL;
+                }
+
+                continue;
+
+        delete:
+                va_end(ap);
+        }
+
+        r[i] = NULL;
+
+        assert(i <= n);
+
+        return r;
+}
diff --git a/src/strv.h b/src/strv.h
new file mode 100644
index 0000000..f0be83d
--- /dev/null
+++ b/src/strv.h
@@ -0,0 +1,65 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foostrvhfoo
+#define foostrvhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "macro.h"
+
+char *strv_find(char **l, const char *name);
+void strv_free(char **l);
+char **strv_copy(char **l) _malloc;
+unsigned strv_length(char **l);
+
+char **strv_merge(char **a, char **b);
+char **strv_merge_concat(char **a, char **b, const char *suffix);
+char **strv_append(char **l, const char *s);
+
+char **strv_remove(char **l, const char *s);
+char **strv_uniq(char **l);
+
+#define strv_contains(l, s) (!!strv_find((l), (s)))
+
+char **strv_new(const char *x, ...) _sentinel _malloc;
+char **strv_new_ap(const char *x, va_list ap) _malloc;
+
+static inline bool strv_isempty(char **l) {
+        return !l || !*l;
+}
+
+char **strv_split(const char *s, const char *separator) _malloc;
+char **strv_split_quoted(const char *s) _malloc;
+
+char *strv_join(char **l, const char *separator) _malloc;
+
+char **strv_env_merge(char **x, ...) _sentinel;
+char **strv_env_delete(char **x, ...) _sentinel;
+
+#define STRV_FOREACH(s, l)                      \
+        for ((s) = (l); (s) && *(s); (s)++)
+
+#define STRV_FOREACH_BACKWARDS(s, l)            \
+        for (; (l) && ((s) >= (l)); (s)--)
+
+#endif
diff --git a/src/swap.c b/src/swap.c
new file mode 100644
index 0000000..bd49e1e
--- /dev/null
+++ b/src/swap.c
@@ -0,0 +1,578 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/swap.h>
+
+#include "unit.h"
+#include "swap.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "unit-name.h"
+#include "dbus-swap.h"
+
+static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
+        [SWAP_DEAD] = UNIT_INACTIVE,
+        [SWAP_ACTIVE] = UNIT_ACTIVE,
+        [SWAP_MAINTAINANCE] = UNIT_INACTIVE
+};
+
+static void swap_init(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(s->meta.load_state == UNIT_STUB);
+
+        s->parameters_etc_fstab.priority = s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
+}
+
+static void swap_done(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        free(s->what);
+        free(s->parameters_etc_fstab.what);
+        free(s->parameters_proc_swaps.what);
+        free(s->parameters_fragment.what);
+}
+
+int swap_add_one_mount_link(Swap *s, Mount *m) {
+         int r;
+
+        assert(s);
+        assert(m);
+
+        if (s->meta.load_state != UNIT_LOADED ||
+            m->meta.load_state != UNIT_LOADED)
+                return 0;
+
+        if (is_device_path(s->what))
+                return 0;
+
+        if (!path_startswith(s->what, m->where))
+                return 0;
+
+        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
+                return r;
+
+        if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
+                return r;
+
+        return 0;
+}
+
+static int swap_add_mount_links(Swap *s) {
+        Meta *other;
+        int r;
+
+        assert(s);
+
+        LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_MOUNT])
+                if ((r = swap_add_one_mount_link(s, (Mount*) other)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int swap_add_target_links(Swap *s) {
+        Unit *tu;
+        SwapParameters *p;
+        int r;
+
+        assert(s);
+
+        if (s->from_fragment)
+                p = &s->parameters_fragment;
+        else if (s->from_etc_fstab)
+                p = &s->parameters_etc_fstab;
+        else
+                return 0;
+
+        if ((r = manager_load_unit(s->meta.manager, SPECIAL_SWAP_TARGET, NULL, &tu)) < 0)
+                return r;
+
+        if (!p->noauto && p->handle)
+                if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(s), true)) < 0)
+                        return r;
+
+        return unit_add_dependency(UNIT(s), UNIT_BEFORE, tu, true);
+}
+
+static int swap_verify(Swap *s) {
+        bool b;
+        char *e;
+
+        if (UNIT(s)->meta.load_state != UNIT_LOADED)
+                  return 0;
+
+        if (!(e = unit_name_from_path(s->what, ".swap")))
+                  return -ENOMEM;
+
+        b = unit_has_name(UNIT(s), e);
+        free(e);
+
+        if (!b) {
+                log_error("%s: Value of \"What\" and unit name do not match, not loading.\n", UNIT(s)->meta.id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int swap_load(Unit *u) {
+        int r;
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(u->meta.load_state == UNIT_STUB);
+
+        /* Load a .swap file */
+        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
+                return r;
+
+        if (u->meta.load_state == UNIT_LOADED) {
+
+                if (s->meta.fragment_path)
+                        s->from_fragment = true;
+
+                if (!s->what) {
+                        if (s->parameters_fragment.what)
+                                s->what = strdup(s->parameters_fragment.what);
+                        else if (s->parameters_etc_fstab.what)
+                                s->what = strdup(s->parameters_etc_fstab.what);
+                        else if (s->parameters_proc_swaps.what)
+                                s->what = strdup(s->parameters_proc_swaps.what);
+                        else
+                                s->what = unit_name_to_path(u->meta.id);
+
+                        if (!s->what)
+                                return -ENOMEM;
+                }
+
+                path_kill_slashes(s->what);
+
+                if (!s->meta.description)
+                        if ((r = unit_set_description(u, s->what)) < 0)
+                                return r;
+
+                if ((r = unit_add_node_link(u, s->what,
+                                            (u->meta.manager->running_as == MANAGER_INIT ||
+                                             u->meta.manager->running_as == MANAGER_SYSTEM))) < 0)
+                        return r;
+
+                if ((r = swap_add_mount_links(s)) < 0)
+                        return r;
+
+                if ((r = swap_add_target_links(s)) < 0)
+                        return r;
+        }
+
+        return swap_verify(s);
+}
+
+static int swap_find(Manager *m, const char *what, Unit **_u) {
+        Unit *u;
+        char *e;
+
+        assert(m);
+        assert(what);
+        assert(_u);
+
+        /* /proc/swaps and /etc/fstab might refer to this device by
+         * different names (e.g. one by uuid, the other by the kernel
+         * name), we hence need to look for all aliases we are aware
+         * of for this device */
+
+        if (!(e = unit_name_from_path(what, ".device")))
+                return -ENOMEM;
+
+        u = manager_get_unit(m, e);
+        free(e);
+
+        if (u) {
+                Iterator i;
+                const char *d;
+
+                SET_FOREACH(d, u->meta.names, i) {
+                        Unit *k;
+
+                        if (!(e = unit_name_change_suffix(d, ".swap")))
+                                return -ENOMEM;
+
+                        k = manager_get_unit(m, e);
+                        free(e);
+
+                        if (k) {
+                                *_u = k;
+                                return 0;
+                        }
+                }
+        }
+
+        *_u = NULL;
+        return 0;
+}
+
+int swap_add_one(
+                Manager *m,
+                const char *what,
+                int priority,
+                bool noauto,
+                bool handle,
+                bool from_proc_swaps) {
+        Unit *u = NULL;
+        char *e = NULL, *w = NULL;
+        bool delete;
+        int r;
+        SwapParameters *p;
+
+        assert(m);
+        assert(what);
+
+        if (!(e = unit_name_from_path(what, ".swap")))
+                return -ENOMEM;
+
+        if (!(u = manager_get_unit(m, e)))
+                if ((r = swap_find(m, what, &u)) < 0)
+                        goto fail;
+
+        if (!u) {
+                delete = true;
+
+                if (!(u = unit_new(m))) {
+                        free(e);
+                        return -ENOMEM;
+                }
+        } else
+                delete = false;
+
+        if ((r = unit_add_name(u, e)) < 0)
+                goto fail;
+
+        if (!(w = strdup(what))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (from_proc_swaps) {
+                p = &SWAP(u)->parameters_proc_swaps;
+                SWAP(u)->from_proc_swaps = true;
+        } else {
+                p = &SWAP(u)->parameters_etc_fstab;
+                SWAP(u)->from_etc_fstab = true;
+        }
+
+        free(p->what);
+        p->what = w;
+
+        p->priority = priority;
+        p->noauto = noauto;
+        p->handle = handle;
+
+        if (delete)
+                unit_add_to_load_queue(u);
+
+        unit_add_to_dbus_queue(u);
+
+        free(e);
+
+        return 0;
+
+fail:
+        free(w);
+        free(e);
+
+        if (delete && u)
+                unit_free(u);
+
+        return r;
+}
+
+static void swap_set_state(Swap *s, SwapState state) {
+        SwapState old_state;
+        assert(s);
+
+        old_state = s->state;
+        s->state = state;
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(s)->meta.id,
+                          swap_state_to_string(old_state),
+                          swap_state_to_string(state));
+
+        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int swap_coldplug(Unit *u) {
+        Swap *s = SWAP(u);
+        SwapState new_state = SWAP_DEAD;
+
+        assert(s);
+        assert(s->state == SWAP_DEAD);
+
+        if (s->deserialized_state != s->state)
+                new_state = s->deserialized_state;
+        else if (s->from_proc_swaps)
+                new_state = SWAP_ACTIVE;
+
+        if (new_state != s->state)
+                swap_set_state(s, new_state);
+
+        return 0;
+}
+
+static void swap_dump(Unit *u, FILE *f, const char *prefix) {
+        Swap *s = SWAP(u);
+        SwapParameters *p;
+
+        assert(s);
+        assert(f);
+
+        if (s->from_proc_swaps)
+                p = &s->parameters_proc_swaps;
+        else if (s->from_fragment)
+                p = &s->parameters_fragment;
+        else
+                p = &s->parameters_etc_fstab;
+
+        fprintf(f,
+                "%sSwap State: %s\n"
+                "%sWhat: %s\n"
+                "%sPriority: %i\n"
+                "%sNoAuto: %s\n"
+                "%sHandle: %s\n"
+                "%sFrom /etc/fstab: %s\n"
+                "%sFrom /proc/swaps: %s\n"
+                "%sFrom fragment: %s\n",
+                prefix, swap_state_to_string(s->state),
+                prefix, s->what,
+                prefix, p->priority,
+                prefix, yes_no(p->noauto),
+                prefix, yes_no(p->handle),
+                prefix, yes_no(s->from_etc_fstab),
+                prefix, yes_no(s->from_proc_swaps),
+                prefix, yes_no(s->from_fragment));
+}
+
+static void swap_enter_dead(Swap *s, bool success) {
+        assert(s);
+
+        swap_set_state(s, success ? SWAP_MAINTAINANCE : SWAP_DEAD);
+}
+
+static int swap_start(Unit *u) {
+        Swap *s = SWAP(u);
+        int priority = -1;
+        int r;
+
+        assert(s);
+        assert(s->state == SWAP_DEAD || s->state == SWAP_MAINTAINANCE);
+
+        if (s->from_fragment)
+                priority = s->parameters_fragment.priority;
+        else if (s->from_etc_fstab)
+                priority = s->parameters_etc_fstab.priority;
+
+        r = swapon(s->what, (priority << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK);
+
+        if (r < 0 && errno != EBUSY) {
+                r = -errno;
+                swap_enter_dead(s, false);
+                return r;
+        }
+
+        swap_set_state(s, SWAP_ACTIVE);
+        return 0;
+}
+
+static int swap_stop(Unit *u) {
+        Swap *s = SWAP(u);
+        int r;
+
+        assert(s);
+
+        assert(s->state == SWAP_ACTIVE);
+
+        r = swapoff(s->what);
+        swap_enter_dead(s, r >= 0 || errno == EINVAL);
+
+        return 0;
+}
+
+static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", swap_state_to_string(s->state));
+
+        return 0;
+}
+
+static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                SwapState state;
+
+                if ((state = swap_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        s->deserialized_state = state;
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState swap_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[SWAP(u)->state];
+}
+
+static const char *swap_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return swap_state_to_string(SWAP(u)->state);
+}
+
+static bool swap_check_gc(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        return s->from_etc_fstab || s->from_proc_swaps;
+}
+
+static int swap_load_proc_swaps(Manager *m) {
+        rewind(m->proc_swaps);
+
+        (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
+
+        for (;;) {
+                char *dev = NULL, *d;
+                int prio = 0, k;
+
+                if ((k = fscanf(m->proc_swaps,
+                                "%ms " /* device/file */
+                                "%*s " /* type of swap */
+                                "%*s " /* swap size */
+                                "%*s " /* used */
+                                "%i\n", /* priority */
+                                &dev, &prio)) != 2) {
+
+                        if (k == EOF)
+                                break;
+
+                        free(dev);
+                        return -EBADMSG;
+                }
+
+                d = cunescape(dev);
+                free(dev);
+
+                if (!d)
+                        return -ENOMEM;
+
+                k = swap_add_one(m, d, prio, false, false, true);
+                free(d);
+
+                if (k < 0)
+                        return k;
+        }
+
+        return 0;
+}
+
+static void swap_shutdown(Manager *m) {
+        assert(m);
+
+        if (m->proc_swaps) {
+                fclose(m->proc_swaps);
+                m->proc_swaps = NULL;
+        }
+}
+
+static const char* const swap_state_table[_SWAP_STATE_MAX] = {
+        [SWAP_DEAD] = "dead",
+        [SWAP_ACTIVE] = "active",
+        [SWAP_MAINTAINANCE] = "maintainance"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
+
+static int swap_enumerate(Manager *m) {
+        int r;
+        assert(m);
+
+        if (!m->proc_swaps)
+                if (!(m->proc_swaps = fopen("/proc/swaps", "re")))
+                        return -errno;
+
+        if ((r = swap_load_proc_swaps(m)) < 0)
+                swap_shutdown(m);
+
+        return r;
+}
+
+const UnitVTable swap_vtable = {
+        .suffix = ".swap",
+
+        .no_instances = true,
+        .no_isolate = true,
+
+        .init = swap_init,
+        .load = swap_load,
+        .done = swap_done,
+
+        .coldplug = swap_coldplug,
+
+        .dump = swap_dump,
+
+        .start = swap_start,
+        .stop = swap_stop,
+
+        .serialize = swap_serialize,
+        .deserialize_item = swap_deserialize_item,
+
+        .active_state = swap_active_state,
+        .sub_state_to_string = swap_sub_state_to_string,
+
+        .check_gc = swap_check_gc,
+
+        .bus_message_handler = bus_swap_message_handler,
+
+        .enumerate = swap_enumerate,
+        .shutdown = swap_shutdown
+};
diff --git a/src/swap.h b/src/swap.h
new file mode 100644
index 0000000..f54a9ee
--- /dev/null
+++ b/src/swap.h
@@ -0,0 +1,71 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooswaphfoo
+#define fooswaphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2010 Maarten Lankhorst
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Swap Swap;
+
+#include "unit.h"
+
+typedef enum SwapState {
+        SWAP_DEAD,
+        SWAP_ACTIVE,
+        SWAP_MAINTAINANCE,
+        _SWAP_STATE_MAX,
+        _SWAP_STATE_INVALID = -1
+} SwapState;
+
+typedef struct SwapParameters {
+        char *what;
+        int priority;
+        bool noauto:1;
+        bool handle:1;
+} SwapParameters;
+
+struct Swap {
+        Meta meta;
+
+        SwapParameters parameters_etc_fstab;
+        SwapParameters parameters_proc_swaps;
+        SwapParameters parameters_fragment;
+
+        char *what;
+
+        bool from_etc_fstab:1;
+        bool from_proc_swaps:1;
+        bool from_fragment:1;
+
+        SwapState state, deserialized_state;
+};
+
+extern const UnitVTable swap_vtable;
+
+int swap_add_one(Manager *m, const char *what, int prio, bool no_auto, bool handle, bool from_proc_swap);
+
+int swap_add_one_mount_link(Swap *s, Mount *m);
+
+const char* swap_state_to_string(SwapState i);
+SwapState swap_state_from_string(const char *s);
+
+
+#endif
diff --git a/src/systemadm.vala b/src/systemadm.vala
new file mode 100644
index 0000000..bd0062a
--- /dev/null
+++ b/src/systemadm.vala
@@ -0,0 +1,956 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+using Gtk;
+using GLib;
+using DBus;
+using Pango;
+
+static bool session = false;
+
+public class LeftLabel : Label {
+        public LeftLabel(string? text = null) {
+                if (text != null)
+                        set_markup("<b>%s</b>".printf(text));
+                set_alignment(0, 0);
+                set_padding(6, 0);
+        }
+}
+
+public class RightLabel : Label {
+        public RightLabel(string? text = null) {
+                set_text_or_na(text);
+                set_alignment(0, 0);
+                set_ellipsize(EllipsizeMode.START);
+                set_selectable(true);
+        }
+
+        public void set_text_or_na(string? text = null) {
+                if (text == null || text == "")
+                        set_markup("<i>n/a</i>");
+                else
+                        set_text(text);
+        }
+
+        public void set_markup_or_na(string? text = null) {
+                if (text == null || text == "")
+                        set_markup("<i>n/a</i>");
+                else
+                        set_markup(text);
+        }
+}
+
+public class MainWindow : Window {
+
+        private string? current_unit_id;
+        private uint32 current_job_id;
+
+        private TreeView unit_view;
+        private TreeView job_view;
+
+        private ListStore unit_model;
+        private ListStore job_model;
+
+        private Button start_button;
+        private Button stop_button;
+        private Button restart_button;
+        private Button reload_button;
+        private Button cancel_button;
+
+        private Entry unit_load_entry;
+        private Button unit_load_button;
+
+        private Button server_snapshot_button;
+        private Button server_reload_button;
+
+        private Connection bus;
+        private Manager manager;
+
+        private RightLabel unit_id_label;
+        private RightLabel unit_aliases_label;
+        private RightLabel unit_dependency_label;
+        private RightLabel unit_description_label;
+        private RightLabel unit_load_state_label;
+        private RightLabel unit_active_state_label;
+        private RightLabel unit_sub_state_label;
+        private RightLabel unit_fragment_path_label;
+        private RightLabel unit_active_enter_timestamp_label;
+        private RightLabel unit_active_exit_timestamp_label;
+        private RightLabel unit_can_start_label;
+        private RightLabel unit_can_reload_label;
+        private RightLabel unit_cgroup_label;
+
+        private RightLabel job_id_label;
+        private RightLabel job_state_label;
+        private RightLabel job_type_label;
+
+        private ComboBox unit_type_combo_box;
+
+        public MainWindow() throws DBus.Error {
+                title = session ? "systemd Session Manager" : "systemd System Manager";
+                position = WindowPosition.CENTER;
+                set_default_size(1000, 700);
+                set_border_width(12);
+                destroy += Gtk.main_quit;
+
+                Notebook notebook = new Notebook();
+                add(notebook);
+
+                Box unit_vbox = new VBox(false, 12);
+                notebook.append_page(unit_vbox, new Label("Units"));
+                unit_vbox.set_border_width(12);
+
+                Box job_vbox = new VBox(false, 12);
+                notebook.append_page(job_vbox, new Label("Jobs"));
+                job_vbox.set_border_width(12);
+
+                unit_type_combo_box = new ComboBox.text();
+                Box type_hbox = new HBox(false, 6);
+                type_hbox.pack_start(unit_type_combo_box, false, false, 0);
+                unit_vbox.pack_start(type_hbox, false, false, 0);
+
+                unit_type_combo_box.append_text("Show All Units");
+                unit_type_combo_box.append_text("Show Only Live Units");
+                unit_type_combo_box.append_text("Services");
+                unit_type_combo_box.append_text("Sockets");
+                unit_type_combo_box.append_text("Devices");
+                unit_type_combo_box.append_text("Mounts");
+                unit_type_combo_box.append_text("Automounts");
+                unit_type_combo_box.append_text("Targets");
+                unit_type_combo_box.append_text("Snapshots");
+                unit_type_combo_box.set_active(1);
+                unit_type_combo_box.changed += unit_type_changed;
+
+                unit_load_entry = new Entry();
+                unit_load_button = new Button.with_mnemonic("_Load");
+                unit_load_button.set_sensitive(false);
+
+                unit_load_entry.changed += on_unit_load_entry_changed;
+                unit_load_entry.activate += on_unit_load;
+                unit_load_button.clicked += on_unit_load;
+
+                Box unit_load_hbox = new HBox(false, 6);
+                unit_load_hbox.pack_start(unit_load_entry, false, true, 0);
+                unit_load_hbox.pack_start(unit_load_button, false, true, 0);
+
+                server_snapshot_button = new Button.with_mnemonic("Take S_napshot");
+                server_reload_button = new Button.with_mnemonic("Reload _Configuration");
+
+                server_snapshot_button.clicked += on_server_snapshot;
+                server_reload_button.clicked += on_server_reload;
+
+                type_hbox.pack_end(server_snapshot_button, false, true, 0);
+                type_hbox.pack_end(server_reload_button, false, true, 0);
+                type_hbox.pack_end(unit_load_hbox, false, true, 24);
+
+                unit_model = new ListStore(7, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(Unit));
+                job_model = new ListStore(6, typeof(string), typeof(string), typeof(string), typeof(string), typeof(Job), typeof(uint32));
+
+                TreeModelFilter unit_model_filter;
+                unit_model_filter = new TreeModelFilter(unit_model, null);
+                unit_model_filter.set_visible_func(unit_filter);
+
+                unit_view = new TreeView.with_model(unit_model_filter);
+                job_view = new TreeView.with_model(job_model);
+
+                unit_view.cursor_changed += unit_changed;
+                job_view.cursor_changed += job_changed;
+
+                unit_view.insert_column_with_attributes(-1, "Load State", new CellRendererText(), "text", 2);
+                unit_view.insert_column_with_attributes(-1, "Active State", new CellRendererText(), "text", 3);
+                unit_view.insert_column_with_attributes(-1, "Unit State", new CellRendererText(), "text", 4);
+                unit_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 0);
+                unit_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 5);
+
+                job_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 0);
+                job_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 1);
+                job_view.insert_column_with_attributes(-1, "Type", new CellRendererText(), "text", 2);
+                job_view.insert_column_with_attributes(-1, "State", new CellRendererText(), "text", 3);
+
+                ScrolledWindow scroll = new ScrolledWindow(null, null);
+                scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
+                scroll.set_shadow_type(ShadowType.IN);
+                scroll.add(unit_view);
+                unit_vbox.pack_start(scroll, true, true, 0);
+
+                scroll = new ScrolledWindow(null, null);
+                scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
+                scroll.set_shadow_type(ShadowType.IN);
+                scroll.add(job_view);
+                job_vbox.pack_start(scroll, true, true, 0);
+
+                unit_id_label = new RightLabel();
+                unit_aliases_label = new RightLabel();
+                unit_dependency_label = new RightLabel();
+                unit_description_label = new RightLabel();
+                unit_load_state_label = new RightLabel();
+                unit_active_state_label = new RightLabel();
+                unit_sub_state_label = new RightLabel();
+                unit_fragment_path_label = new RightLabel();
+                unit_active_enter_timestamp_label = new RightLabel();
+                unit_active_exit_timestamp_label = new RightLabel();
+                unit_can_start_label = new RightLabel();
+                unit_can_reload_label = new RightLabel();
+                unit_cgroup_label = new RightLabel();
+
+                job_id_label = new RightLabel();
+                job_state_label = new RightLabel();
+                job_type_label = new RightLabel();
+
+                unit_dependency_label.set_track_visited_links(false);
+                unit_dependency_label.set_selectable(false);
+                unit_dependency_label.activate_link += on_activate_link;
+
+                Table unit_table = new Table(8, 6, false);
+                unit_table.set_row_spacings(6);
+                unit_table.set_border_width(0);
+                unit_vbox.pack_start(unit_table, false, true, 0);
+
+                Table job_table = new Table(2, 2, false);
+                job_table.set_row_spacings(6);
+                job_table.set_border_width(0);
+                job_vbox.pack_start(job_table, false, true, 0);
+
+                unit_table.attach(new LeftLabel("Id:"),                     0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_id_label,                            1, 6, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Aliases:"),                0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_aliases_label,                       1, 6, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Description:"),            0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_description_label,                   1, 6, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Dependencies:"),           0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_dependency_label,                    1, 6, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Fragment Path:"),          0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_fragment_path_label,                 1, 6, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Control Group:"),          0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_cgroup_label,                        1, 6, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+
+                unit_table.attach(new LeftLabel("Load State:"),             0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_load_state_label,                    1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Active State:"),           0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_active_state_label,                  1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Unit State:"),             0, 1, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_sub_state_label,                     1, 2, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+
+                unit_table.attach(new LeftLabel("Active Enter Timestamp:"), 2, 3, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_active_enter_timestamp_label,        3, 4, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Active Exit Timestamp:"),  2, 3, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_active_exit_timestamp_label,         3, 4, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+
+                unit_table.attach(new LeftLabel("Can Start/Stop:"),         4, 5, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_can_start_label,                     5, 6, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(new LeftLabel("Can Reload:"),             4, 5, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                unit_table.attach(unit_can_reload_label,                    5, 6, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+
+                job_table.attach(new LeftLabel("Id:"),                      0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                job_table.attach(job_id_label,                              1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                job_table.attach(new LeftLabel("State:"),                   0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                job_table.attach(job_state_label,                           1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                job_table.attach(new LeftLabel("Type:"),                    0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+                job_table.attach(job_type_label,                            1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+
+                ButtonBox bbox = new HButtonBox();
+                bbox.set_layout(ButtonBoxStyle.START);
+                bbox.set_spacing(6);
+                unit_vbox.pack_start(bbox, false, true, 0);
+
+                start_button = new Button.with_mnemonic("_Start");
+                stop_button = new Button.with_mnemonic("Sto_p");
+                reload_button = new Button.with_mnemonic("_Reload");
+                restart_button = new Button.with_mnemonic("Res_tart");
+
+                start_button.clicked += on_start;
+                stop_button.clicked += on_stop;
+                reload_button.clicked += on_reload;
+                restart_button.clicked += on_restart;
+
+                bbox.pack_start(start_button, false, true, 0);
+                bbox.pack_start(stop_button, false, true, 0);
+                bbox.pack_start(restart_button, false, true, 0);
+                bbox.pack_start(reload_button, false, true, 0);
+
+                bbox = new HButtonBox();
+                bbox.set_layout(ButtonBoxStyle.START);
+                bbox.set_spacing(6);
+                job_vbox.pack_start(bbox, false, true, 0);
+
+                cancel_button = new Button.with_mnemonic("_Cancel");
+
+                cancel_button.clicked += on_cancel;
+
+                bbox.pack_start(cancel_button, false, true, 0);
+
+                bus = Bus.get(session ? BusType.SESSION : BusType.SYSTEM);
+
+                manager = bus.get_object(
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager") as Manager;
+
+                manager.unit_new += on_unit_new;
+                manager.job_new += on_job_new;
+                manager.unit_removed += on_unit_removed;
+                manager.job_removed += on_job_removed;
+
+                manager.subscribe();
+
+                clear_unit();
+                clear_job();
+                populate_unit_model();
+                populate_job_model();
+        }
+
+        public void populate_unit_model() throws DBus.Error {
+                unit_model.clear();
+
+                var list = manager.list_units();
+
+                foreach (var i in list) {
+                        TreeIter iter;
+
+                        Unit u = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        i.unit_path,
+                                        "org.freedesktop.systemd1.Unit") as Unit;
+
+                        u.changed += on_unit_changed;
+
+                        unit_model.append(out iter);
+                        unit_model.set(iter,
+                                       0, i.id,
+                                       1, i.description,
+                                       2, i.load_state,
+                                       3, i.active_state,
+                                       4, i.sub_state,
+                                       5, i.job_type != "" ? "→ %s".printf(i.job_type) : "",
+                                       6, u);
+                }
+        }
+
+        public void populate_job_model() throws DBus.Error {
+                job_model.clear();
+
+                var list = manager.list_jobs();
+
+                foreach (var i in list) {
+                        TreeIter iter;
+
+                        Job j = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        i.job_path,
+                                        "org.freedesktop.systemd1.Job") as Job;
+
+                        j.changed += on_job_changed;
+
+                        job_model.append(out iter);
+                        job_model.set(iter,
+                                      0, "%u".printf(i.id),
+                                      1, i.name,
+                                      2, "→ %s".printf(i.type),
+                                      3, i.state,
+                                      4, j,
+                                      5, i.id);
+                }
+        }
+
+        public Unit? get_current_unit() {
+                TreePath p;
+                unit_view.get_cursor(out p, null);
+
+                if (p == null)
+                        return null;
+
+                TreeModel model = unit_view.get_model();
+                TreeIter iter;
+                Unit u;
+
+                model.get_iter(out iter, p);
+                model.get(iter, 6, out u);
+
+                return u;
+        }
+
+        public void unit_changed() {
+                Unit u = get_current_unit();
+
+                if (u == null)
+                        clear_unit();
+                else
+                        show_unit(u);
+        }
+
+        public void clear_unit() {
+                current_unit_id = null;
+
+                start_button.set_sensitive(false);
+                stop_button.set_sensitive(false);
+                reload_button.set_sensitive(false);
+                restart_button.set_sensitive(false);
+
+                unit_id_label.set_text_or_na();
+                unit_aliases_label.set_text_or_na();
+                unit_description_label.set_text_or_na();
+                unit_description_label.set_text_or_na();
+                unit_load_state_label.set_text_or_na();
+                unit_active_state_label.set_text_or_na();
+                unit_sub_state_label.set_text_or_na();
+                unit_fragment_path_label.set_text_or_na();
+                unit_active_enter_timestamp_label.set_text_or_na();
+                unit_active_exit_timestamp_label.set_text_or_na();
+                unit_can_reload_label.set_text_or_na();
+                unit_can_start_label.set_text_or_na();
+                unit_cgroup_label.set_text_or_na();
+        }
+
+        public string make_dependency_string(string? prefix, string word, string[] dependencies) {
+                bool first = true;
+                string r;
+
+                if (prefix == null)
+                        r = "";
+                else
+                        r = prefix;
+
+                foreach (string i in dependencies) {
+                        if (r != "")
+                                r += first ? "\n" : ",";
+
+                        if (first) {
+                                r += word;
+                                first = false;
+                        }
+
+                        r += " <a href=\"" + i + "\">" + i + "</a>";
+                }
+
+                return r;
+        }
+
+        public void show_unit(Unit unit) {
+                current_unit_id = unit.id;
+
+                unit_id_label.set_text_or_na(current_unit_id);
+
+                string a = "";
+                foreach (string i in unit.names) {
+                        if (i == current_unit_id)
+                                continue;
+
+                        if (a == "")
+                                a = i;
+                        else
+                                a += "\n" + i;
+                }
+
+                unit_aliases_label.set_text_or_na(a);
+
+                string[]
+                        requires = unit.requires,
+                        requires_overridable = unit.requires_overridable,
+                        requisite = unit.requisite,
+                        requisite_overridable = unit.requisite_overridable,
+                        wants = unit.wants,
+                        required_by = unit.required_by,
+                        required_by_overridable = unit.required_by_overridable,
+                        wanted_by = unit.wanted_by,
+                        conflicts = unit.conflicts,
+                        before = unit.before,
+                        after = unit.after;
+
+                unit_dependency_label.set_markup_or_na(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(
+                                make_dependency_string(null,
+                                "requires", requires),
+                                "overridable requires", requires_overridable),
+                                "requisite", requisite),
+                                "overridable requisite", requisite_overridable),
+                                "wants", wants),
+                                "conflicts", conflicts),
+                                "required by", required_by),
+                                "overridable required by", required_by_overridable),
+                                "wanted by", wanted_by),
+                                "after", after),
+                                "before", before));
+
+                unit_description_label.set_text_or_na(unit.description);
+                unit_load_state_label.set_text_or_na(unit.load_state);
+                unit_active_state_label.set_text_or_na(unit.active_state);
+                unit_sub_state_label.set_text_or_na(unit.sub_state);
+                unit_fragment_path_label.set_text_or_na(unit.fragment_path);
+
+                uint64 t = unit.active_enter_timestamp;
+                if (t > 0) {
+                        Time timestamp = Time.local((time_t) (t / 1000000));
+                        unit_active_enter_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z"));
+                } else
+                        unit_active_enter_timestamp_label.set_text_or_na();
+
+                t = unit.active_exit_timestamp;
+                if (t > 0) {
+                        Time timestamp = Time.local((time_t) (t / 1000000));
+                        unit_active_exit_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z"));
+                } else
+                        unit_active_exit_timestamp_label.set_text_or_na();
+
+                bool b = unit.can_start;
+                start_button.set_sensitive(b);
+                stop_button.set_sensitive(b);
+                restart_button.set_sensitive(b);
+                unit_can_start_label.set_text_or_na(b ? "Yes" : "No");
+
+                b = unit.can_reload;
+                reload_button.set_sensitive(b);
+                unit_can_reload_label.set_text_or_na(b ? "Yes" : "No");
+
+                unit_cgroup_label.set_text_or_na(unit.default_control_group);
+        }
+
+        public Job? get_current_job() {
+                TreePath p;
+                job_view.get_cursor(out p, null);
+
+                if (p == null)
+                        return null;
+
+                TreeIter iter;
+                TreeModel model = job_view.get_model();
+                Job *j;
+
+                model.get_iter(out iter, p);
+                model.get(iter, 4, out j);
+
+                return j;
+        }
+
+        public void job_changed() {
+                Job j = get_current_job();
+
+                if (j == null)
+                        clear_job();
+                else
+                        show_job(j);
+        }
+
+        public void clear_job() {
+                current_job_id = 0;
+
+                job_id_label.set_text_or_na();
+                job_state_label.set_text_or_na();
+                job_type_label.set_text_or_na();
+
+                cancel_button.set_sensitive(false);
+        }
+
+        public void show_job(Job job) {
+                current_job_id = job.id;
+
+                job_id_label.set_text_or_na("%u".printf(current_job_id));
+                job_state_label.set_text_or_na(job.state);
+                job_type_label.set_text_or_na(job.job_type);
+
+                cancel_button.set_sensitive(true);
+        }
+
+        public void on_start() {
+                Unit u = get_current_unit();
+
+                if (u == null)
+                        return;
+
+                try {
+                        u.start("replace");
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_stop() {
+                Unit u = get_current_unit();
+
+                if (u == null)
+                        return;
+
+                try {
+                        u.stop("replace");
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_reload() {
+                Unit u = get_current_unit();
+
+                if (u == null)
+                        return;
+
+                try {
+                        u.reload("replace");
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_restart() {
+                Unit u = get_current_unit();
+
+                if (u == null)
+                        return;
+
+                try {
+                        u.restart("replace");
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_cancel() {
+                Job j = get_current_job();
+
+                if (j == null)
+                        return;
+
+                try {
+                        j.cancel();
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void update_unit_iter(TreeIter iter, string id, Unit u) {
+
+                string t = "";
+                Unit.JobLink jl = u.job;
+
+                if (jl.id != 0) {
+                        Job j = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        jl.path,
+                                        "org.freedesktop.systemd1.Job") as Job;
+
+                        t = j.job_type;
+                }
+
+                unit_model.set(iter,
+                               0, id,
+                               1, u.description,
+                               2, u.load_state,
+                               3, u.active_state,
+                               4, u.sub_state,
+                               5, t != "" ? "→ %s".printf(t) : "",
+                               6, u);
+        }
+
+        public void on_unit_new(string id, ObjectPath path) {
+                Unit u = bus.get_object(
+                                "org.freedesktop.systemd1",
+                                path,
+                                "org.freedesktop.systemd1.Unit") as Unit;
+
+                u.changed += on_unit_changed;
+
+                TreeIter iter;
+                unit_model.append(out iter);
+                update_unit_iter(iter, id, u);
+        }
+
+        public void update_job_iter(TreeIter iter, uint32 id, Job j) {
+                job_model.set(iter,
+                              0, "%u".printf(id),
+                              1, j.unit.id,
+                              2, "→ %s".printf(j.job_type),
+                              3, j.state,
+                              4, j,
+                              5, id);
+        }
+
+        public void on_job_new(uint32 id, ObjectPath path) {
+                Job j = bus.get_object(
+                                "org.freedesktop.systemd1",
+                                path,
+                                "org.freedesktop.systemd1.Job") as Job;
+
+                j.changed += on_job_changed;
+
+                TreeIter iter;
+                job_model.append(out iter);
+                update_job_iter(iter, id, j);
+        }
+
+        public void on_unit_removed(string id, ObjectPath path) {
+                TreeIter iter;
+                if (!(unit_model.get_iter_first(out iter)))
+                        return;
+
+                do {
+                        string name;
+
+                        unit_model.get(iter, 0, out name);
+
+                        if (id == name) {
+                                if (current_unit_id == name)
+                                        clear_unit();
+
+                                unit_model.remove(iter);
+                                break;
+                        }
+
+                } while (unit_model.iter_next(ref iter));
+        }
+
+        public void on_job_removed(uint32 id, ObjectPath path) {
+                TreeIter iter;
+                if (!(job_model.get_iter_first(out iter)))
+                        return;
+
+                do {
+                        uint32 j;
+
+                        job_model.get(iter, 5, out j);
+
+                        if (id == j) {
+                                if (current_job_id == j)
+                                        clear_job();
+
+                                job_model.remove(iter);
+
+                                break;
+                        }
+
+                } while (job_model.iter_next(ref iter));
+        }
+
+        public void on_unit_changed(Unit u) {
+                TreeIter iter;
+                string id;
+
+                if (!(unit_model.get_iter_first(out iter)))
+                        return;
+
+                id = u.id;
+
+                do {
+                        string name;
+
+                        unit_model.get(iter, 0, out name);
+
+                        if (id == name) {
+                                update_unit_iter(iter, id, u);
+
+                                if (current_unit_id == id)
+                                        show_unit(u);
+
+                                break;
+                        }
+
+                } while (unit_model.iter_next(ref iter));
+        }
+
+        public void on_job_changed(Job j) {
+                TreeIter iter;
+                uint32 id;
+
+                if (!(job_model.get_iter_first(out iter)))
+                        return;
+
+                id = j.id;
+
+                do {
+                        uint32 k;
+
+                        job_model.get(iter, 5, out k);
+
+                        if (id == k) {
+                                update_job_iter(iter, id, j);
+
+                                if (current_job_id == id)
+                                        show_job(j);
+
+                                break;
+                        }
+
+                } while (job_model.iter_next(ref iter));
+        }
+
+        public bool unit_filter(TreeModel model, TreeIter iter) {
+                string id, active_state, job;
+
+                model.get(iter, 0, out id, 3, out active_state, 5, out job);
+
+                if (id == null)
+                        return false;
+
+                switch (unit_type_combo_box.get_active()) {
+
+                        case 0:
+                                return true;
+
+                        case 1:
+                                return active_state != "inactive" || job != "";
+
+                        case 2:
+                                return id.has_suffix(".service");
+
+                        case 3:
+                                return id.has_suffix(".socket");
+
+                        case 4:
+                                return id.has_suffix(".device");
+
+                        case 5:
+                                return id.has_suffix(".mount");
+
+                        case 6:
+                                return id.has_suffix(".automount");
+
+                        case 7:
+                                return id.has_suffix(".target");
+
+                        case 8:
+                                return id.has_suffix(".snapshot");
+                }
+
+                return false;
+        }
+
+        public void unit_type_changed() {
+                TreeModelFilter model = (TreeModelFilter) unit_view.get_model();
+
+                model.refilter();
+        }
+
+        public void on_server_reload() {
+                try {
+                        manager.reload();
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_server_snapshot() {
+                try {
+                        manager.create_snapshot();
+
+                        if (unit_type_combo_box.get_active() != 0)
+                                unit_type_combo_box.set_active(8);
+
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_unit_load() {
+                string t = unit_load_entry.get_text();
+
+                if (t == "")
+                        return;
+
+                try {
+                        var path = manager.load_unit(t);
+
+                        Unit u = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        path,
+                                        "org.freedesktop.systemd1.Unit") as Unit;
+
+                        var m = new MessageDialog(this,
+                                                  DialogFlags.DESTROY_WITH_PARENT,
+                                                  MessageType.INFO,
+                                                  ButtonsType.CLOSE,
+                                                  "Unit available as id %s", u.id);
+                        m.title = "Unit";
+                        m.run();
+                        m.destroy();
+
+                        show_unit(u);
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+        }
+
+        public void on_unit_load_entry_changed() {
+                unit_load_button.set_sensitive(unit_load_entry.get_text() != "");
+        }
+
+        public bool on_activate_link(string uri) {
+
+                try {
+                        string path = manager.get_unit(uri);
+
+                        Unit u = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        path,
+                                        "org.freedesktop.systemd1.Unit") as Unit;
+
+                        show_unit(u);
+                } catch (DBus.Error e) {
+                        show_error(e.message);
+                }
+
+                return true;
+        }
+
+        public void show_error(string e) {
+                var m = new MessageDialog(this,
+                                          DialogFlags.DESTROY_WITH_PARENT,
+                                          MessageType.ERROR,
+                                          ButtonsType.CLOSE, "%s", e);
+                m.title = "Error";
+                m.run();
+                m.destroy();
+        }
+
+}
+
+static const OptionEntry entries[] = {
+        { "session", 0,   0,                   OptionArg.NONE,   out session, "Connect to session bus", null },
+        { "system",  0,   OptionFlags.REVERSE, OptionArg.NONE,   out session, "Connect to system bus", null },
+        { null }
+};
+
+void show_error(string e) {
+        var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
+        m.run();
+        m.destroy();
+}
+
+int main (string[] args) {
+
+        try {
+                Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm");
+
+                MainWindow window = new MainWindow();
+                window.show_all();
+
+                Gtk.main();
+        } catch (DBus.Error e) {
+                show_error(e.message);
+        } catch (GLib.Error e) {
+                show_error(e.message);
+        }
+
+        return 0;
+}
diff --git a/src/systemctl.vala b/src/systemctl.vala
new file mode 100644
index 0000000..821be5a
--- /dev/null
+++ b/src/systemctl.vala
@@ -0,0 +1,321 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+using DBus;
+using GLib;
+
+static string type = null;
+static bool all = false;
+static bool replace = false;
+static bool session = false;
+static Connection bus = null;
+
+public static int job_info_compare(void* key1, void* key2) {
+        Manager.JobInfo *j1 = (Manager.JobInfo*) key1;
+        Manager.JobInfo *j2 = (Manager.JobInfo*) key2;
+
+        return j1->id < j2->id ? -1 : (j1->id > j2->id ? 1 : 0);
+}
+
+public static int unit_info_compare(void* key1, void* key2) {
+        Manager.UnitInfo *u1 = (Manager.UnitInfo*) key1;
+        Manager.UnitInfo *u2 = (Manager.UnitInfo*) key2;
+
+        int r = Posix.strcmp(Posix.strrchr(u1->id, '.'), Posix.strrchr(u2->id, '.'));
+        if (r != 0)
+                return r;
+
+        return Posix.strcmp(u1->id, u2->id);
+}
+
+public void on_unit_changed(Unit u) {
+        stdout.printf("Unit %s changed.\n", u.id);
+}
+
+public void on_unit_new(string id, ObjectPath path) {
+        stdout.printf("Unit %s added.\n", id);
+
+        Unit u = bus.get_object(
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Unit") as Unit;
+
+        u.changed += on_unit_changed;
+
+        /* FIXME: We leak memory here */
+        u.ref();
+}
+
+public void on_job_changed(Job j) {
+        stdout.printf("Job %u changed.\n", j.id);
+}
+
+public void on_job_new(uint32 id, ObjectPath path) {
+        stdout.printf("Job %u added.\n", id);
+
+        Job j = bus.get_object(
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Job") as Job;
+
+        j.changed += on_job_changed;
+
+        /* FIXME: We leak memory here */
+        j.ref();
+}
+
+public void on_unit_removed(string id, ObjectPath path) {
+        stdout.printf("Unit %s removed.\n", id);
+}
+
+public void on_job_removed(uint32 id, ObjectPath path) {
+        stdout.printf("Job %u removed.\n", id);
+}
+
+static const OptionEntry entries[] = {
+        { "type",    't', 0,                   OptionArg.STRING, out type,    "List only particular type of units", "TYPE" },
+        { "all",     'a', 0,                   OptionArg.NONE,   out all,     "Show all units, including dead ones", null  },
+        { "replace", 0,   0,                   OptionArg.NONE,   out replace, "When installing a new job, replace existing conflicting ones", null },
+        { "session", 0,   0,                   OptionArg.NONE,   out session, "Connect to session bus", null },
+        { "system",  0,   OptionFlags.REVERSE, OptionArg.NONE,   out session, "Connect to system bus", null },
+        { null }
+};
+
+int main (string[] args) {
+
+        OptionContext context = new OptionContext("[COMMAND [ARGUMENT...]]");
+        context.add_main_entries(entries, null);
+        context.set_description(
+                        "Commands:\n" +
+                        "  list-units                      List units\n" +
+                        "  list-jobs                       List jobs\n" +
+                        "  clear-jobs                      Cancel all jobs\n" +
+                        "  load [NAME...]                  Load one or more units\n" +
+                        "  cancel [JOB...]                 Cancel one or more jobs\n" +
+                        "  start [NAME...]                 Start on or more units\n" +
+                        "  stop [NAME...]                  Stop on or more units\n" +
+                        "  enter [NAME]                    Start one unit and stop all others\n" +
+                        "  restart [NAME...]               Restart on or more units\n" +
+                        "  reload [NAME...]                Reload on or more units\n" +
+                        "  monitor                         Monitor unit/job changes\n" +
+                        "  dump                            Dump server status\n" +
+                        "  snapshot [NAME]                 Create a snapshot\n" +
+                        "  daemon-reload                   Reload daemon configuration\n" +
+                        "  daemon-reexecute                Reexecute daemon\n" +
+                        "  show-environment                Dump environment\n" +
+                        "  set-environment [NAME=VALUE...] Set one or more environment variables\n" +
+                        "  unset-environment [NAME...]     Unset one or more environment variables\n");
+
+        try {
+                context.parse(ref args);
+        } catch (GLib.OptionError e) {
+                message("Failed to parse command line: %s".printf(e.message));
+        }
+
+        try {
+                bus = Bus.get(session ? BusType.SESSION : BusType.SYSTEM);
+
+                Manager manager = bus.get_object (
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager") as Manager;
+
+                if (args[1] == "list-units" || args.length <= 1) {
+                        var list = manager.list_units();
+                        uint n = 0;
+                        Posix.qsort(list, list.length, sizeof(Manager.UnitInfo), unit_info_compare);
+
+                        stdout.printf("%-45s %-6s %-12s %-12s %-17s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB");
+
+                        foreach (var i in list) {
+
+                                if (type != null && !i.id.has_suffix(".%s".printf(type)))
+                                        continue;
+
+                                if (!all && i.active_state == "inactive")
+                                        continue;
+
+                                stdout.printf("%-45s %-6s %-12s %-12s", i.id, i.load_state, i.active_state, i.sub_state);
+
+                                if (i.job_id != 0)
+                                        stdout.printf(" -> %-15s", i.job_type);
+
+                                stdout.puts("\n");
+                                n++;
+                        }
+
+                        if (all)
+                                stdout.printf("\n%u units listed.\n", n);
+                        else
+                                stdout.printf("\n%u live units listed. Pass --all to see dead units, too.\n", n);
+
+
+                } else if (args[1] == "list-jobs") {
+                        var list = manager.list_jobs();
+                        Posix.qsort(list, list.length, sizeof(Manager.JobInfo), job_info_compare);
+
+                        stdout.printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
+
+                        foreach (var i in list)
+                                stdout.printf("%4u %-45s → %-15s %-7s\n", i.id, i.name, i.type, i.state);
+
+                        stdout.printf("\n%u jobs listed.\n", list.length);
+
+                } else if (args[1] == "clear-jobs") {
+
+                        manager.clear_jobs();
+
+                } else if (args[1] == "load") {
+
+                        if (args.length < 3) {
+                                stderr.printf("Missing argument.\n");
+                                return 1;
+                        }
+
+                        for (int i = 2; i < args.length; i++)
+                                manager.load_unit(args[i]);
+
+                } else if (args[1] == "cancel") {
+
+                        if (args.length < 3) {
+                                stderr.printf("Missing argument.\n");
+                                return 1;
+                        }
+
+                        for (int i = 2; i < args.length; i++) {
+                                uint32 id;
+
+                                if (args[i].scanf("%u", out id) != 1) {
+                                        stderr.printf("Failed to parse argument.\n");
+                                        return 1;
+                                }
+
+                                ObjectPath p = manager.get_job(id);
+
+                                Job j = bus.get_object (
+                                                "org.freedesktop.systemd1",
+                                                p,
+                                                "org.freedesktop.systemd1.Job") as Job;
+
+                                j.cancel();
+                        }
+
+                } else if (args[1] == "start" ||
+                           args[1] == "stop" ||
+                           args[1] == "reload" ||
+                           args[1] == "restart") {
+
+                        if (args.length < 3) {
+                                stderr.printf("Missing argument.\n");
+                                return 1;
+                        }
+
+                        for (int i = 2; i < args.length; i++) {
+
+                                ObjectPath p = manager.load_unit(args[i]);
+
+                                Unit u = bus.get_object(
+                                                "org.freedesktop.systemd1",
+                                                p,
+                                                "org.freedesktop.systemd1.Unit") as Unit;
+
+                                string mode = replace ? "replace" : "fail";
+
+                                if (args[1] == "start")
+                                        u.start(mode);
+                                else if (args[1] == "stop")
+                                        u.stop(mode);
+                                else if (args[1] == "restart")
+                                        u.restart(mode);
+                                else if (args[1] == "reload")
+                                        u.reload(mode);
+                        }
+
+                } else if (args[1] == "isolate") {
+
+                        if (args.length != 3) {
+                                stderr.printf("Missing argument.\n");
+                                return 1;
+                        }
+
+                        ObjectPath p = manager.load_unit(args[2]);
+
+                        Unit u = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        p,
+                                        "org.freedesktop.systemd1.Unit") as Unit;
+
+                        u.start("isolate");
+
+                } else if (args[1] == "monitor") {
+
+                        manager.subscribe();
+
+                        manager.unit_new += on_unit_new;
+                        manager.unit_removed += on_unit_removed;
+                        manager.job_new += on_job_new;
+                        manager.job_removed += on_job_removed;
+
+                        MainLoop l = new MainLoop();
+                        l.run();
+
+                } else if (args[1] == "dump")
+                        stdout.puts(manager.dump());
+
+                else if (args[1] == "snapshot") {
+
+                        ObjectPath p = manager.create_snapshot(args.length > 2 ? args[2] : "");
+
+                        Unit u = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        p,
+                                        "org.freedesktop.systemd1.Unit") as Unit;
+
+                        stdout.printf("%s\n", u.id);
+
+                } else if (args[1] == "daemon-reload")
+                        manager.reload();
+
+                else if (args[1] == "daemon-reexecute" || args[1] == "daemon-reexec")
+                        manager.reexecute();
+
+                else if (args[1] == "daemon-exit")
+                        manager.exit();
+
+                else if (args[1] == "show-environment") {
+                        foreach(var x in manager.environment)
+                                stderr.printf("%s\n", x);
+
+                } else if (args[1] == "set-environment")
+                        manager.set_environment(args[2:args.length]);
+
+                else if (args[1] == "unset-environment")
+                        manager.unset_environment(args[2:args.length]);
+
+                else {
+                        stderr.printf("Unknown command %s.\n", args[1]);
+                        return 1;
+                }
+
+        } catch (DBus.Error e) {
+                stderr.printf("%s\n".printf(e.message));
+        }
+
+        return 0;
+}
diff --git a/src/systemd-interfaces.vala b/src/systemd-interfaces.vala
new file mode 100644
index 0000000..7282bf3
--- /dev/null
+++ b/src/systemd-interfaces.vala
@@ -0,0 +1,137 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+using DBus;
+
+[DBus (name = "org.freedesktop.systemd1.Manager")]
+public interface Manager : DBus.Object {
+
+        public struct UnitInfo {
+                string id;
+                string description;
+                string load_state;
+                string active_state;
+                string sub_state;
+                ObjectPath unit_path;
+                uint32 job_id;
+                string job_type;
+                ObjectPath job_path;
+        }
+
+        public struct JobInfo {
+                uint32 id;
+                string name;
+                string type;
+                string state;
+                ObjectPath job_path;
+                ObjectPath unit_path;
+        }
+
+        public abstract string[] environment { owned get; }
+
+        public abstract UnitInfo[] list_units() throws DBus.Error;
+        public abstract JobInfo[] list_jobs() throws DBus.Error;
+
+        public abstract ObjectPath get_unit(string name) throws DBus.Error;
+        public abstract ObjectPath load_unit(string name) throws DBus.Error;
+        public abstract ObjectPath get_job(uint32 id) throws DBus.Error;
+
+        public abstract void clear_jobs() throws DBus.Error;
+
+        public abstract void subscribe() throws DBus.Error;
+        public abstract void unsubscribe() throws DBus.Error;
+
+        public abstract string dump() throws DBus.Error;
+
+        public abstract void reload() throws DBus.Error;
+        public abstract void reexecute() throws DBus.Error;
+        public abstract void exit() throws DBus.Error;
+
+        public abstract ObjectPath create_snapshot(string name = "", bool cleanup = false) throws DBus.Error;
+
+        public abstract void set_environment(string[] names) throws DBus.Error;
+        public abstract void unset_environment(string[] names) throws DBus.Error;
+
+        public abstract signal void unit_new(string id, ObjectPath path);
+        public abstract signal void unit_removed(string id, ObjectPath path);
+        public abstract signal void job_new(uint32 id, ObjectPath path);
+        public abstract signal void job_removed(uint32 id, ObjectPath path);
+}
+
+[DBus (name = "org.freedesktop.systemd1.Unit")]
+public interface Unit : DBus.Object {
+        public struct JobLink {
+                uint32 id;
+                ObjectPath path;
+        }
+
+        public abstract string id { owned get; }
+        public abstract string[] names { owned get; }
+        public abstract string[] requires { owned get; }
+        public abstract string[] requires_overridable { owned get; }
+        public abstract string[] requisite { owned get; }
+        public abstract string[] requisite_overridable { owned get; }
+        public abstract string[] wants { owned get; }
+        public abstract string[] required_by { owned get; }
+        public abstract string[] required_by_overridable { owned get; }
+        public abstract string[] wanted_by { owned get; }
+        public abstract string[] conflicts { owned get; }
+        public abstract string[] before { owned get; }
+        public abstract string[] after { owned get; }
+        public abstract string description { owned get; }
+        public abstract string load_state { owned get; }
+        public abstract string active_state { owned get; }
+        public abstract string sub_state { owned get; }
+        public abstract string fragment_path { owned get; }
+        public abstract uint64 inactive_exit_timestamp { owned get; }
+        public abstract uint64 active_enter_timestamp { owned get; }
+        public abstract uint64 active_exit_timestamp { owned get; }
+        public abstract uint64 inactive_enter_timestamp { owned get; }
+        public abstract bool can_start { owned get; }
+        public abstract bool can_reload { owned get; }
+        public abstract JobLink job { owned get; }
+        public abstract bool recursive_stop { owned get; }
+        public abstract bool stop_when_unneeded { owned get; }
+        public abstract string default_control_group { owned get; }
+        public abstract string[] control_groups { owned get; }
+
+        public abstract ObjectPath start(string mode) throws DBus.Error;
+        public abstract ObjectPath stop(string mode) throws DBus.Error;
+        public abstract ObjectPath restart(string mode) throws DBus.Error;
+        public abstract ObjectPath reload(string mode) throws DBus.Error;
+
+        public abstract signal void changed();
+}
+
+[DBus (name = "org.freedesktop.systemd1.Job")]
+public interface Job : DBus.Object {
+        public struct UnitLink {
+                string id;
+                ObjectPath path;
+        }
+
+        public abstract uint32 id { owned get; }
+        public abstract string state { owned get; }
+        public abstract string job_type { owned get; }
+        public abstract UnitLink unit { owned get; }
+
+        public abstract void cancel() throws DBus.Error;
+
+        public abstract signal void changed();
+}
diff --git a/src/target.c b/src/target.c
new file mode 100644
index 0000000..75f8ef8
--- /dev/null
+++ b/src/target.c
@@ -0,0 +1,194 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <signal.h>
+
+#include "unit.h"
+#include "target.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "dbus-target.h"
+
+static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
+        [TARGET_DEAD] = UNIT_INACTIVE,
+        [TARGET_ACTIVE] = UNIT_ACTIVE
+};
+
+static void target_set_state(Target *t, TargetState state) {
+        TargetState old_state;
+        assert(t);
+
+        old_state = t->state;
+        t->state = state;
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(t)->meta.id,
+                          target_state_to_string(old_state),
+                          target_state_to_string(state));
+
+        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int target_coldplug(Unit *u) {
+        Target *t = TARGET(u);
+
+        assert(t);
+        assert(t->state == TARGET_DEAD);
+
+        if (t->deserialized_state != t->state)
+                target_set_state(t, t->deserialized_state);
+
+        return 0;
+}
+
+static void target_dump(Unit *u, FILE *f, const char *prefix) {
+        Target *t = TARGET(u);
+
+        assert(t);
+        assert(f);
+
+        fprintf(f,
+                "%sTarget State: %s\n",
+                prefix, target_state_to_string(t->state));
+}
+
+static int target_start(Unit *u) {
+        Target *t = TARGET(u);
+
+        assert(t);
+        assert(t->state == TARGET_DEAD);
+
+        target_set_state(t, TARGET_ACTIVE);
+        return 0;
+}
+
+static int target_stop(Unit *u) {
+        Target *t = TARGET(u);
+
+        assert(t);
+        assert(t->state == TARGET_ACTIVE);
+
+        target_set_state(t, TARGET_DEAD);
+        return 0;
+}
+
+static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Target *s = TARGET(u);
+
+        assert(s);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", target_state_to_string(s->state));
+        return 0;
+}
+
+static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Target *s = TARGET(u);
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                TargetState state;
+
+                if ((state = target_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        s->deserialized_state = state;
+
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState target_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[TARGET(u)->state];
+}
+
+static const char *target_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return target_state_to_string(TARGET(u)->state);
+}
+
+int target_get_runlevel(Target *t) {
+
+        static const struct {
+                const char *special;
+                const int runlevel;
+        } table[] = {
+                { SPECIAL_RUNLEVEL5_TARGET, '5' },
+                { SPECIAL_RUNLEVEL4_TARGET, '4' },
+                { SPECIAL_RUNLEVEL3_TARGET, '3' },
+                { SPECIAL_RUNLEVEL2_TARGET, '2' },
+                { SPECIAL_RUNLEVEL1_TARGET, '1' },
+                { SPECIAL_RUNLEVEL0_TARGET, '0' },
+                { SPECIAL_RUNLEVEL6_TARGET, '6' },
+        };
+
+        unsigned i;
+
+        assert(t);
+
+        /* Tries to determine if this is a SysV runlevel and returns
+         * it if that is so. */
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (unit_has_name(UNIT(t), table[i].special))
+                        return table[i].runlevel;
+
+        return 0;
+}
+
+static const char* const target_state_table[_TARGET_STATE_MAX] = {
+        [TARGET_DEAD] = "dead",
+        [TARGET_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
+
+const UnitVTable target_vtable = {
+        .suffix = ".target",
+
+        .load = unit_load_fragment_and_dropin,
+        .coldplug = target_coldplug,
+
+        .dump = target_dump,
+
+        .start = target_start,
+        .stop = target_stop,
+
+        .serialize = target_serialize,
+        .deserialize_item = target_deserialize_item,
+
+        .active_state = target_active_state,
+        .sub_state_to_string = target_sub_state_to_string,
+
+        .bus_message_handler = bus_target_message_handler
+};
diff --git a/src/target.h b/src/target.h
new file mode 100644
index 0000000..5397d50
--- /dev/null
+++ b/src/target.h
@@ -0,0 +1,49 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef footargethfoo
+#define footargethfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Target Target;
+
+#include "unit.h"
+
+typedef enum TargetState {
+        TARGET_DEAD,
+        TARGET_ACTIVE,
+        _TARGET_STATE_MAX,
+        _TARGET_STATE_INVALID = -1
+} TargetState;
+
+struct Target {
+        Meta meta;
+
+        TargetState state, deserialized_state;
+};
+
+extern const UnitVTable target_vtable;
+
+int target_get_runlevel(Target *t);
+
+const char* target_state_to_string(TargetState i);
+TargetState target_state_from_string(const char *s);
+
+#endif
diff --git a/src/test-engine.c b/src/test-engine.c
new file mode 100644
index 0000000..27e16f3
--- /dev/null
+++ b/src/test-engine.c
@@ -0,0 +1,99 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "manager.h"
+
+int main(int argc, char *argv[]) {
+        Manager *m = NULL;
+        Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
+        Job *j;
+
+        assert_se(set_unit_path("test2") >= 0);
+
+        assert_se(manager_new(MANAGER_INIT, false, &m) >= 0);
+
+        printf("Load1:\n");
+        assert_se(manager_load_unit(m, "a.service", NULL, &a) == 0);
+        assert_se(manager_load_unit(m, "b.service", NULL, &b) == 0);
+        assert_se(manager_load_unit(m, "c.service", NULL, &c) == 0);
+        manager_dump_units(m, stdout, "\t");
+
+        printf("Test1: (Trivial)\n");
+        assert_se(manager_add_job(m, JOB_START, c, JOB_REPLACE, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Load2:\n");
+        manager_clear_jobs(m);
+        assert_se(manager_load_unit(m, "d.service", NULL, &d) == 0);
+        assert_se(manager_load_unit(m, "e.service", NULL, &e) == 0);
+        manager_dump_units(m, stdout, "\t");
+
+        printf("Test2: (Cyclic Order, Unfixable)\n");
+        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, &j) == -ENOEXEC);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
+        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Test4: (Identical transaction)\n");
+        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Load3:\n");
+        assert_se(manager_load_unit(m, "g.service", NULL, &g) == 0);
+        manager_dump_units(m, stdout, "\t");
+
+        printf("Test5: (Colliding transaction, fail)\n");
+        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, &j) == -EEXIST);
+
+        printf("Test6: (Colliding transaction, replace)\n");
+        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Test7: (Unmeargable job type, fail)\n");
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, &j) == -EEXIST);
+
+        printf("Test8: (Mergeable job type, fail)\n");
+        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Test9: (Unmeargable job type, replace)\n");
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        printf("Load4:\n");
+        assert_se(manager_load_unit(m, "h.service", NULL, &h) == 0);
+        manager_dump_units(m, stdout, "\t");
+
+        printf("Test10: (Unmeargable job type of auxiliary job, fail)\n");
+        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, &j) == 0);
+        manager_dump_jobs(m, stdout, "\t");
+
+        manager_free(m);
+
+        return 0;
+}
diff --git a/src/test-job-type.c b/src/test-job-type.c
new file mode 100644
index 0000000..b531262
--- /dev/null
+++ b/src/test-job-type.c
@@ -0,0 +1,84 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "job.h"
+
+int main(int argc, char*argv[]) {
+        JobType a, b, c, d, e, f, g;
+
+        for (a = 0; a < _JOB_TYPE_MAX; a++)
+                for (b = 0; b < _JOB_TYPE_MAX; b++) {
+
+                        if (!job_type_is_mergeable(a, b))
+                                printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b));
+
+                        for (c = 0; c < _JOB_TYPE_MAX; c++) {
+
+                                /* Verify transitivity of mergeability
+                                 * of job types */
+                                assert(!job_type_is_mergeable(a, b) ||
+                                       !job_type_is_mergeable(b, c) ||
+                                       job_type_is_mergeable(a, c));
+
+                                d = a;
+                                if (job_type_merge(&d, b) >= 0) {
+
+                                        printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(d));
+
+                                        /* Verify that merged entries can be
+                                         * merged with the same entries they
+                                         * can be merged with seperately */
+                                        assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(d, c));
+                                        assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(d, c));
+
+                                        /* Verify that if a merged
+                                         * with b is not mergable with
+                                         * c then either a or b is not
+                                         * mergeable with c either. */
+                                        assert(job_type_is_mergeable(d, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c));
+
+                                        e = b;
+                                        if (job_type_merge(&e, c) >= 0) {
+
+                                                /* Verify associativity */
+
+                                                f = d;
+                                                assert(job_type_merge(&f, c) == 0);
+
+                                                g = e;
+                                                assert(job_type_merge(&g, a) == 0);
+
+                                                assert(f == g);
+
+                                                printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(d));
+                                        }
+                                }
+                        }
+                }
+
+
+        return 0;
+}
diff --git a/src/test-loopback.c b/src/test-loopback.c
new file mode 100644
index 0000000..5cd7b41
--- /dev/null
+++ b/src/test-loopback.c
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "loopback-setup.h"
+
+int main(int argc, char* argv[]) {
+        int r;
+
+        if ((r = loopback_setup()) < 0)
+                fprintf(stderr, "loopback: %s\n", strerror(-r));
+
+        return 0;
+}
diff --git a/src/test-ns.c b/src/test-ns.c
new file mode 100644
index 0000000..a54011e
--- /dev/null
+++ b/src/test-ns.c
@@ -0,0 +1,60 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include "namespace.h"
+#include "log.h"
+
+int main(int argc, char *argv[]) {
+        const char * const writable[] = {
+                "/home",
+                NULL
+        };
+
+        const char * const readable[] = {
+                "/",
+                "/usr",
+                "/boot",
+                NULL
+        };
+
+        const char * const inaccessible[] = {
+                "/home/lennart/projects",
+                NULL
+        };
+
+        int r;
+
+        if ((r = setup_namespace((char**) writable, (char**) readable, (char**) inaccessible, true, MS_SHARED)) < 0) {
+                log_error("Failed to setup namespace: %s", strerror(-r));
+                return 1;
+        }
+
+        execl("/bin/sh", "/bin/sh", NULL);
+        log_error("execl(): %m");
+
+        return 1;
+}
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000..41aeb7f
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,51 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "unit.h"
+#include "timer.h"
+
+static void timer_done(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+}
+
+static UnitActiveState timer_active_state(Unit *u) {
+
+        static const UnitActiveState table[_TIMER_STATE_MAX] = {
+                [TIMER_DEAD] = UNIT_INACTIVE,
+                [TIMER_WAITING] = UNIT_ACTIVE,
+                [TIMER_RUNNING] = UNIT_ACTIVE
+        };
+
+        return table[TIMER(u)->state];
+}
+
+const UnitVTable timer_vtable = {
+        .suffix = ".timer",
+
+        .load = unit_load_fragment_and_dropin,
+        .done = timer_done,
+
+        .active_state = timer_active_state
+};
diff --git a/src/timer.h b/src/timer.h
new file mode 100644
index 0000000..0ec3e0d
--- /dev/null
+++ b/src/timer.h
@@ -0,0 +1,49 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef footimerhfoo
+#define footimerhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Timer Timer;
+
+#include "unit.h"
+
+typedef enum TimerState {
+        TIMER_DEAD,
+        TIMER_WAITING,
+        TIMER_RUNNING,
+        _TIMER_STATE_MAX
+} TimerState;
+
+struct Timer {
+        Meta meta;
+
+        TimerState state;
+
+        clockid_t clock_id;
+        usec_t next_elapse;
+
+        Service *service;
+};
+
+extern const UnitVTable timer_vtable;
+
+#endif
diff --git a/src/unit-name.c b/src/unit-name.c
new file mode 100644
index 0000000..c5901ca
--- /dev/null
+++ b/src/unit-name.c
@@ -0,0 +1,424 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+
+#include "unit.h"
+#include "unit-name.h"
+
+#define VALID_CHARS                             \
+        "0123456789"                            \
+        "abcdefghijklmnopqrstuvwxyz"            \
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
+        ":-_.\\"
+
+UnitType unit_name_to_type(const char *n) {
+        UnitType t;
+
+        assert(n);
+
+        for (t = 0; t < _UNIT_TYPE_MAX; t++)
+                if (endswith(n, unit_vtable[t]->suffix))
+                        return t;
+
+        return _UNIT_TYPE_INVALID;
+}
+
+bool unit_name_is_valid(const char *n) {
+        UnitType t;
+        const char *e, *i, *at;
+
+        /* Valid formats:
+         *
+         *         string at instance.suffix
+         *         string.suffix
+         */
+
+        assert(n);
+
+        if (strlen(n) >= UNIT_NAME_MAX)
+                return false;
+
+        t = unit_name_to_type(n);
+        if (t < 0 || t >= _UNIT_TYPE_MAX)
+                return false;
+
+        assert_se(e = strrchr(n, '.'));
+
+        if (e == n)
+                return false;
+
+        for (i = n, at = NULL; i < e; i++) {
+
+                if (*i == '@' && !at)
+                        at = i;
+
+                if (!strchr("@" VALID_CHARS, *i))
+                        return false;
+        }
+
+        if (at) {
+                if (at == n)
+                        return false;
+
+                if (at[1] == '.')
+                        return false;
+        }
+
+        return true;
+}
+
+bool unit_instance_is_valid(const char *i) {
+        assert(i);
+
+        /* The max length depends on the length of the string, so we
+         * don't really check this here. */
+
+        if (i[0] == 0)
+                return false;
+
+        /* We allow additional @ in the instance string, we do not
+         * allow them in the prefix! */
+
+        for (; *i; i++)
+                if (!strchr("@" VALID_CHARS, *i))
+                        return false;
+
+        return true;
+}
+
+bool unit_prefix_is_valid(const char *p) {
+
+        /* We don't allow additional @ in the instance string */
+
+        if (p[0] == 0)
+                return false;
+
+        for (; *p; p++)
+                if (!strchr(VALID_CHARS, *p))
+                        return false;
+
+        return true;
+}
+
+int unit_name_to_instance(const char *n, char **instance) {
+        const char *p, *d;
+        char *i;
+
+        assert(n);
+        assert(instance);
+
+        /* Everything past the first @ and before the last . is the instance */
+        if (!(p = strchr(n, '@'))) {
+                *instance = NULL;
+                return 0;
+        }
+
+        assert_se(d = strrchr(n, '.'));
+        assert(p < d);
+
+        if (!(i = strndup(p+1, d-p-1)))
+                return -ENOMEM;
+
+        *instance = i;
+        return 0;
+}
+
+char *unit_name_to_prefix_and_instance(const char *n) {
+        const char *d;
+
+        assert(n);
+
+        assert_se(d = strrchr(n, '.'));
+
+        return strndup(n, d - n);
+}
+
+char *unit_name_to_prefix(const char *n) {
+        const char *p;
+
+        if ((p = strchr(n, '@')))
+                return strndup(n, p - n);
+
+        return unit_name_to_prefix_and_instance(n);
+}
+
+char *unit_name_change_suffix(const char *n, const char *suffix) {
+        char *e, *r;
+        size_t a, b;
+
+        assert(n);
+        assert(unit_name_is_valid(n));
+        assert(suffix);
+
+        assert_se(e = strrchr(n, '.'));
+        a = e - n;
+        b = strlen(suffix);
+
+        if (!(r = new(char, a + b + 1)))
+                return NULL;
+
+        memcpy(r, n, a);
+        memcpy(r+a, suffix, b+1);
+
+        return r;
+}
+
+char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
+        char *r;
+
+        assert(prefix);
+        assert(unit_prefix_is_valid(prefix));
+        assert(!instance || unit_instance_is_valid(instance));
+        assert(suffix);
+        assert(unit_name_to_type(suffix) >= 0);
+
+        if (!instance)
+                return strappend(prefix, suffix);
+
+        if (asprintf(&r, "%s@%s%s", prefix, instance, suffix) < 0)
+                return NULL;
+
+        return r;
+}
+
+static char* do_escape(const char *f, char *t) {
+        assert(f);
+        assert(t);
+
+        for (; *f; f++) {
+                if (*f == '/')
+                        *(t++) = '-';
+                else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
+                        *(t++) = '\\';
+                        *(t++) = 'x';
+                        *(t++) = hexchar(*f > 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        return t;
+}
+
+char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
+        char *r, *t;
+        size_t a, b, c;
+
+        assert(prefix);
+        assert(suffix);
+        assert(unit_name_to_type(suffix) >= 0);
+
+        /* Takes a arbitrary string for prefix and instance plus a
+         * suffix and makes a nice string suitable as unit name of it,
+         * escaping all weird chars on the way.
+         *
+         * / becomes ., and all chars not alloweed in a unit name get
+         * escaped as \xFF, including \ and ., of course. This
+         * escaping is hence reversible.
+         *
+         * This is primarily useful to make nice unit names from
+         * strings, but is actually useful for any kind of string.
+         */
+
+        a = strlen(prefix);
+        c = strlen(suffix);
+
+        if (instance) {
+                b = strlen(instance);
+
+                if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
+                        return NULL;
+
+                t = do_escape(prefix, r);
+                *(t++) = '@';
+                t = do_escape(instance, t);
+        } else {
+
+                if (!(r = new(char, a*4 + c + 1)))
+                        return NULL;
+
+                t = do_escape(prefix, r);
+        }
+
+        strcpy(t, suffix);
+        return r;
+}
+
+char *unit_name_escape(const char *f) {
+        char *r, *t;
+
+        if (!(r = new(char, strlen(f)*4+1)))
+                return NULL;
+
+        t = do_escape(f, r);
+        *t = 0;
+
+        return r;
+
+}
+
+char *unit_name_unescape(const char *f) {
+        char *r, *t;
+
+        assert(f);
+
+        if (!(r = strdup(f)))
+                return NULL;
+
+        for (t = r; *f; f++) {
+                if (*f == '-')
+                        *(t++) = '/';
+                else 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;
+}
+
+bool unit_name_is_template(const char *n) {
+        const char *p;
+
+        assert(n);
+
+        if (!(p = strchr(n, '@')))
+                return false;
+
+        return p[1] == '.';
+}
+
+char *unit_name_replace_instance(const char *f, const char *i) {
+        const char *p, *e;
+        char *r, *k;
+        size_t a;
+
+        assert(f);
+
+        p = strchr(f, '@');
+        assert_se(e = strrchr(f, '.'));
+
+        a = p - f;
+
+        if (p) {
+                size_t b;
+
+                b = strlen(i);
+
+                if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
+                        return NULL;
+
+                k = mempcpy(r, f, a + 1);
+                k = mempcpy(k, i, b);
+        } else {
+
+                if (!(r = new(char, a + strlen(e) + 1)))
+                        return NULL;
+
+                k = mempcpy(r, f, a);
+        }
+
+        strcpy(k, e);
+        return r;
+}
+
+char *unit_name_template(const char *f) {
+        const char *p, *e;
+        char *r;
+        size_t a;
+
+        if (!(p = strchr(f, '@')))
+                return strdup(f);
+
+        assert_se(e = strrchr(f, '.'));
+        a = p - f + 1;
+
+        if (!(r = new(char, a + strlen(e) + 1)))
+                return NULL;
+
+        strcpy(mempcpy(r, f, a), e);
+        return r;
+
+}
+
+char *unit_name_from_path(const char *path, const char *suffix) {
+        char *p, *r;
+
+        assert(path);
+        assert(suffix);
+
+        if (!(p = strdup(path)))
+                return NULL;
+
+        path_kill_slashes(p);
+
+        path = p[0] == '/' ? p + 1 : p;
+
+        if (path[0] == 0) {
+                free(p);
+                return strappend("-", suffix);
+        }
+
+        r = unit_name_build_escape(path, NULL, suffix);
+        free(p);
+
+        return r;
+}
+
+char *unit_name_to_path(const char *name) {
+        char *w, *e;
+
+        assert(name);
+
+        if (!(w = unit_name_to_prefix(name)))
+                return NULL;
+
+        e = unit_name_unescape(w);
+        free(w);
+
+        if (!e)
+                return NULL;
+
+        if (e[0] != '/') {
+                w = strappend("/", e);
+                free(e);
+
+                if (!w)
+                        return NULL;
+
+                e = w;
+        }
+
+        return e;
+}
diff --git a/src/unit-name.h b/src/unit-name.h
new file mode 100644
index 0000000..b6dd2c9
--- /dev/null
+++ b/src/unit-name.h
@@ -0,0 +1,54 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foounitnamehfoo
+#define foounitnamehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "unit.h"
+
+UnitType unit_name_to_type(const char *n);
+
+int unit_name_to_instance(const char *n, char **instance);
+char* unit_name_to_prefix(const char *n);
+char* unit_name_to_prefix_and_instance(const char *n);
+
+bool unit_name_is_valid(const char *n);
+bool unit_prefix_is_valid(const char *p);
+bool unit_instance_is_valid(const char *i);
+
+char *unit_name_change_suffix(const char *n, const char *suffix);
+
+char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
+char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix);
+
+char *unit_name_escape(const char *f);
+char *unit_name_unescape(const char *f);
+
+bool unit_name_is_template(const char *n);
+
+char *unit_name_replace_instance(const char *f, const char *i);
+
+char *unit_name_template(const char *f);
+
+char *unit_name_from_path(const char *path, const char *suffix);
+char *unit_name_to_path(const char *name);
+
+#endif
diff --git a/src/unit.c b/src/unit.c
new file mode 100644
index 0000000..1959b1b
--- /dev/null
+++ b/src/unit.c
@@ -0,0 +1,1949 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <sys/poll.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "set.h"
+#include "unit.h"
+#include "macro.h"
+#include "strv.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "log.h"
+#include "unit-name.h"
+#include "specifier.h"
+#include "dbus-unit.h"
+
+const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
+        [UNIT_SERVICE] = &service_vtable,
+        [UNIT_TIMER] = &timer_vtable,
+        [UNIT_SOCKET] = &socket_vtable,
+        [UNIT_TARGET] = &target_vtable,
+        [UNIT_DEVICE] = &device_vtable,
+        [UNIT_MOUNT] = &mount_vtable,
+        [UNIT_AUTOMOUNT] = &automount_vtable,
+        [UNIT_SNAPSHOT] = &snapshot_vtable,
+        [UNIT_SWAP] = &swap_vtable
+};
+
+Unit *unit_new(Manager *m) {
+        Unit *u;
+
+        assert(m);
+
+        if (!(u = new0(Unit, 1)))
+                return NULL;
+
+        if (!(u->meta.names = set_new(string_hash_func, string_compare_func))) {
+                free(u);
+                return NULL;
+        }
+
+        u->meta.manager = m;
+        u->meta.type = _UNIT_TYPE_INVALID;
+
+        return u;
+}
+
+bool unit_has_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        return !!set_get(u->meta.names, (char*) name);
+}
+
+int unit_add_name(Unit *u, const char *text) {
+        UnitType t;
+        char *s = NULL, *i = NULL;
+        int r;
+
+        assert(u);
+        assert(text);
+
+        if (unit_name_is_template(text)) {
+                if (!u->meta.instance)
+                        return -EINVAL;
+
+                s = unit_name_replace_instance(text, u->meta.instance);
+        } else
+                s = strdup(text);
+
+        if (!s)
+                return -ENOMEM;
+
+        if (!unit_name_is_valid(s)) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        assert_se((t = unit_name_to_type(s)) >= 0);
+
+        if (u->meta.type != _UNIT_TYPE_INVALID && t != u->meta.type) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        if ((r = unit_name_to_instance(s, &i)) < 0)
+                goto fail;
+
+        if (i && unit_vtable[t]->no_instances)
+                goto fail;
+
+        if (u->meta.type != _UNIT_TYPE_INVALID && !streq_ptr(u->meta.instance, i)) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        if (unit_vtable[t]->no_alias &&
+            !set_isempty(u->meta.names) &&
+            !set_get(u->meta.names, s)) {
+                r = -EEXIST;
+                goto fail;
+        }
+
+        if (hashmap_size(u->meta.manager->units) >= MANAGER_MAX_NAMES) {
+                r = -E2BIG;
+                goto fail;
+        }
+
+        if ((r = set_put(u->meta.names, s)) < 0) {
+                if (r == -EEXIST)
+                        r = 0;
+                goto fail;
+        }
+
+        if ((r = hashmap_put(u->meta.manager->units, s, u)) < 0) {
+                set_remove(u->meta.names, s);
+                goto fail;
+        }
+
+        if (u->meta.type == _UNIT_TYPE_INVALID) {
+
+                u->meta.type = t;
+                u->meta.id = s;
+                u->meta.instance = i;
+
+                LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta);
+
+                if (UNIT_VTABLE(u)->init)
+                        UNIT_VTABLE(u)->init(u);
+        } else
+                free(i);
+
+        unit_add_to_dbus_queue(u);
+        return 0;
+
+fail:
+        free(s);
+        free(i);
+
+        return r;
+}
+
+int unit_choose_id(Unit *u, const char *name) {
+        char *s, *t = NULL;
+
+        assert(u);
+        assert(name);
+
+        if (unit_name_is_template(name)) {
+
+                if (!u->meta.instance)
+                        return -EINVAL;
+
+                if (!(t = unit_name_replace_instance(name, u->meta.instance)))
+                        return -ENOMEM;
+
+                name = t;
+        }
+
+        /* Selects one of the names of this unit as the id */
+        s = set_get(u->meta.names, (char*) name);
+        free(t);
+
+        if (!s)
+                return -ENOENT;
+
+        u->meta.id = s;
+        unit_add_to_dbus_queue(u);
+
+        return 0;
+}
+
+int unit_set_description(Unit *u, const char *description) {
+        char *s;
+
+        assert(u);
+
+        if (!(s = strdup(description)))
+                return -ENOMEM;
+
+        free(u->meta.description);
+        u->meta.description = s;
+
+        unit_add_to_dbus_queue(u);
+        return 0;
+}
+
+bool unit_check_gc(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->no_gc)
+                return true;
+
+        if (u->meta.job)
+                return true;
+
+        if (unit_active_state(u) != UNIT_INACTIVE)
+                return true;
+
+        if (UNIT_VTABLE(u)->check_gc)
+                if (UNIT_VTABLE(u)->check_gc(u))
+                        return true;
+
+        return false;
+}
+
+void unit_add_to_load_queue(Unit *u) {
+        assert(u);
+        assert(u->meta.type != _UNIT_TYPE_INVALID);
+
+        if (u->meta.load_state != UNIT_STUB || u->meta.in_load_queue)
+                return;
+
+        LIST_PREPEND(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
+        u->meta.in_load_queue = true;
+}
+
+void unit_add_to_cleanup_queue(Unit *u) {
+        assert(u);
+
+        if (u->meta.in_cleanup_queue)
+                return;
+
+        LIST_PREPEND(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta);
+        u->meta.in_cleanup_queue = true;
+}
+
+void unit_add_to_gc_queue(Unit *u) {
+        assert(u);
+
+        if (u->meta.in_gc_queue || u->meta.in_cleanup_queue)
+                return;
+
+        if (unit_check_gc(u))
+                return;
+
+        LIST_PREPEND(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta);
+        u->meta.in_gc_queue = true;
+
+        u->meta.manager->n_in_gc_queue ++;
+
+        if (u->meta.manager->gc_queue_timestamp <= 0)
+                u->meta.manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
+}
+
+void unit_add_to_dbus_queue(Unit *u) {
+        assert(u);
+        assert(u->meta.type != _UNIT_TYPE_INVALID);
+
+        if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue)
+                return;
+
+        if (set_isempty(u->meta.manager->subscribed)) {
+                u->meta.sent_dbus_new_signal = true;
+                return;
+        }
+
+        LIST_PREPEND(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
+        u->meta.in_dbus_queue = true;
+}
+
+static void bidi_set_free(Unit *u, Set *s) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+
+        /* Frees the set and makes sure we are dropped from the
+         * inverse pointers */
+
+        SET_FOREACH(other, s, i) {
+                UnitDependency d;
+
+                for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+                        set_remove(other->meta.dependencies[d], u);
+
+                unit_add_to_gc_queue(other);
+        }
+
+        set_free(s);
+}
+
+void unit_free(Unit *u) {
+        UnitDependency d;
+        Iterator i;
+        char *t;
+
+        assert(u);
+
+        bus_unit_send_removed_signal(u);
+
+        /* Detach from next 'bigger' objects */
+        SET_FOREACH(t, u->meta.names, i)
+                hashmap_remove_value(u->meta.manager->units, t, u);
+
+        if (u->meta.type != _UNIT_TYPE_INVALID)
+                LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta);
+
+        if (u->meta.in_load_queue)
+                LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
+
+        if (u->meta.in_dbus_queue)
+                LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
+
+        if (u->meta.in_cleanup_queue)
+                LIST_REMOVE(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta);
+
+        if (u->meta.in_gc_queue) {
+                LIST_REMOVE(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta);
+                u->meta.manager->n_in_gc_queue--;
+        }
+
+        /* Free data and next 'smaller' objects */
+        if (u->meta.job)
+                job_free(u->meta.job);
+
+        if (u->meta.load_state != UNIT_STUB)
+                if (UNIT_VTABLE(u)->done)
+                        UNIT_VTABLE(u)->done(u);
+
+        cgroup_bonding_free_list(u->meta.cgroup_bondings);
+
+        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+                bidi_set_free(u, u->meta.dependencies[d]);
+
+        free(u->meta.description);
+        free(u->meta.fragment_path);
+
+        while ((t = set_steal_first(u->meta.names)))
+                free(t);
+        set_free(u->meta.names);
+
+        free(u->meta.instance);
+
+        free(u);
+}
+
+UnitActiveState unit_active_state(Unit *u) {
+        assert(u);
+
+        if (u->meta.load_state != UNIT_LOADED)
+                return UNIT_INACTIVE;
+
+        return UNIT_VTABLE(u)->active_state(u);
+}
+
+const char* unit_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return UNIT_VTABLE(u)->sub_state_to_string(u);
+}
+
+static void complete_move(Set **s, Set **other) {
+        assert(s);
+        assert(other);
+
+        if (!*other)
+                return;
+
+        if (*s)
+                set_move(*s, *other);
+        else {
+                *s = *other;
+                *other = NULL;
+        }
+}
+
+static void merge_names(Unit *u, Unit *other) {
+        char *t;
+        Iterator i;
+
+        assert(u);
+        assert(other);
+
+        complete_move(&u->meta.names, &other->meta.names);
+
+        while ((t = set_steal_first(other->meta.names)))
+                free(t);
+
+        set_free(other->meta.names);
+        other->meta.names = NULL;
+        other->meta.id = NULL;
+
+        SET_FOREACH(t, u->meta.names, i)
+                assert_se(hashmap_replace(u->meta.manager->units, t, u) == 0);
+}
+
+static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) {
+        Iterator i;
+        Unit *back;
+        int r;
+
+        assert(u);
+        assert(other);
+        assert(d < _UNIT_DEPENDENCY_MAX);
+
+        SET_FOREACH(back, other->meta.dependencies[d], i) {
+                UnitDependency k;
+
+                for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
+                        if ((r = set_remove_and_put(back->meta.dependencies[k], other, u)) < 0) {
+
+                                if (r == -EEXIST)
+                                        set_remove(back->meta.dependencies[k], other);
+                                else
+                                        assert(r == -ENOENT);
+                        }
+        }
+
+        complete_move(&u->meta.dependencies[d], &other->meta.dependencies[d]);
+
+        set_free(other->meta.dependencies[d]);
+        other->meta.dependencies[d] = NULL;
+}
+
+int unit_merge(Unit *u, Unit *other) {
+        UnitDependency d;
+
+        assert(u);
+        assert(other);
+        assert(u->meta.manager == other->meta.manager);
+        assert(u->meta.type != _UNIT_TYPE_INVALID);
+
+        other = unit_follow_merge(other);
+
+        if (other == u)
+                return 0;
+
+        if (u->meta.type != other->meta.type)
+                return -EINVAL;
+
+        if (!streq_ptr(u->meta.instance, other->meta.instance))
+                return -EINVAL;
+
+        if (other->meta.load_state != UNIT_STUB &&
+            other->meta.load_state != UNIT_FAILED)
+                return -EEXIST;
+
+        if (other->meta.job)
+                return -EEXIST;
+
+        if (unit_active_state(other) != UNIT_INACTIVE)
+                return -EEXIST;
+
+        /* Merge names */
+        merge_names(u, other);
+
+        /* Merge dependencies */
+        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+                merge_dependencies(u, other, d);
+
+        other->meta.load_state = UNIT_MERGED;
+        other->meta.merged_into = u;
+
+        /* If there is still some data attached to the other node, we
+         * don't need it anymore, and can free it. */
+        if (other->meta.load_state != UNIT_STUB)
+                if (UNIT_VTABLE(other)->done)
+                        UNIT_VTABLE(other)->done(other);
+
+        unit_add_to_dbus_queue(u);
+        unit_add_to_cleanup_queue(other);
+
+        return 0;
+}
+
+int unit_merge_by_name(Unit *u, const char *name) {
+        Unit *other;
+        int r;
+        char *s = NULL;
+
+        assert(u);
+        assert(name);
+
+        if (unit_name_is_template(name)) {
+                if (!u->meta.instance)
+                        return -EINVAL;
+
+                if (!(s = unit_name_replace_instance(name, u->meta.instance)))
+                        return -ENOMEM;
+
+                name = s;
+        }
+
+        if (!(other = manager_get_unit(u->meta.manager, name)))
+                r = unit_add_name(u, name);
+        else
+                r = unit_merge(u, other);
+
+        free(s);
+        return r;
+}
+
+Unit* unit_follow_merge(Unit *u) {
+        assert(u);
+
+        while (u->meta.load_state == UNIT_MERGED)
+                assert_se(u = u->meta.merged_into);
+
+        return u;
+}
+
+int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
+        int r;
+
+        assert(u);
+        assert(c);
+
+        if (c->std_output != EXEC_OUTPUT_KERNEL && c->std_output != EXEC_OUTPUT_SYSLOG)
+                return 0;
+
+        /* If syslog or kernel logging is requested, make sure our own
+         * logging daemon is run first. */
+
+        if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
+                return r;
+
+        if (u->meta.manager->running_as != MANAGER_SESSION)
+                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
+                        return r;
+
+        return 0;
+}
+
+const char *unit_description(Unit *u) {
+        assert(u);
+
+        if (u->meta.description)
+                return u->meta.description;
+
+        return u->meta.id;
+}
+
+void unit_dump(Unit *u, FILE *f, const char *prefix) {
+        char *t;
+        UnitDependency d;
+        Iterator i;
+        char *p2;
+        const char *prefix2;
+        CGroupBonding *b;
+        char
+                timestamp1[FORMAT_TIMESTAMP_MAX],
+                timestamp2[FORMAT_TIMESTAMP_MAX],
+                timestamp3[FORMAT_TIMESTAMP_MAX],
+                timestamp4[FORMAT_TIMESTAMP_MAX];
+
+        assert(u);
+        assert(u->meta.type >= 0);
+
+        if (!prefix)
+                prefix = "";
+        p2 = strappend(prefix, "\t");
+        prefix2 = p2 ? p2 : prefix;
+
+        fprintf(f,
+                "%s-> Unit %s:\n"
+                "%s\tDescription: %s\n"
+                "%s\tInstance: %s\n"
+                "%s\tUnit Load State: %s\n"
+                "%s\tUnit Active State: %s\n"
+                "%s\tInactive Exit Timestamp: %s\n"
+                "%s\tActive Enter Timestamp: %s\n"
+                "%s\tActive Exit Timestamp: %s\n"
+                "%s\tInactive Enter Timestamp: %s\n"
+                "%s\tGC Check Good: %s\n",
+                prefix, u->meta.id,
+                prefix, unit_description(u),
+                prefix, strna(u->meta.instance),
+                prefix, unit_load_state_to_string(u->meta.load_state),
+                prefix, unit_active_state_to_string(unit_active_state(u)),
+                prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.inactive_exit_timestamp)),
+                prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp)),
+                prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp)),
+                prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp)),
+                prefix, yes_no(unit_check_gc(u)));
+
+        SET_FOREACH(t, u->meta.names, i)
+                fprintf(f, "%s\tName: %s\n", prefix, t);
+
+        if (u->meta.fragment_path)
+                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->meta.fragment_path);
+
+        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+                Unit *other;
+
+                SET_FOREACH(other, u->meta.dependencies[d], i)
+                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->meta.id);
+        }
+
+        if (u->meta.load_state == UNIT_LOADED) {
+                fprintf(f,
+                        "%s\tRecursive Stop: %s\n"
+                        "%s\tStop When Unneeded: %s\n",
+                        prefix, yes_no(u->meta.recursive_stop),
+                        prefix, yes_no(u->meta.stop_when_unneeded));
+
+                LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings)
+                        fprintf(f, "%s\tControlGroup: %s:%s\n",
+                                prefix, b->controller, b->path);
+
+                if (UNIT_VTABLE(u)->dump)
+                        UNIT_VTABLE(u)->dump(u, f, prefix2);
+
+        } else if (u->meta.load_state == UNIT_MERGED)
+                fprintf(f,
+                        "%s\tMerged into: %s\n",
+                        prefix, u->meta.merged_into->meta.id);
+
+        if (u->meta.job)
+                job_dump(u->meta.job, f, prefix2);
+
+        free(p2);
+}
+
+/* Common implementation for multiple backends */
+int unit_load_fragment_and_dropin(Unit *u) {
+        int r;
+
+        assert(u);
+
+        /* Load a .service file */
+        if ((r = unit_load_fragment(u)) < 0)
+                return r;
+
+        if (u->meta.load_state == UNIT_STUB)
+                return -ENOENT;
+
+        /* Load drop-in directory data */
+        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
+                return r;
+
+        return 0;
+}
+
+/* Common implementation for multiple backends */
+int unit_load_fragment_and_dropin_optional(Unit *u) {
+        int r;
+
+        assert(u);
+
+        /* Same as unit_load_fragment_and_dropin(), but whether
+         * something can be loaded or not doesn't matter. */
+
+        /* Load a .service file */
+        if ((r = unit_load_fragment(u)) < 0)
+                return r;
+
+        if (u->meta.load_state == UNIT_STUB)
+                u->meta.load_state = UNIT_LOADED;
+
+        /* Load drop-in directory data */
+        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
+                return r;
+
+        return 0;
+}
+
+/* Common implementation for multiple backends */
+int unit_load_nop(Unit *u) {
+        assert(u);
+
+        if (u->meta.load_state == UNIT_STUB)
+                u->meta.load_state = UNIT_LOADED;
+
+        return 0;
+}
+
+int unit_load(Unit *u) {
+        int r;
+
+        assert(u);
+
+        if (u->meta.in_load_queue) {
+                LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
+                u->meta.in_load_queue = false;
+        }
+
+        if (u->meta.type == _UNIT_TYPE_INVALID)
+                return -EINVAL;
+
+        if (u->meta.load_state != UNIT_STUB)
+                return 0;
+
+        if (UNIT_VTABLE(u)->load)
+                if ((r = UNIT_VTABLE(u)->load(u)) < 0)
+                        goto fail;
+
+        if (u->meta.load_state == UNIT_STUB) {
+                r = -ENOENT;
+                goto fail;
+        }
+
+        assert((u->meta.load_state != UNIT_MERGED) == !u->meta.merged_into);
+
+        unit_add_to_dbus_queue(unit_follow_merge(u));
+        unit_add_to_gc_queue(u);
+
+        return 0;
+
+fail:
+        u->meta.load_state = UNIT_FAILED;
+        unit_add_to_dbus_queue(u);
+
+        log_debug("Failed to load configuration for %s: %s", u->meta.id, strerror(-r));
+
+        return r;
+}
+
+/* Errors:
+ *         -EBADR:    This unit type does not support starting.
+ *         -EALREADY: Unit is already started.
+ *         -EAGAIN:   An operation is already in progress. Retry later.
+ */
+int unit_start(Unit *u) {
+        UnitActiveState state;
+
+        assert(u);
+
+        /* If this is already (being) started, then this will
+         * succeed. Note that this will even succeed if this unit is
+         * not startable by the user. This is relied on to detect when
+         * we need to wait for units and when waiting is finished. */
+        state = unit_active_state(u);
+        if (UNIT_IS_ACTIVE_OR_RELOADING(state))
+                return -EALREADY;
+
+        /* If it is stopped, but we cannot start it, then fail */
+        if (!UNIT_VTABLE(u)->start)
+                return -EBADR;
+
+        /* We don't suppress calls to ->start() here when we are
+         * already starting, to allow this request to be used as a
+         * "hurry up" call, for example when the unit is in some "auto
+         * restart" state where it waits for a holdoff timer to elapse
+         * before it will start again. */
+
+        unit_add_to_dbus_queue(u);
+        return UNIT_VTABLE(u)->start(u);
+}
+
+bool unit_can_start(Unit *u) {
+        assert(u);
+
+        return !!UNIT_VTABLE(u)->start;
+}
+
+/* Errors:
+ *         -EBADR:    This unit type does not support stopping.
+ *         -EALREADY: Unit is already stopped.
+ *         -EAGAIN:   An operation is already in progress. Retry later.
+ */
+int unit_stop(Unit *u) {
+        UnitActiveState state;
+
+        assert(u);
+
+        state = unit_active_state(u);
+        if (state == UNIT_INACTIVE)
+                return -EALREADY;
+
+        if (!UNIT_VTABLE(u)->stop)
+                return -EBADR;
+
+        unit_add_to_dbus_queue(u);
+        return UNIT_VTABLE(u)->stop(u);
+}
+
+/* Errors:
+ *         -EBADR:    This unit type does not support reloading.
+ *         -ENOEXEC:  Unit is not started.
+ *         -EAGAIN:   An operation is already in progress. Retry later.
+ */
+int unit_reload(Unit *u) {
+        UnitActiveState state;
+
+        assert(u);
+
+        if (!unit_can_reload(u))
+                return -EBADR;
+
+        state = unit_active_state(u);
+        if (unit_active_state(u) == UNIT_ACTIVE_RELOADING)
+                return -EALREADY;
+
+        if (unit_active_state(u) != UNIT_ACTIVE)
+                return -ENOEXEC;
+
+        unit_add_to_dbus_queue(u);
+        return UNIT_VTABLE(u)->reload(u);
+}
+
+bool unit_can_reload(Unit *u) {
+        assert(u);
+
+        if (!UNIT_VTABLE(u)->reload)
+                return false;
+
+        if (!UNIT_VTABLE(u)->can_reload)
+                return true;
+
+        return UNIT_VTABLE(u)->can_reload(u);
+}
+
+static void unit_check_uneeded(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+
+        /* If this service shall be shut down when unneeded then do
+         * so. */
+
+        if (!u->meta.stop_when_unneeded)
+                return;
+
+        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        return;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        return;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTED_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        return;
+
+        log_debug("Service %s is not needed anymore. Stopping.", u->meta.id);
+
+        /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
+        manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL);
+}
+
+static void retroactively_start_dependencies(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+        assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
+                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i)
+                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
+                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
+                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
+}
+
+static void retroactively_stop_dependencies(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
+
+        if (u->meta.recursive_stop) {
+                /* Pull down units need us recursively if enabled */
+                SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
+                        if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                                manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
+        }
+
+        /* Garbage collect services that might not be needed anymore, if enabled */
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+}
+
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
+        bool unexpected = false;
+        usec_t ts;
+
+        assert(u);
+        assert(os < _UNIT_ACTIVE_STATE_MAX);
+        assert(ns < _UNIT_ACTIVE_STATE_MAX);
+
+        /* Note that this is called for all low-level state changes,
+         * even if they might map to the same high-level
+         * UnitActiveState! That means that ns == os is OK an expected
+         * behaviour here. For example: if a mount point is remounted
+         * this function will be called too and the utmp code below
+         * relies on that! */
+
+        ts = now(CLOCK_REALTIME);
+
+        if (os == UNIT_INACTIVE && ns != UNIT_INACTIVE)
+                u->meta.inactive_exit_timestamp = ts;
+        else if (os != UNIT_INACTIVE && ns == UNIT_INACTIVE)
+                u->meta.inactive_enter_timestamp = ts;
+
+        if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                u->meta.active_enter_timestamp = ts;
+        else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                u->meta.active_exit_timestamp = ts;
+
+        if (u->meta.job) {
+
+                if (u->meta.job->state == JOB_WAITING)
+
+                        /* So we reached a different state for this
+                         * job. Let's see if we can run it now if it
+                         * failed previously due to EAGAIN. */
+                        job_add_to_run_queue(u->meta.job);
+
+                else {
+                        assert(u->meta.job->state == JOB_RUNNING);
+
+                        /* Let's check whether this state change
+                         * constitutes a finished job, or maybe
+                         * cotradicts a running job and hence needs to
+                         * invalidate jobs. */
+
+                        switch (u->meta.job->type) {
+
+                        case JOB_START:
+                        case JOB_VERIFY_ACTIVE:
+
+                                if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                                        job_finish_and_invalidate(u->meta.job, true);
+                                else if (ns != UNIT_ACTIVATING) {
+                                        unexpected = true;
+                                        job_finish_and_invalidate(u->meta.job, false);
+                                }
+
+                                break;
+
+                        case JOB_RELOAD:
+                        case JOB_RELOAD_OR_START:
+
+                                if (ns == UNIT_ACTIVE)
+                                        job_finish_and_invalidate(u->meta.job, true);
+                                else if (ns != UNIT_ACTIVATING && ns != UNIT_ACTIVE_RELOADING) {
+                                        unexpected = true;
+                                        job_finish_and_invalidate(u->meta.job, false);
+                                }
+
+                                break;
+
+                        case JOB_STOP:
+                        case JOB_RESTART:
+                        case JOB_TRY_RESTART:
+
+                                if (ns == UNIT_INACTIVE)
+                                        job_finish_and_invalidate(u->meta.job, true);
+                                else if (ns != UNIT_DEACTIVATING) {
+                                        unexpected = true;
+                                        job_finish_and_invalidate(u->meta.job, false);
+                                }
+
+                                break;
+
+                        default:
+                                assert_not_reached("Job type unknown");
+                        }
+                }
+        }
+
+        /* If this state change happened without being requested by a
+         * job, then let's retroactively start or stop dependencies */
+
+        if (unexpected) {
+                if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
+                        retroactively_start_dependencies(u);
+                else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
+                        retroactively_stop_dependencies(u);
+        }
+
+        /* Some names are special */
+        if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
+                if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) {
+                        /* The bus just might have become available,
+                         * hence try to connect to it, if we aren't
+                         * yet connected. */
+                        bus_init_system(u->meta.manager);
+                        bus_init_api(u->meta.manager);
+                }
+
+                if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
+                        /* The syslog daemon just might have become
+                         * available, hence try to connect to it, if
+                         * we aren't yet connected. */
+                        log_open();
+
+                if (u->meta.type == UNIT_MOUNT)
+                        /* Another directory became available, let's
+                         * check if that is enough to write our utmp
+                         * entry. */
+                        manager_write_utmp_reboot(u->meta.manager);
+
+                if (u->meta.type == UNIT_TARGET)
+                        /* A target got activated, maybe this is a runlevel? */
+                        manager_write_utmp_runlevel(u->meta.manager, u);
+
+        } else if (!UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
+
+                if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
+                        /* The syslog daemon might just have
+                         * terminated, hence try to disconnect from
+                         * it. */
+                        log_close_syslog();
+
+                /* We don't care about D-Bus here, since we'll get an
+                 * asynchronous notification for it anyway. */
+        }
+
+        /* Maybe we finished startup and are now ready for being
+         * stopped because unneeded? */
+        unit_check_uneeded(u);
+
+        unit_add_to_dbus_queue(u);
+        unit_add_to_gc_queue(u);
+}
+
+int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
+        struct epoll_event ev;
+
+        assert(u);
+        assert(fd >= 0);
+        assert(w);
+        assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u));
+
+        zero(ev);
+        ev.data.ptr = w;
+        ev.events = events;
+
+        if (epoll_ctl(u->meta.manager->epoll_fd,
+                      w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD,
+                      fd,
+                      &ev) < 0)
+                return -errno;
+
+        w->fd = fd;
+        w->type = WATCH_FD;
+        w->data.unit = u;
+
+        return 0;
+}
+
+void unit_unwatch_fd(Unit *u, Watch *w) {
+        assert(u);
+        assert(w);
+
+        if (w->type == WATCH_INVALID)
+                return;
+
+        assert(w->type == WATCH_FD);
+        assert(w->data.unit == u);
+        assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
+
+        w->fd = -1;
+        w->type = WATCH_INVALID;
+        w->data.unit = NULL;
+}
+
+int unit_watch_pid(Unit *u, pid_t pid) {
+        assert(u);
+        assert(pid >= 1);
+
+        /* Watch a specific PID. We only support one unit watching
+         * each PID for now. */
+
+        return hashmap_put(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
+}
+
+void unit_unwatch_pid(Unit *u, pid_t pid) {
+        assert(u);
+        assert(pid >= 1);
+
+        hashmap_remove_value(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
+}
+
+int unit_watch_timer(Unit *u, usec_t delay, Watch *w) {
+        struct itimerspec its;
+        int flags, fd;
+        bool ours;
+
+        assert(u);
+        assert(w);
+        assert(w->type == WATCH_INVALID || (w->type == WATCH_TIMER && w->data.unit == u));
+
+        /* This will try to reuse the old timer if there is one */
+
+        if (w->type == WATCH_TIMER) {
+                ours = false;
+                fd = w->fd;
+        } else {
+                ours = true;
+                if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
+                        return -errno;
+        }
+
+        zero(its);
+
+        if (delay <= 0) {
+                /* Set absolute time in the past, but not 0, since we
+                 * don't want to disarm the timer */
+                its.it_value.tv_sec = 0;
+                its.it_value.tv_nsec = 1;
+
+                flags = TFD_TIMER_ABSTIME;
+        } else {
+                timespec_store(&its.it_value, delay);
+                flags = 0;
+        }
+
+        /* This will also flush the elapse counter */
+        if (timerfd_settime(fd, flags, &its, NULL) < 0)
+                goto fail;
+
+        if (w->type == WATCH_INVALID) {
+                struct epoll_event ev;
+
+                zero(ev);
+                ev.data.ptr = w;
+                ev.events = EPOLLIN;
+
+                if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
+                        goto fail;
+        }
+
+        w->fd = fd;
+        w->type = WATCH_TIMER;
+        w->data.unit = u;
+
+        return 0;
+
+fail:
+        if (ours)
+                close_nointr_nofail(fd);
+
+        return -errno;
+}
+
+void unit_unwatch_timer(Unit *u, Watch *w) {
+        assert(u);
+        assert(w);
+
+        if (w->type == WATCH_INVALID)
+                return;
+
+        assert(w->type == WATCH_TIMER && w->data.unit == u);
+
+        assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
+        close_nointr_nofail(w->fd);
+
+        w->fd = -1;
+        w->type = WATCH_INVALID;
+        w->data.unit = NULL;
+}
+
+bool unit_job_is_applicable(Unit *u, JobType j) {
+        assert(u);
+        assert(j >= 0 && j < _JOB_TYPE_MAX);
+
+        switch (j) {
+
+        case JOB_VERIFY_ACTIVE:
+        case JOB_START:
+                return true;
+
+        case JOB_STOP:
+        case JOB_RESTART:
+        case JOB_TRY_RESTART:
+                return unit_can_start(u);
+
+        case JOB_RELOAD:
+                return unit_can_reload(u);
+
+        case JOB_RELOAD_OR_START:
+                return unit_can_reload(u) && unit_can_start(u);
+
+        default:
+                assert_not_reached("Invalid job type");
+        }
+}
+
+int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
+
+        static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
+                [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
+                [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
+                [UNIT_WANTS] = UNIT_WANTED_BY,
+                [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
+                [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
+                [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_CONFLICTS] = UNIT_CONFLICTS,
+                [UNIT_BEFORE] = UNIT_AFTER,
+                [UNIT_AFTER] = UNIT_BEFORE,
+                [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
+                [UNIT_REFERENCED_BY] = UNIT_REFERENCES
+        };
+        int r, q = 0, v = 0, w = 0;
+
+        assert(u);
+        assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
+        assert(inverse_table[d] != _UNIT_DEPENDENCY_INVALID);
+        assert(other);
+
+        /* We won't allow dependencies on ourselves. We will not
+         * consider them an error however. */
+        if (u == other)
+                return 0;
+
+        if (UNIT_VTABLE(u)->no_requires &&
+            (d == UNIT_REQUIRES ||
+             d == UNIT_REQUIRES_OVERRIDABLE ||
+             d == UNIT_REQUISITE ||
+             d == UNIT_REQUISITE_OVERRIDABLE)) {
+                    return -EINVAL;
+        }
+
+        if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0 ||
+            (r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
+                return r;
+
+        if (add_reference)
+                if ((r = set_ensure_allocated(&u->meta.dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
+                    (r = set_ensure_allocated(&other->meta.dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
+                        return r;
+
+        if ((q = set_put(u->meta.dependencies[d], other)) < 0)
+                return q;
+
+        if ((v = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) {
+                r = v;
+                goto fail;
+        }
+
+        if (add_reference) {
+                if ((w = set_put(u->meta.dependencies[UNIT_REFERENCES], other)) < 0) {
+                        r = w;
+                        goto fail;
+                }
+
+                if ((r = set_put(other->meta.dependencies[UNIT_REFERENCED_BY], u)) < 0)
+                        goto fail;
+        }
+
+        unit_add_to_dbus_queue(u);
+        return 0;
+
+fail:
+        if (q > 0)
+                set_remove(u->meta.dependencies[d], other);
+
+        if (v > 0)
+                set_remove(other->meta.dependencies[inverse_table[d]], u);
+
+        if (w > 0)
+                set_remove(u->meta.dependencies[UNIT_REFERENCES], other);
+
+        return r;
+}
+
+static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
+        char *s;
+
+        assert(u);
+        assert(name || path);
+
+        if (!name)
+                name = file_name_from_path(path);
+
+        if (!unit_name_is_template(name)) {
+                *p = NULL;
+                return name;
+        }
+
+        if (u->meta.instance)
+                s = unit_name_replace_instance(name, u->meta.instance);
+        else {
+                char *i;
+
+                if (!(i = unit_name_to_prefix(u->meta.id)))
+                        return NULL;
+
+                s = unit_name_replace_instance(name, i);
+                free(i);
+        }
+
+        if (!s)
+                return NULL;
+
+        *p = s;
+        return s;
+}
+
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+        Unit *other;
+        int r;
+        char *s;
+
+        assert(u);
+        assert(name || path);
+
+        if (!(name = resolve_template(u, name, path, &s)))
+                return -ENOMEM;
+
+        if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0)
+                goto finish;
+
+        r = unit_add_dependency(u, d, other, add_reference);
+
+finish:
+        free(s);
+        return r;
+}
+
+int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+        Unit *other;
+        int r;
+        char *s;
+
+        assert(u);
+        assert(name || path);
+
+        if (!(name = resolve_template(u, name, path, &s)))
+                return -ENOMEM;
+
+        if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0)
+                goto finish;
+
+        r = unit_add_dependency(other, d, u, add_reference);
+
+finish:
+        free(s);
+        return r;
+}
+
+int set_unit_path(const char *p) {
+        char *cwd, *c;
+        int r;
+
+        /* This is mostly for debug purposes */
+
+        if (path_is_absolute(p)) {
+                if (!(c = strdup(p)))
+                        return -ENOMEM;
+        } else {
+                if (!(cwd = get_current_dir_name()))
+                        return -errno;
+
+                r = asprintf(&c, "%s/%s", cwd, p);
+                free(cwd);
+
+                if (r < 0)
+                        return -ENOMEM;
+        }
+
+        if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) {
+                r = -errno;
+                free(c);
+                return r;
+        }
+
+        return 0;
+}
+
+char *unit_dbus_path(Unit *u) {
+        char *p, *e;
+
+        assert(u);
+
+        if (!(e = bus_path_escape(u->meta.id)))
+                return NULL;
+
+        if (asprintf(&p, "/org/freedesktop/systemd1/unit/%s", e) < 0) {
+                free(e);
+                return NULL;
+        }
+
+        free(e);
+        return p;
+}
+
+int unit_add_cgroup(Unit *u, CGroupBonding *b) {
+        CGroupBonding *l;
+        int r;
+
+        assert(u);
+        assert(b);
+        assert(b->path);
+
+        /* Ensure this hasn't been added yet */
+        assert(!b->unit);
+
+        l = hashmap_get(u->meta.manager->cgroup_bondings, b->path);
+        LIST_PREPEND(CGroupBonding, by_path, l, b);
+
+        if ((r = hashmap_replace(u->meta.manager->cgroup_bondings, b->path, l)) < 0) {
+                LIST_REMOVE(CGroupBonding, by_path, l, b);
+                return r;
+        }
+
+        LIST_PREPEND(CGroupBonding, by_unit, u->meta.cgroup_bondings, b);
+        b->unit = u;
+
+        return 0;
+}
+
+static char *default_cgroup_path(Unit *u) {
+        char *p;
+        int r;
+
+        assert(u);
+
+        if (u->meta.instance) {
+                char *t;
+
+                if (!(t = unit_name_template(u->meta.id)))
+                        return NULL;
+
+                r = asprintf(&p, "%s/%s/%s", u->meta.manager->cgroup_hierarchy, t, u->meta.instance);
+                free(t);
+        } else
+                r = asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id);
+
+        return r < 0 ? NULL : p;
+}
+
+int unit_add_cgroup_from_text(Unit *u, const char *name) {
+        size_t n;
+        char *controller = NULL, *path = NULL;
+        CGroupBonding *b = NULL;
+        int r;
+
+        assert(u);
+        assert(name);
+
+        /* Detect controller name */
+        n = strcspn(name, ":");
+
+        if (name[n] == 0 ||
+            (name[n] == ':' && name[n+1] == 0)) {
+
+                /* Only controller name, no path? */
+
+                if (!(path = default_cgroup_path(u)))
+                        return -ENOMEM;
+
+        } else {
+                const char *p;
+
+                /* Controller name, and path. */
+                p = name+n+1;
+
+                if (!path_is_absolute(p))
+                        return -EINVAL;
+
+                if (!(path = strdup(p)))
+                        return -ENOMEM;
+        }
+
+        if (n > 0)
+                controller = strndup(name, n);
+        else
+                controller = strdup(u->meta.manager->cgroup_controller);
+
+        if (!controller) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (cgroup_bonding_find_list(u->meta.cgroup_bondings, controller)) {
+                r = -EEXIST;
+                goto fail;
+        }
+
+        if (!(b = new0(CGroupBonding, 1))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        b->controller = controller;
+        b->path = path;
+        b->only_us = false;
+        b->clean_up = false;
+
+        if ((r = unit_add_cgroup(u, b)) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        free(path);
+        free(controller);
+        free(b);
+
+        return r;
+}
+
+int unit_add_default_cgroup(Unit *u) {
+        CGroupBonding *b;
+        int r = -ENOMEM;
+
+        assert(u);
+
+        /* Adds in the default cgroup data, if it wasn't specified yet */
+
+        if (unit_get_default_cgroup(u))
+                return 0;
+
+        if (!(b = new0(CGroupBonding, 1)))
+                return -ENOMEM;
+
+        if (!(b->controller = strdup(u->meta.manager->cgroup_controller)))
+                goto fail;
+
+        if (!(b->path = default_cgroup_path(u)))
+                goto fail;
+
+        b->clean_up = true;
+        b->only_us = true;
+
+        if ((r = unit_add_cgroup(u, b)) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        free(b->path);
+        free(b->controller);
+        free(b);
+
+        return r;
+}
+
+CGroupBonding* unit_get_default_cgroup(Unit *u) {
+        assert(u);
+
+        return cgroup_bonding_find_list(u->meta.cgroup_bondings, u->meta.manager->cgroup_controller);
+}
+
+int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
+        char *t;
+        int r;
+
+        assert(u);
+        assert(type);
+        assert(_found);
+
+        if (!(t = unit_name_change_suffix(u->meta.id, type)))
+                return -ENOMEM;
+
+        assert(!unit_has_name(u, t));
+
+        r = manager_load_unit(u->meta.manager, t, NULL, _found);
+        free(t);
+
+        assert(r < 0 || *_found != u);
+
+        return r;
+}
+
+int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
+        Unit *found;
+        char *t;
+
+        assert(u);
+        assert(type);
+        assert(_found);
+
+        if (!(t = unit_name_change_suffix(u->meta.id, type)))
+                return -ENOMEM;
+
+        assert(!unit_has_name(u, t));
+
+        found = manager_get_unit(u->meta.manager, t);
+        free(t);
+
+        if (!found)
+                return -ENOENT;
+
+        *_found = found;
+        return 0;
+}
+
+static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        return unit_name_to_prefix_and_instance(u->meta.id);
+}
+
+static char *specifier_prefix(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        return unit_name_to_prefix(u->meta.id);
+}
+
+static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        char *p, *r;
+
+        assert(u);
+
+        if (!(p = unit_name_to_prefix(u->meta.id)))
+                return NULL;
+
+        r = unit_name_unescape(p);
+        free(p);
+
+        return r;
+}
+
+static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        if (u->meta.instance)
+                return unit_name_unescape(u->meta.instance);
+
+        return strdup("");
+}
+
+char *unit_name_printf(Unit *u, const char* format) {
+
+        /*
+         * This will use the passed string as format string and
+         * replace the following specifiers:
+         *
+         * %n: the full id of the unit                 (foo at bar.waldo)
+         * %N: the id of the unit without the suffix   (foo at bar)
+         * %p: the prefix                              (foo)
+         * %i: the instance                            (bar)
+         */
+
+        const Specifier table[] = {
+                { 'n', specifier_string,              u->meta.id },
+                { 'N', specifier_prefix_and_instance, NULL },
+                { 'p', specifier_prefix,              NULL },
+                { 'i', specifier_string,              u->meta.instance },
+                { 0, NULL, NULL }
+        };
+
+        assert(u);
+        assert(format);
+
+        return specifier_printf(format, table, u);
+}
+
+char *unit_full_printf(Unit *u, const char *format) {
+
+        /* This is similar to unit_name_printf() but also supports
+         * unescaping */
+
+        const Specifier table[] = {
+                { 'n', specifier_string,              u->meta.id },
+                { 'N', specifier_prefix_and_instance, NULL },
+                { 'p', specifier_prefix,              NULL },
+                { 'P', specifier_prefix_unescaped,    NULL },
+                { 'i', specifier_string,              u->meta.instance },
+                { 'I', specifier_instance_unescaped,  NULL },
+                { 0, NULL, NULL }
+        };
+
+        assert(u);
+        assert(format);
+
+        return specifier_printf(format, table, u);
+}
+
+char **unit_full_printf_strv(Unit *u, char **l) {
+        size_t n;
+        char **r, **i, **j;
+
+        /* Applies unit_full_printf to every entry in l */
+
+        assert(u);
+
+        n = strv_length(l);
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        for (i = l, j = r; *i; i++, j++)
+                if (!(*j = unit_full_printf(u, *i)))
+                        goto fail;
+
+        *j = NULL;
+        return r;
+
+fail:
+        j--;
+        while (j >= r)
+                free(*j);
+
+        free(r);
+
+        return NULL;
+}
+
+int unit_watch_bus_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        /* Watch a specific name on the bus. We only support one unit
+         * watching each name for now. */
+
+        return hashmap_put(u->meta.manager->watch_bus, name, u);
+}
+
+void unit_unwatch_bus_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        hashmap_remove_value(u->meta.manager->watch_bus, name, u);
+}
+
+bool unit_can_serialize(Unit *u) {
+        assert(u);
+
+        return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
+}
+
+int unit_serialize(Unit *u, FILE *f, FDSet *fds) {
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        if (!unit_can_serialize(u))
+                return 0;
+
+        if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
+                return r;
+
+        /* End marker */
+        fputc('\n', f);
+        return 0;
+}
+
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
+        va_list ap;
+
+        assert(u);
+        assert(f);
+        assert(key);
+        assert(format);
+
+        fputs(key, f);
+        fputc('=', f);
+
+        va_start(ap, format);
+        vfprintf(f, format, ap);
+        va_end(ap);
+
+        fputc('\n', f);
+}
+
+void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
+        assert(u);
+        assert(f);
+        assert(key);
+        assert(value);
+
+        fprintf(f, "%s=%s\n", key, value);
+}
+
+int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        if (!unit_can_serialize(u))
+                return 0;
+
+        for (;;) {
+                char line[1024], *l, *v;
+                size_t k;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                return 0;
+                        return -errno;
+                }
+
+                l = strstrip(line);
+
+                /* End marker */
+                if (l[0] == 0)
+                        return 0;
+
+                k = strcspn(l, "=");
+
+                if (l[k] == '=') {
+                        l[k] = 0;
+                        v = l+k+1;
+                } else
+                        v = l+k;
+
+                if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
+                        return r;
+        }
+}
+
+int unit_add_node_link(Unit *u, const char *what, bool wants) {
+        Unit *device;
+        char *e;
+        int r;
+
+        assert(u);
+
+        if (!what)
+                return 0;
+
+        /* Adds in links to the device node that this unit is based on */
+
+        if (!is_device_path(what))
+                return 0;
+
+        if (!(e = unit_name_build_escape(what+1, NULL, ".device")))
+                return -ENOMEM;
+
+        r = manager_load_unit(u->meta.manager, e, NULL, &device);
+        free(e);
+
+        if (r < 0)
+                return r;
+
+        if ((r = unit_add_dependency(u, UNIT_AFTER, device, true)) < 0)
+                return r;
+
+        if ((r = unit_add_dependency(u, UNIT_REQUIRES, device, true)) < 0)
+                return r;
+
+        if (wants)
+                if ((r = unit_add_dependency(device, UNIT_WANTS, u, false)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
+        [UNIT_SERVICE] = "service",
+        [UNIT_TIMER] = "timer",
+        [UNIT_SOCKET] = "socket",
+        [UNIT_TARGET] = "target",
+        [UNIT_DEVICE] = "device",
+        [UNIT_MOUNT] = "mount",
+        [UNIT_AUTOMOUNT] = "automount",
+        [UNIT_SNAPSHOT] = "snapshot",
+        [UNIT_SWAP] = "swap"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
+
+static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
+        [UNIT_STUB] = "stub",
+        [UNIT_LOADED] = "loaded",
+        [UNIT_FAILED] = "failed",
+        [UNIT_MERGED] = "merged"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+
+static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
+        [UNIT_ACTIVE] = "active",
+        [UNIT_INACTIVE] = "inactive",
+        [UNIT_ACTIVATING] = "activating",
+        [UNIT_DEACTIVATING] = "deactivating"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
+
+static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
+        [UNIT_REQUIRES] = "Requires",
+        [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
+        [UNIT_WANTS] = "Wants",
+        [UNIT_REQUISITE] = "Requisite",
+        [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
+        [UNIT_REQUIRED_BY] = "RequiredBy",
+        [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
+        [UNIT_WANTED_BY] = "WantedBy",
+        [UNIT_CONFLICTS] = "Conflicts",
+        [UNIT_BEFORE] = "Before",
+        [UNIT_AFTER] = "After",
+        [UNIT_REFERENCES] = "References",
+        [UNIT_REFERENCED_BY] = "ReferencedBy"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
+
+static const char* const kill_mode_table[_KILL_MODE_MAX] = {
+        [KILL_CONTROL_GROUP] = "control-group",
+        [KILL_PROCESS_GROUP] = "process-group",
+        [KILL_PROCESS] = "process",
+        [KILL_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
diff --git a/src/unit.h b/src/unit.h
new file mode 100644
index 0000000..8f9d9e9
--- /dev/null
+++ b/src/unit.h
@@ -0,0 +1,448 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foounithfoo
+#define foounithfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+typedef union Unit Unit;
+typedef struct Meta Meta;
+typedef struct UnitVTable UnitVTable;
+typedef enum UnitType UnitType;
+typedef enum UnitLoadState UnitLoadState;
+typedef enum UnitActiveState UnitActiveState;
+typedef enum UnitDependency UnitDependency;
+
+#include "set.h"
+#include "util.h"
+#include "list.h"
+#include "socket-util.h"
+#include "execute.h"
+
+#define UNIT_NAME_MAX 128
+#define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC)
+#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
+
+typedef enum KillMode {
+        KILL_CONTROL_GROUP = 0,
+        KILL_PROCESS_GROUP,
+        KILL_PROCESS,
+        KILL_NONE,
+        _KILL_MODE_MAX,
+        _KILL_MODE_INVALID = -1
+} KillMode;
+
+enum UnitType {
+        UNIT_SERVICE = 0,
+        UNIT_SOCKET,
+        UNIT_TARGET,
+        UNIT_DEVICE,
+        UNIT_MOUNT,
+        UNIT_AUTOMOUNT,
+        UNIT_SNAPSHOT,
+        UNIT_TIMER,
+        UNIT_SWAP,
+        _UNIT_TYPE_MAX,
+        _UNIT_TYPE_INVALID = -1
+};
+
+enum UnitLoadState {
+        UNIT_STUB,
+        UNIT_LOADED,
+        UNIT_FAILED,
+        UNIT_MERGED,
+        _UNIT_LOAD_STATE_MAX,
+        _UNIT_LOAD_STATE_INVALID = -1
+};
+
+enum UnitActiveState {
+        UNIT_ACTIVE,
+        UNIT_ACTIVE_RELOADING,
+        UNIT_INACTIVE,
+        UNIT_ACTIVATING,
+        UNIT_DEACTIVATING,
+        _UNIT_ACTIVE_STATE_MAX,
+        _UNIT_ACTIVE_STATE_INVALID = -1
+};
+
+static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) {
+        return t == UNIT_ACTIVE || t == UNIT_ACTIVE_RELOADING;
+}
+
+static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) {
+        return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_ACTIVE_RELOADING;
+}
+
+static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
+        return t == UNIT_INACTIVE || t == UNIT_DEACTIVATING;
+}
+
+enum UnitDependency {
+        /* Positive dependencies */
+        UNIT_REQUIRES,
+        UNIT_REQUIRES_OVERRIDABLE,
+        UNIT_REQUISITE,
+        UNIT_REQUISITE_OVERRIDABLE,
+        UNIT_WANTS,
+
+        /* Inverse of the above */
+        UNIT_REQUIRED_BY,             /* inverse of 'requires' and 'requisite' is 'required_by' */
+        UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'soft_requires' and 'soft_requisite' is 'soft_required_by' */
+        UNIT_WANTED_BY,               /* inverse of 'wants' */
+
+        /* Negative dependencies */
+        UNIT_CONFLICTS,               /* inverse of 'conflicts' is 'conflicts' */
+
+        /* Order */
+        UNIT_BEFORE,                  /* inverse of 'before' is 'after' and vice versa */
+        UNIT_AFTER,
+
+        /* Reference information for GC logic */
+        UNIT_REFERENCES,              /* Inverse of 'references' is 'referenced_by' */
+        UNIT_REFERENCED_BY,
+
+        _UNIT_DEPENDENCY_MAX,
+        _UNIT_DEPENDENCY_INVALID = -1
+};
+
+#include "manager.h"
+#include "job.h"
+#include "cgroup.h"
+
+struct Meta {
+        Manager *manager;
+
+        UnitType type;
+        UnitLoadState load_state;
+        Unit *merged_into;
+
+        char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
+        char *instance;
+
+        Set *names;
+        Set *dependencies[_UNIT_DEPENDENCY_MAX];
+
+        char *description;
+        char *fragment_path; /* if loaded from a config file this is the primary path to it */
+
+        /* If there is something to do with this unit, then this is
+         * the job for it */
+        Job *job;
+
+        usec_t inactive_exit_timestamp;
+        usec_t active_enter_timestamp;
+        usec_t active_exit_timestamp;
+        usec_t inactive_enter_timestamp;
+
+        /* Counterparts in the cgroup filesystem */
+        CGroupBonding *cgroup_bondings;
+
+        /* Per type list */
+        LIST_FIELDS(Meta, units_per_type);
+
+        /* Load queue */
+        LIST_FIELDS(Meta, load_queue);
+
+        /* D-Bus queue */
+        LIST_FIELDS(Meta, dbus_queue);
+
+        /* Cleanup queue */
+        LIST_FIELDS(Meta, cleanup_queue);
+
+        /* GC queue */
+        LIST_FIELDS(Meta, gc_queue);
+
+        /* Used during GC sweeps */
+        unsigned gc_marker;
+
+        /* If we go down, pull down everything that depends on us, too */
+        bool recursive_stop;
+
+        /* Garbage collect us we nobody wants or requires us anymore */
+        bool stop_when_unneeded;
+
+        bool in_load_queue:1;
+        bool in_dbus_queue:1;
+        bool in_cleanup_queue:1;
+        bool in_gc_queue:1;
+
+        bool sent_dbus_new_signal:1;
+};
+
+#include "service.h"
+#include "timer.h"
+#include "socket.h"
+#include "target.h"
+#include "device.h"
+#include "mount.h"
+#include "automount.h"
+#include "snapshot.h"
+#include "swap.h"
+
+union Unit {
+        Meta meta;
+        Service service;
+        Timer timer;
+        Socket socket;
+        Target target;
+        Device device;
+        Mount mount;
+        Automount automount;
+        Snapshot snapshot;
+        Swap swap;
+};
+
+struct UnitVTable {
+        const char *suffix;
+
+        /* This should reset all type-specific variables. This should
+         * not allocate memory, and is called with zero-initialized
+         * data. It should hence only initialize variables that need
+         * to be set != 0. */
+        void (*init)(Unit *u);
+
+        /* This should free all type-specific variables. It should be
+         * idempotent. */
+        void (*done)(Unit *u);
+
+        /* Actually load data from disk. This may fail, and should set
+         * load_state to UNIT_LOADED, UNIT_MERGED or leave it at
+         * UNIT_STUB if no configuration could be found. */
+        int (*load)(Unit *u);
+
+        /* If a a lot of units got created via enumerate(), this is
+         * where to actually set the state and call unit_notify(). */
+        int (*coldplug)(Unit *u);
+
+        void (*dump)(Unit *u, FILE *f, const char *prefix);
+
+        int (*start)(Unit *u);
+        int (*stop)(Unit *u);
+        int (*reload)(Unit *u);
+
+        bool (*can_reload)(Unit *u);
+
+        /* Write all data that cannot be restored from other sources
+         * away using unit_serialize_item() */
+        int (*serialize)(Unit *u, FILE *f, FDSet *fds);
+
+        /* Restore one item from the serialization */
+        int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds);
+
+        /* Boils down the more complex internal state of this unit to
+         * a simpler one that the engine can understand */
+        UnitActiveState (*active_state)(Unit *u);
+
+        /* Returns the substate specific to this unit type as
+         * string. This is purely information so that we can give the
+         * user a more finegrained explanation in which actual state a
+         * unit is in. */
+        const char* (*sub_state_to_string)(Unit *u);
+
+        /* Return true when there is reason to keep this entry around
+         * even nothing references it and it isn't active in any
+         * way */
+        bool (*check_gc)(Unit *u);
+
+        /* Return true when this unit is suitable for snapshotting */
+        bool (*check_snapshot)(Unit *u);
+
+        void (*fd_event)(Unit *u, int fd, uint32_t events, Watch *w);
+        void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
+        void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
+
+        /* Called whenever any of the cgroups this unit watches for
+         * ran empty */
+        void (*cgroup_notify_empty)(Unit *u);
+
+        /* Called whenever a name thus Unit registered for comes or
+         * goes away. */
+        void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner);
+
+        /* Called whenever a bus PID lookup finishes */
+        void (*bus_query_pid_done)(Unit *u, const char *name, pid_t pid);
+
+        /* Called for each message received on the bus */
+        DBusHandlerResult (*bus_message_handler)(Unit *u, DBusMessage *message);
+
+        /* This is called for each unit type and should be used to
+         * enumerate existing devices and load them. However,
+         * everything that is loaded here should still stay in
+         * inactive state. It is the job of the coldplug() call above
+         * to put the units into the initial state.  */
+        int (*enumerate)(Manager *m);
+
+        /* Type specific cleanups. */
+        void (*shutdown)(Manager *m);
+
+        /* Can units of this type have multiple names? */
+        bool no_alias:1;
+
+        /* If true units of this types can never have "Requires"
+         * dependencies, because state changes can only be observed,
+         * not triggered */
+        bool no_requires:1;
+
+        /* Instances make no sense for this type */
+        bool no_instances:1;
+
+        /* Exclude this type from snapshots */
+        bool no_snapshots:1;
+
+        /* Exclude from automatic gc */
+        bool no_gc:1;
+
+        /* Exclude from isolation requests */
+        bool no_isolate:1;
+};
+
+extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
+
+#define UNIT_VTABLE(u) unit_vtable[(u)->meta.type]
+
+/* For casting a unit into the various unit types */
+#define DEFINE_CAST(UPPERCASE, MixedCase)                               \
+        static inline MixedCase* UPPERCASE(Unit *u) {                   \
+                if (!u || u->meta.type != UNIT_##UPPERCASE)             \
+                        return NULL;                                    \
+                                                                        \
+                return (MixedCase*) u;                                  \
+        }
+
+/* For casting the various unit types into a unit */
+#define UNIT(u) ((Unit*) (u))
+
+DEFINE_CAST(SOCKET, Socket);
+DEFINE_CAST(TIMER, Timer);
+DEFINE_CAST(SERVICE, Service);
+DEFINE_CAST(TARGET, Target);
+DEFINE_CAST(DEVICE, Device);
+DEFINE_CAST(MOUNT, Mount);
+DEFINE_CAST(AUTOMOUNT, Automount);
+DEFINE_CAST(SNAPSHOT, Snapshot);
+DEFINE_CAST(SWAP, Swap);
+
+Unit *unit_new(Manager *m);
+void unit_free(Unit *u);
+
+int unit_add_name(Unit *u, const char *name);
+
+int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference);
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
+int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
+
+int unit_add_exec_dependencies(Unit *u, ExecContext *c);
+
+int unit_add_cgroup(Unit *u, CGroupBonding *b);
+int unit_add_cgroup_from_text(Unit *u, const char *name);
+int unit_add_default_cgroup(Unit *u);
+CGroupBonding* unit_get_default_cgroup(Unit *u);
+
+int unit_choose_id(Unit *u, const char *name);
+int unit_set_description(Unit *u, const char *description);
+
+bool unit_check_gc(Unit *u);
+
+void unit_add_to_load_queue(Unit *u);
+void unit_add_to_dbus_queue(Unit *u);
+void unit_add_to_cleanup_queue(Unit *u);
+void unit_add_to_gc_queue(Unit *u);
+
+int unit_merge(Unit *u, Unit *other);
+int unit_merge_by_name(Unit *u, const char *other);
+
+Unit *unit_follow_merge(Unit *u);
+
+int unit_load_fragment_and_dropin(Unit *u);
+int unit_load_fragment_and_dropin_optional(Unit *u);
+int unit_load_nop(Unit *u);
+int unit_load(Unit *unit);
+
+const char *unit_description(Unit *u);
+
+bool unit_has_name(Unit *u, const char *name);
+
+UnitActiveState unit_active_state(Unit *u);
+
+const char* unit_sub_state_to_string(Unit *u);
+
+void unit_dump(Unit *u, FILE *f, const char *prefix);
+
+bool unit_can_reload(Unit *u);
+bool unit_can_start(Unit *u);
+
+int unit_start(Unit *u);
+int unit_stop(Unit *u);
+int unit_reload(Unit *u);
+
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns);
+
+int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w);
+void unit_unwatch_fd(Unit *u, Watch *w);
+
+int unit_watch_pid(Unit *u, pid_t pid);
+void unit_unwatch_pid(Unit *u, pid_t pid);
+
+int unit_watch_timer(Unit *u, usec_t delay, Watch *w);
+void unit_unwatch_timer(Unit *u, Watch *w);
+
+int unit_watch_bus_name(Unit *u, const char *name);
+void unit_unwatch_bus_name(Unit *u, const char *name);
+
+bool unit_job_is_applicable(Unit *u, JobType j);
+
+int set_unit_path(const char *p);
+
+char *unit_dbus_path(Unit *u);
+
+int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
+int unit_get_related_unit(Unit *u, const char *type, Unit **_found);
+
+char *unit_name_printf(Unit *u, const char* text);
+char *unit_full_printf(Unit *u, const char *text);
+char **unit_full_printf_strv(Unit *u, char **l);
+
+bool unit_can_serialize(Unit *u);
+int unit_serialize(Unit *u, FILE *f, FDSet *fds);
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr(4,5);
+void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
+int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
+
+int unit_add_node_link(Unit *u, const char *what, bool wants);
+
+const char *unit_type_to_string(UnitType i);
+UnitType unit_type_from_string(const char *s);
+
+const char *unit_load_state_to_string(UnitLoadState i);
+UnitLoadState unit_load_state_from_string(const char *s);
+
+const char *unit_active_state_to_string(UnitActiveState i);
+UnitActiveState unit_active_state_from_string(const char *s);
+
+const char *unit_dependency_to_string(UnitDependency i);
+UnitDependency unit_dependency_from_string(const char *s);
+
+const char *kill_mode_to_string(KillMode k);
+KillMode kill_mode_from_string(const char *s);
+
+#endif
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..f7d538a
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,2027 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <linux/sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <linux/tiocl.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <sys/inotify.h>
+#include <sys/poll.h>
+#include <libgen.h>
+#include <ctype.h>
+
+#include "macro.h"
+#include "util.h"
+#include "ioprio.h"
+#include "missing.h"
+#include "log.h"
+#include "strv.h"
+
+bool streq_ptr(const char *a, const char *b) {
+
+        /* Like streq(), but tries to make sense of NULL pointers */
+
+        if (a && b)
+                return streq(a, b);
+
+        if (!a && !b)
+                return true;
+
+        return false;
+}
+
+usec_t now(clockid_t clock_id) {
+        struct timespec ts;
+
+        assert_se(clock_gettime(clock_id, &ts) == 0);
+
+        return timespec_load(&ts);
+}
+
+usec_t timespec_load(const struct timespec *ts) {
+        assert(ts);
+
+        return
+                (usec_t) ts->tv_sec * USEC_PER_SEC +
+                (usec_t) ts->tv_nsec / NSEC_PER_USEC;
+}
+
+struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
+        assert(ts);
+
+        ts->tv_sec = (time_t) (u / USEC_PER_SEC);
+        ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
+
+        return ts;
+}
+
+usec_t timeval_load(const struct timeval *tv) {
+        assert(tv);
+
+        return
+                (usec_t) tv->tv_sec * USEC_PER_SEC +
+                (usec_t) tv->tv_usec;
+}
+
+struct timeval *timeval_store(struct timeval *tv, usec_t u) {
+        assert(tv);
+
+        tv->tv_sec = (time_t) (u / USEC_PER_SEC);
+        tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
+
+        return tv;
+}
+
+bool endswith(const char *s, const char *postfix) {
+        size_t sl, pl;
+
+        assert(s);
+        assert(postfix);
+
+        sl = strlen(s);
+        pl = strlen(postfix);
+
+        if (pl == 0)
+                return true;
+
+        if (sl < pl)
+                return false;
+
+        return memcmp(s + sl - pl, postfix, pl) == 0;
+}
+
+bool startswith(const char *s, const char *prefix) {
+        size_t sl, pl;
+
+        assert(s);
+        assert(prefix);
+
+        sl = strlen(s);
+        pl = strlen(prefix);
+
+        if (pl == 0)
+                return true;
+
+        if (sl < pl)
+                return false;
+
+        return memcmp(s, prefix, pl) == 0;
+}
+
+bool startswith_no_case(const char *s, const char *prefix) {
+        size_t sl, pl;
+        unsigned i;
+
+        assert(s);
+        assert(prefix);
+
+        sl = strlen(s);
+        pl = strlen(prefix);
+
+        if (pl == 0)
+                return true;
+
+        if (sl < pl)
+                return false;
+
+        for(i = 0; i < pl; ++i) {
+                if (tolower(s[i]) != tolower(prefix[i]))
+                        return false;
+        }
+
+        return true;
+}
+
+bool first_word(const char *s, const char *word) {
+        size_t sl, wl;
+
+        assert(s);
+        assert(word);
+
+        sl = strlen(s);
+        wl = strlen(word);
+
+        if (sl < wl)
+                return false;
+
+        if (wl == 0)
+                return true;
+
+        if (memcmp(s, word, wl) != 0)
+                return false;
+
+        return s[wl] == 0 ||
+                strchr(WHITESPACE, s[wl]);
+}
+
+int close_nointr(int fd) {
+        assert(fd >= 0);
+
+        for (;;) {
+                int r;
+
+                if ((r = close(fd)) >= 0)
+                        return r;
+
+                if (errno != EINTR)
+                        return r;
+        }
+}
+
+void close_nointr_nofail(int fd) {
+        int saved_errno = errno;
+
+        /* like close_nointr() but cannot fail, and guarantees errno
+         * is unchanged */
+
+        assert_se(close_nointr(fd) == 0);
+
+        errno = saved_errno;
+}
+
+int parse_boolean(const char *v) {
+        assert(v);
+
+        if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
+                return 1;
+        else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
+                return 0;
+
+        return -EINVAL;
+}
+
+int safe_atou(const char *s, unsigned *ret_u) {
+        char *x = NULL;
+        unsigned long l;
+
+        assert(s);
+        assert(ret_u);
+
+        errno = 0;
+        l = strtoul(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        if ((unsigned long) (unsigned) l != l)
+                return -ERANGE;
+
+        *ret_u = (unsigned) l;
+        return 0;
+}
+
+int safe_atoi(const char *s, int *ret_i) {
+        char *x = NULL;
+        long l;
+
+        assert(s);
+        assert(ret_i);
+
+        errno = 0;
+        l = strtol(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        if ((long) (int) l != l)
+                return -ERANGE;
+
+        *ret_i = (int) l;
+        return 0;
+}
+
+int safe_atolu(const char *s, long unsigned *ret_lu) {
+        char *x = NULL;
+        unsigned long l;
+
+        assert(s);
+        assert(ret_lu);
+
+        errno = 0;
+        l = strtoul(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_lu = l;
+        return 0;
+}
+
+int safe_atoli(const char *s, long int *ret_li) {
+        char *x = NULL;
+        long l;
+
+        assert(s);
+        assert(ret_li);
+
+        errno = 0;
+        l = strtol(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_li = l;
+        return 0;
+}
+
+int safe_atollu(const char *s, long long unsigned *ret_llu) {
+        char *x = NULL;
+        unsigned long long l;
+
+        assert(s);
+        assert(ret_llu);
+
+        errno = 0;
+        l = strtoull(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_llu = l;
+        return 0;
+}
+
+int safe_atolli(const char *s, long long int *ret_lli) {
+        char *x = NULL;
+        long long l;
+
+        assert(s);
+        assert(ret_lli);
+
+        errno = 0;
+        l = strtoll(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_lli = l;
+        return 0;
+}
+
+/* Split a string into words. */
+char *split(const char *c, size_t *l, const char *separator, char **state) {
+        char *current;
+
+        current = *state ? *state : (char*) c;
+
+        if (!*current || *c == 0)
+                return NULL;
+
+        current += strspn(current, separator);
+        *l = strcspn(current, separator);
+        *state = current+*l;
+
+        return (char*) current;
+}
+
+/* Split a string into words, but consider strings enclosed in '' and
+ * "" as words even if they include spaces. */
+char *split_quoted(const char *c, size_t *l, char **state) {
+        char *current;
+
+        current = *state ? *state : (char*) c;
+
+        if (!*current || *c == 0)
+                return NULL;
+
+        current += strspn(current, WHITESPACE);
+
+        if (*current == '\'') {
+                current ++;
+                *l = strcspn(current, "'");
+                *state = current+*l;
+
+                if (**state == '\'')
+                        (*state)++;
+        } else if (*current == '\"') {
+                current ++;
+                *l = strcspn(current, "\"");
+                *state = current+*l;
+
+                if (**state == '\"')
+                        (*state)++;
+        } else {
+                *l = strcspn(current, WHITESPACE);
+                *state = current+*l;
+        }
+
+        /* FIXME: Cannot deal with strings that have spaces AND ticks
+         * in them */
+
+        return (char*) current;
+}
+
+char **split_path_and_make_absolute(const char *p) {
+        char **l;
+        assert(p);
+
+        if (!(l = strv_split(p, ":")))
+                return NULL;
+
+        if (!strv_path_make_absolute_cwd(l)) {
+                strv_free(l);
+                return NULL;
+        }
+
+        return l;
+}
+
+int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
+        int r;
+        FILE *f;
+        char fn[132], line[256], *p;
+        long long unsigned ppid;
+
+        assert(pid >= 0);
+        assert(_ppid);
+
+        assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
+        fn[sizeof(fn)-1] = 0;
+
+        if (!(f = fopen(fn, "r")))
+                return -errno;
+
+        if (!(fgets(line, sizeof(line), f))) {
+                r = -errno;
+                fclose(f);
+                return r;
+        }
+
+        fclose(f);
+
+        /* Let's skip the pid and comm fields. The latter is enclosed
+         * in () but does not escape any () in its value, so let's
+         * skip over it manually */
+
+        if (!(p = strrchr(line, ')')))
+                return -EIO;
+
+        p++;
+
+        if (sscanf(p, " "
+                   "%*c "  /* state */
+                   "%llu ", /* ppid */
+                   &ppid) != 1)
+                return -EIO;
+
+        if ((long long unsigned) (pid_t) ppid != ppid)
+                return -ERANGE;
+
+        *_ppid = (pid_t) ppid;
+
+        return 0;
+}
+
+int write_one_line_file(const char *fn, const char *line) {
+        FILE *f;
+        int r;
+
+        assert(fn);
+        assert(line);
+
+        if (!(f = fopen(fn, "we")))
+                return -errno;
+
+        if (fputs(line, f) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        r = 0;
+finish:
+        fclose(f);
+        return r;
+}
+
+int read_one_line_file(const char *fn, char **line) {
+        FILE *f;
+        int r;
+        char t[2048], *c;
+
+        assert(fn);
+        assert(line);
+
+        if (!(f = fopen(fn, "re")))
+                return -errno;
+
+        if (!(fgets(t, sizeof(t), f))) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (!(c = strdup(t))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        *line = c;
+        r = 0;
+
+finish:
+        fclose(f);
+        return r;
+}
+
+char *truncate_nl(char *s) {
+        assert(s);
+
+        s[strcspn(s, NEWLINE)] = 0;
+        return s;
+}
+
+int get_process_name(pid_t pid, char **name) {
+        char *p;
+        int r;
+
+        assert(pid >= 1);
+        assert(name);
+
+        if (asprintf(&p, "/proc/%llu/comm", (unsigned long long) pid) < 0)
+                return -ENOMEM;
+
+        r = read_one_line_file(p, name);
+        free(p);
+
+        if (r < 0)
+                return r;
+
+        truncate_nl(*name);
+        return 0;
+}
+
+char *strappend(const char *s, const char *suffix) {
+        size_t a, b;
+        char *r;
+
+        assert(s);
+        assert(suffix);
+
+        a = strlen(s);
+        b = strlen(suffix);
+
+        if (!(r = new(char, a+b+1)))
+                return NULL;
+
+        memcpy(r, s, a);
+        memcpy(r+a, suffix, b);
+        r[a+b] = 0;
+
+        return r;
+}
+
+int readlink_malloc(const char *p, char **r) {
+        size_t l = 100;
+
+        assert(p);
+        assert(r);
+
+        for (;;) {
+                char *c;
+                ssize_t n;
+
+                if (!(c = new(char, l)))
+                        return -ENOMEM;
+
+                if ((n = readlink(p, c, l-1)) < 0) {
+                        int ret = -errno;
+                        free(c);
+                        return ret;
+                }
+
+                if ((size_t) n < l-1) {
+                        c[n] = 0;
+                        *r = c;
+                        return 0;
+                }
+
+                free(c);
+                l *= 2;
+        }
+}
+
+char *file_name_from_path(const char *p) {
+        char *r;
+
+        assert(p);
+
+        if ((r = strrchr(p, '/')))
+                return r + 1;
+
+        return (char*) p;
+}
+
+bool path_is_absolute(const char *p) {
+        assert(p);
+
+        return p[0] == '/';
+}
+
+bool is_path(const char *p) {
+
+        return !!strchr(p, '/');
+}
+
+char *path_make_absolute(const char *p, const char *prefix) {
+        char *r;
+
+        assert(p);
+
+        /* Makes every item in the list an absolute path by prepending
+         * the prefix, if specified and necessary */
+
+        if (path_is_absolute(p) || !prefix)
+                return strdup(p);
+
+        if (asprintf(&r, "%s/%s", prefix, p) < 0)
+                return NULL;
+
+        return r;
+}
+
+char *path_make_absolute_cwd(const char *p) {
+        char *cwd, *r;
+
+        assert(p);
+
+        /* Similar to path_make_absolute(), but prefixes with the
+         * current working directory. */
+
+        if (path_is_absolute(p))
+                return strdup(p);
+
+        if (!(cwd = get_current_dir_name()))
+                return NULL;
+
+        r = path_make_absolute(p, cwd);
+        free(cwd);
+
+        return r;
+}
+
+char **strv_path_make_absolute_cwd(char **l) {
+        char **s;
+
+        /* Goes through every item in the string list and makes it
+         * absolute. This works in place and won't rollback any
+         * changes on failure. */
+
+        STRV_FOREACH(s, l) {
+                char *t;
+
+                if (!(t = path_make_absolute_cwd(*s)))
+                        return NULL;
+
+                free(*s);
+                *s = t;
+        }
+
+        return l;
+}
+
+int reset_all_signal_handlers(void) {
+        int sig;
+
+        for (sig = 1; sig < _NSIG; sig++) {
+                struct sigaction sa;
+
+                if (sig == SIGKILL || sig == SIGSTOP)
+                        continue;
+
+                zero(sa);
+                sa.sa_handler = SIG_DFL;
+                sa.sa_flags = SA_RESTART;
+
+                /* On Linux the first two RT signals are reserved by
+                 * glibc, and sigaction() will return EINVAL for them. */
+                if ((sigaction(sig, &sa, NULL) < 0))
+                        if (errno != EINVAL)
+                                return -errno;
+        }
+
+        return 0;
+}
+
+char *strstrip(char *s) {
+        char *e, *l = NULL;
+
+        /* Drops trailing whitespace. Modifies the string in
+         * place. Returns pointer to first non-space character */
+
+        s += strspn(s, WHITESPACE);
+
+        for (e = s; *e; e++)
+                if (!strchr(WHITESPACE, *e))
+                        l = e;
+
+        if (l)
+                *(l+1) = 0;
+        else
+                *s = 0;
+
+        return s;
+}
+
+char *delete_chars(char *s, const char *bad) {
+        char *f, *t;
+
+        /* Drops all whitespace, regardless where in the string */
+
+        for (f = s, t = s; *f; f++) {
+                if (strchr(bad, *f))
+                        continue;
+
+                *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return s;
+}
+
+char *file_in_same_dir(const char *path, const char *filename) {
+        char *e, *r;
+        size_t k;
+
+        assert(path);
+        assert(filename);
+
+        /* This removes the last component of path and appends
+         * filename, unless the latter is absolute anyway or the
+         * former isn't */
+
+        if (path_is_absolute(filename))
+                return strdup(filename);
+
+        if (!(e = strrchr(path, '/')))
+                return strdup(filename);
+
+        k = strlen(filename);
+        if (!(r = new(char, e-path+1+k+1)))
+                return NULL;
+
+        memcpy(r, path, e-path+1);
+        memcpy(r+(e-path)+1, filename, k+1);
+
+        return r;
+}
+
+int mkdir_parents(const char *path, mode_t mode) {
+        const char *p, *e;
+
+        assert(path);
+
+        /* Creates every parent directory in the path except the last
+         * component. */
+
+        p = path + strspn(path, "/");
+        for (;;) {
+                int r;
+                char *t;
+
+                e = p + strcspn(p, "/");
+                p = e + strspn(e, "/");
+
+                /* Is this the last component? If so, then we're
+                 * done */
+                if (*p == 0)
+                        return 0;
+
+                if (!(t = strndup(path, e - path)))
+                        return -ENOMEM;
+
+                r = mkdir(t, mode);
+
+                free(t);
+
+                if (r < 0 && errno != EEXIST)
+                        return -errno;
+        }
+}
+
+int mkdir_p(const char *path, mode_t mode) {
+        int r;
+
+        /* Like mkdir -p */
+
+        if ((r = mkdir_parents(path, mode)) < 0)
+                return r;
+
+        if (mkdir(path, mode) < 0)
+                return -errno;
+
+        return 0;
+}
+
+char hexchar(int x) {
+        static const char table[16] = "0123456789abcdef";
+
+        return table[x & 15];
+}
+
+int unhexchar(char c) {
+
+        if (c >= '0' && c <= '9')
+                return c - '0';
+
+        if (c >= 'a' && c <= 'f')
+                return c - 'a' + 10;
+
+        if (c >= 'A' && c <= 'F')
+                return c - 'A' + 10;
+
+        return -1;
+}
+
+char octchar(int x) {
+        return '0' + (x & 7);
+}
+
+int unoctchar(char c) {
+
+        if (c >= '0' && c <= '7')
+                return c - '0';
+
+        return -1;
+}
+
+char decchar(int x) {
+        return '0' + (x % 10);
+}
+
+int undecchar(char c) {
+
+        if (c >= '0' && c <= '9')
+                return c - '0';
+
+        return -1;
+}
+
+char *cescape(const char *s) {
+        char *r, *t;
+        const char *f;
+
+        assert(s);
+
+        /* Does C style string escaping. */
+
+        if (!(r = new(char, strlen(s)*4 + 1)))
+                return NULL;
+
+        for (f = s, t = r; *f; f++)
+
+                switch (*f) {
+
+                case '\a':
+                        *(t++) = '\\';
+                        *(t++) = 'a';
+                        break;
+                case '\b':
+                        *(t++) = '\\';
+                        *(t++) = 'b';
+                        break;
+                case '\f':
+                        *(t++) = '\\';
+                        *(t++) = 'f';
+                        break;
+                case '\n':
+                        *(t++) = '\\';
+                        *(t++) = 'n';
+                        break;
+                case '\r':
+                        *(t++) = '\\';
+                        *(t++) = 'r';
+                        break;
+                case '\t':
+                        *(t++) = '\\';
+                        *(t++) = 't';
+                        break;
+                case '\v':
+                        *(t++) = '\\';
+                        *(t++) = 'v';
+                        break;
+                case '\\':
+                        *(t++) = '\\';
+                        *(t++) = '\\';
+                        break;
+                case '"':
+                        *(t++) = '\\';
+                        *(t++) = '"';
+                        break;
+                case '\'':
+                        *(t++) = '\\';
+                        *(t++) = '\'';
+                        break;
+
+                default:
+                        /* For special chars we prefer octal over
+                         * hexadecimal encoding, simply because glib's
+                         * g_strescape() does the same */
+                        if ((*f < ' ') || (*f >= 127)) {
+                                *(t++) = '\\';
+                                *(t++) = octchar((unsigned char) *f >> 6);
+                                *(t++) = octchar((unsigned char) *f >> 3);
+                                *(t++) = octchar((unsigned char) *f);
+                        } else
+                                *(t++) = *f;
+                        break;
+                }
+
+        *t = 0;
+
+        return r;
+}
+
+char *cunescape(const char *s) {
+        char *r, *t;
+        const char *f;
+
+        assert(s);
+
+        /* Undoes C style string escaping */
+
+        if (!(r = new(char, strlen(s)+1)))
+                return r;
+
+        for (f = s, t = r; *f; f++) {
+
+                if (*f != '\\') {
+                        *(t++) = *f;
+                        continue;
+                }
+
+                f++;
+
+                switch (*f) {
+
+                case 'a':
+                        *(t++) = '\a';
+                        break;
+                case 'b':
+                        *(t++) = '\b';
+                        break;
+                case 'f':
+                        *(t++) = '\f';
+                        break;
+                case 'n':
+                        *(t++) = '\n';
+                        break;
+                case 'r':
+                        *(t++) = '\r';
+                        break;
+                case 't':
+                        *(t++) = '\t';
+                        break;
+                case 'v':
+                        *(t++) = '\v';
+                        break;
+                case '\\':
+                        *(t++) = '\\';
+                        break;
+                case '"':
+                        *(t++) = '"';
+                        break;
+                case '\'':
+                        *(t++) = '\'';
+                        break;
+
+                case 'x': {
+                        /* hexadecimal encoding */
+                        int a, b;
+
+                        if ((a = unhexchar(f[1])) < 0 ||
+                            (b = unhexchar(f[2])) < 0) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '\\';
+                                *(t++) = 'x';
+                        } else {
+                                *(t++) = (char) ((a << 4) | b);
+                                f += 2;
+                        }
+
+                        break;
+                }
+
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7': {
+                        /* octal encoding */
+                        int a, b, c;
+
+                        if ((a = unoctchar(f[0])) < 0 ||
+                            (b = unoctchar(f[1])) < 0 ||
+                            (c = unoctchar(f[2])) < 0) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '\\';
+                                *(t++) = f[0];
+                        } else {
+                                *(t++) = (char) ((a << 6) | (b << 3) | c);
+                                f += 2;
+                        }
+
+                        break;
+                }
+
+                case 0:
+                        /* premature end of string.*/
+                        *(t++) = '\\';
+                        goto finish;
+
+                default:
+                        /* Invalid escape code, let's take it literal then */
+                        *(t++) = '\\';
+                        *(t++) = 'f';
+                        break;
+                }
+        }
+
+finish:
+        *t = 0;
+        return r;
+}
+
+
+char *xescape(const char *s, const char *bad) {
+        char *r, *t;
+        const char *f;
+
+        /* Escapes all chars in bad, in addition to \ and all special
+         * chars, in \xFF style escaping. May be reversed with
+         * cunescape. */
+
+        if (!(r = new(char, strlen(s)*4+1)))
+                return NULL;
+
+        for (f = s, t = r; *f; f++) {
+
+                if ((*f < ' ') || (*f >= 127) ||
+                    (*f == '\\') || strchr(bad, *f)) {
+                        *(t++) = '\\';
+                        *(t++) = 'x';
+                        *(t++) = hexchar(*f >> 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+char *bus_path_escape(const char *s) {
+        char *r, *t;
+        const char *f;
+
+        assert(s);
+
+        /* Escapes all chars that D-Bus' object path cannot deal
+         * with. Can be reverse with bus_path_unescape() */
+
+        if (!(r = new(char, strlen(s)*3+1)))
+                return NULL;
+
+        for (f = s, t = r; *f; f++) {
+
+                if (!(*f >= 'A' && *f <= 'Z') &&
+                    !(*f >= 'a' && *f <= 'z') &&
+                    !(*f >= '0' && *f <= '9')) {
+                        *(t++) = '_';
+                        *(t++) = hexchar(*f >> 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+char *bus_path_unescape(const char *f) {
+        char *r, *t;
+
+        assert(f);
+
+        if (!(r = strdup(f)))
+                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;
+}
+
+char *path_kill_slashes(char *path) {
+        char *f, *t;
+        bool slash = false;
+
+        /* Removes redundant inner and trailing slashes. Modifies the
+         * passed string in-place.
+         *
+         * ///foo///bar/ becomes /foo/bar
+         */
+
+        for (f = path, t = path; *f; f++) {
+
+                if (*f == '/') {
+                        slash = true;
+                        continue;
+                }
+
+                if (slash) {
+                        slash = false;
+                        *(t++) = '/';
+                }
+
+                *(t++) = *f;
+        }
+
+        /* Special rule, if we are talking of the root directory, a
+        trailing slash is good */
+
+        if (t == path && slash)
+                *(t++) = '/';
+
+        *t = 0;
+        return path;
+}
+
+bool path_startswith(const char *path, const char *prefix) {
+        assert(path);
+        assert(prefix);
+
+        if ((path[0] == '/') != (prefix[0] == '/'))
+                return false;
+
+        for (;;) {
+                size_t a, b;
+
+                path += strspn(path, "/");
+                prefix += strspn(prefix, "/");
+
+                if (*prefix == 0)
+                        return true;
+
+                if (*path == 0)
+                        return false;
+
+                a = strcspn(path, "/");
+                b = strcspn(prefix, "/");
+
+                if (a != b)
+                        return false;
+
+                if (memcmp(path, prefix, a) != 0)
+                        return false;
+
+                path += a;
+                prefix += b;
+        }
+}
+
+bool path_equal(const char *a, const char *b) {
+        assert(a);
+        assert(b);
+
+        if ((a[0] == '/') != (b[0] == '/'))
+                return false;
+
+        for (;;) {
+                size_t j, k;
+
+                a += strspn(a, "/");
+                b += strspn(b, "/");
+
+                if (*a == 0 && *b == 0)
+                        return true;
+
+                if (*a == 0 || *b == 0)
+                        return false;
+
+                j = strcspn(a, "/");
+                k = strcspn(b, "/");
+
+                if (j != k)
+                        return false;
+
+                if (memcmp(a, b, j) != 0)
+                        return false;
+
+                a += j;
+                b += k;
+        }
+}
+
+char *ascii_strlower(char *t) {
+        char *p;
+
+        assert(t);
+
+        for (p = t; *p; p++)
+                if (*p >= 'A' && *p <= 'Z')
+                        *p = *p - 'A' + 'a';
+
+        return t;
+}
+
+bool ignore_file(const char *filename) {
+        assert(filename);
+
+        return
+                filename[0] == '.' ||
+                streq(filename, "lost+found") ||
+                endswith(filename, "~") ||
+                endswith(filename, ".rpmnew") ||
+                endswith(filename, ".rpmsave") ||
+                endswith(filename, ".rpmorig") ||
+                endswith(filename, ".dpkg-old") ||
+                endswith(filename, ".dpkg-new") ||
+                endswith(filename, ".swp");
+}
+
+int fd_nonblock(int fd, bool nonblock) {
+        int flags;
+
+        assert(fd >= 0);
+
+        if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
+                return -errno;
+
+        if (nonblock)
+                flags |= O_NONBLOCK;
+        else
+                flags &= ~O_NONBLOCK;
+
+        if (fcntl(fd, F_SETFL, flags) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int fd_cloexec(int fd, bool cloexec) {
+        int flags;
+
+        assert(fd >= 0);
+
+        if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
+                return -errno;
+
+        if (cloexec)
+                flags |= FD_CLOEXEC;
+        else
+                flags &= ~FD_CLOEXEC;
+
+        if (fcntl(fd, F_SETFD, flags) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int close_all_fds(const int except[], unsigned n_except) {
+        DIR *d;
+        struct dirent *de;
+        int r = 0;
+
+        if (!(d = opendir("/proc/self/fd")))
+                return -errno;
+
+        while ((de = readdir(d))) {
+                int fd = -1;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                if ((r = safe_atoi(de->d_name, &fd)) < 0)
+                        goto finish;
+
+                if (fd < 3)
+                        continue;
+
+                if (fd == dirfd(d))
+                        continue;
+
+                if (except) {
+                        bool found;
+                        unsigned i;
+
+                        found = false;
+                        for (i = 0; i < n_except; i++)
+                                if (except[i] == fd) {
+                                        found = true;
+                                        break;
+                                }
+
+                        if (found)
+                                continue;
+                }
+
+                if ((r = close_nointr(fd)) < 0) {
+                        /* Valgrind has its own FD and doesn't want to have it closed */
+                        if (errno != EBADF)
+                                goto finish;
+                }
+        }
+
+        r = 0;
+
+finish:
+        closedir(d);
+        return r;
+}
+
+bool chars_intersect(const char *a, const char *b) {
+        const char *p;
+
+        /* Returns true if any of the chars in a are in b. */
+        for (p = a; *p; p++)
+                if (strchr(b, *p))
+                        return true;
+
+        return false;
+}
+
+char *format_timestamp(char *buf, size_t l, usec_t t) {
+        struct tm tm;
+        time_t sec;
+
+        assert(buf);
+        assert(l > 0);
+
+        if (t <= 0)
+                return NULL;
+
+        sec = (time_t) t / USEC_PER_SEC;
+
+        if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0)
+                return NULL;
+
+        return buf;
+}
+
+bool fstype_is_network(const char *fstype) {
+        static const char * const table[] = {
+                "cifs",
+                "smbfs",
+                "ncpfs",
+                "nfs",
+                "nfs4",
+                "gfs",
+                "gfs2"
+        };
+
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (streq(table[i], fstype))
+                        return true;
+
+        return false;
+}
+
+int chvt(int vt) {
+        int fd, r = 0;
+
+        if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
+                return -errno;
+
+        if (vt < 0) {
+                int tiocl[2] = {
+                        TIOCL_GETKMSGREDIRECT,
+                        0
+                };
+
+                if (ioctl(fd, TIOCLINUX, tiocl) < 0)
+                        return -errno;
+
+                vt = tiocl[0] <= 0 ? 1 : tiocl[0];
+        }
+
+        if (ioctl(fd, VT_ACTIVATE, vt) < 0)
+                r = -errno;
+
+        close_nointr_nofail(r);
+        return r;
+}
+
+int read_one_char(FILE *f, char *ret, bool *need_nl) {
+        struct termios old_termios, new_termios;
+        char c;
+        char line[1024];
+
+        assert(f);
+        assert(ret);
+
+        if (tcgetattr(fileno(f), &old_termios) >= 0) {
+                new_termios = old_termios;
+
+                new_termios.c_lflag &= ~ICANON;
+                new_termios.c_cc[VMIN] = 1;
+                new_termios.c_cc[VTIME] = 0;
+
+                if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
+                        size_t k;
+
+                        k = fread(&c, 1, 1, f);
+
+                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
+
+                        if (k <= 0)
+                                return -EIO;
+
+                        if (need_nl)
+                                *need_nl = c != '\n';
+
+                        *ret = c;
+                        return 0;
+                }
+        }
+
+        if (!(fgets(line, sizeof(line), f)))
+                return -EIO;
+
+        truncate_nl(line);
+
+        if (strlen(line) != 1)
+                return -EBADMSG;
+
+        if (need_nl)
+                *need_nl = false;
+
+        *ret = line[0];
+        return 0;
+}
+
+int ask(char *ret, const char *replies, const char *text, ...) {
+        assert(ret);
+        assert(replies);
+        assert(text);
+
+        for (;;) {
+                va_list ap;
+                char c;
+                int r;
+                bool need_nl = true;
+
+                fputs("\x1B[1m", stdout);
+
+                va_start(ap, text);
+                vprintf(text, ap);
+                va_end(ap);
+
+                fputs("\x1B[0m", stdout);
+
+                fflush(stdout);
+
+                if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
+
+                        if (r == -EBADMSG) {
+                                puts("Bad input, please try again.");
+                                continue;
+                        }
+
+                        putchar('\n');
+                        return r;
+                }
+
+                if (need_nl)
+                        putchar('\n');
+
+                if (strchr(replies, c)) {
+                        *ret = c;
+                        return 0;
+                }
+
+                puts("Read unexpected character, please try again.");
+        }
+}
+
+int reset_terminal(int fd) {
+        struct termios termios;
+        int r = 0;
+
+        assert(fd >= 0);
+
+        /* Set terminal to some sane defaults */
+
+        if (tcgetattr(fd, &termios) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        /* We only reset the stuff that matters to the software. How
+         * hardware is set up we don't touch assuming that somebody
+         * else will do that for us */
+
+        termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
+        termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
+        termios.c_oflag |= ONLCR;
+        termios.c_cflag |= CREAD;
+        termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
+
+        termios.c_cc[VINTR]    =   03;  /* ^C */
+        termios.c_cc[VQUIT]    =  034;  /* ^\ */
+        termios.c_cc[VERASE]   = 0177;
+        termios.c_cc[VKILL]    =  025;  /* ^X */
+        termios.c_cc[VEOF]     =   04;  /* ^D */
+        termios.c_cc[VSTART]   =  021;  /* ^Q */
+        termios.c_cc[VSTOP]    =  023;  /* ^S */
+        termios.c_cc[VSUSP]    =  032;  /* ^Z */
+        termios.c_cc[VLNEXT]   =  026;  /* ^V */
+        termios.c_cc[VWERASE]  =  027;  /* ^W */
+        termios.c_cc[VREPRINT] =  022;  /* ^R */
+        termios.c_cc[VEOL]     =    0;
+        termios.c_cc[VEOL2]    =    0;
+
+        termios.c_cc[VTIME]  = 0;
+        termios.c_cc[VMIN]   = 1;
+
+        if (tcsetattr(fd, TCSANOW, &termios) < 0)
+                r = -errno;
+
+finish:
+        /* Just in case, flush all crap out */
+        tcflush(fd, TCIOFLUSH);
+
+        return r;
+}
+
+int open_terminal(const char *name, int mode) {
+        int fd, r;
+
+        if ((fd = open(name, mode)) < 0)
+                return -errno;
+
+        if ((r = isatty(fd)) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        if (!r) {
+                close_nointr_nofail(fd);
+                return -ENOTTY;
+        }
+
+        return fd;
+}
+
+int flush_fd(int fd) {
+        struct pollfd pollfd;
+
+        zero(pollfd);
+        pollfd.fd = fd;
+        pollfd.events = POLLIN;
+
+        for (;;) {
+                char buf[1024];
+                ssize_t l;
+                int r;
+
+                if ((r = poll(&pollfd, 1, 0)) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+                }
+
+                if (r == 0)
+                        return 0;
+
+                if ((l = read(fd, buf, sizeof(buf))) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        if (errno == EAGAIN)
+                                return 0;
+
+                        return -errno;
+                }
+
+                if (l <= 0)
+                        return 0;
+        }
+}
+
+int acquire_terminal(const char *name, bool fail, bool force) {
+        int fd = -1, notify = -1, r, wd = -1;
+
+        assert(name);
+
+        /* We use inotify to be notified when the tty is closed. We
+         * create the watch before checking if we can actually acquire
+         * it, so that we don't lose any event.
+         *
+         * Note: strictly speaking this actually watches for the
+         * device being closed, it does *not* really watch whether a
+         * tty loses its controlling process. However, unless some
+         * rogue process uses TIOCNOTTY on /dev/tty *after* closing
+         * its tty otherwise this will not become a problem. As long
+         * as the administrator makes sure not configure any service
+         * on the same tty as an untrusted user this should not be a
+         * problem. (Which he probably should not do anyway.) */
+
+        if (!fail && !force) {
+                if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+        }
+
+        for (;;) {
+                if (notify >= 0)
+                        if ((r = flush_fd(notify)) < 0)
+                                goto fail;
+
+                /* We pass here O_NOCTTY only so that we can check the return
+                 * value TIOCSCTTY and have a reliable way to figure out if we
+                 * successfully became the controlling process of the tty */
+                if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
+                        return -errno;
+
+                /* First, try to get the tty */
+                if ((r = ioctl(fd, TIOCSCTTY, force)) < 0 &&
+                    (force || fail || errno != EPERM)) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                if (r >= 0)
+                        break;
+
+                assert(!fail);
+                assert(!force);
+                assert(notify >= 0);
+
+                for (;;) {
+                        struct inotify_event e;
+                        ssize_t l;
+
+                        if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
+
+                                if (l < 0) {
+
+                                        if (errno == EINTR)
+                                                continue;
+
+                                        r = -errno;
+                                } else
+                                        r = -EIO;
+
+                                goto fail;
+                        }
+
+                        if (e.wd != wd || !(e.mask & IN_CLOSE)) {
+                                r = -errno;
+                                goto fail;
+                        }
+
+                        break;
+                }
+
+                /* We close the tty fd here since if the old session
+                 * ended our handle will be dead. It's important that
+                 * we do this after sleeping, so that we don't enter
+                 * an endless loop. */
+                close_nointr_nofail(fd);
+        }
+
+        if (notify >= 0)
+                close_nointr_nofail(notify);
+
+        if ((r = reset_terminal(fd)) < 0)
+                log_warning("Failed to reset terminal: %s", strerror(-r));
+
+        return fd;
+
+fail:
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        if (notify >= 0)
+                close_nointr_nofail(notify);
+
+        return r;
+}
+
+int release_terminal(void) {
+        int r = 0, fd;
+        struct sigaction sa_old, sa_new;
+
+        if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
+                return -errno;
+
+        /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
+         * by our own TIOCNOTTY */
+
+        zero(sa_new);
+        sa_new.sa_handler = SIG_IGN;
+        sa_new.sa_flags = SA_RESTART;
+        assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
+
+        if (ioctl(fd, TIOCNOTTY) < 0)
+                r = -errno;
+
+        assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
+
+        close_nointr_nofail(fd);
+        return r;
+}
+
+int ignore_signal(int sig) {
+        struct sigaction sa;
+
+        zero(sa);
+        sa.sa_handler = SIG_IGN;
+        sa.sa_flags = SA_RESTART;
+
+        return sigaction(sig, &sa, NULL);
+}
+
+int close_pipe(int p[]) {
+        int a = 0, b = 0;
+
+        assert(p);
+
+        if (p[0] >= 0) {
+                a = close_nointr(p[0]);
+                p[0] = -1;
+        }
+
+        if (p[1] >= 0) {
+                b = close_nointr(p[1]);
+                p[1] = -1;
+        }
+
+        return a < 0 ? a : b;
+}
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes) {
+        uint8_t *p;
+        ssize_t n = 0;
+
+        assert(fd >= 0);
+        assert(buf);
+
+        p = buf;
+
+        while (nbytes > 0) {
+                ssize_t k;
+
+                if ((k = read(fd, p, nbytes)) <= 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        if (errno == EAGAIN) {
+                                struct pollfd pollfd;
+
+                                zero(pollfd);
+                                pollfd.fd = fd;
+                                pollfd.events = POLLIN;
+
+                                if (poll(&pollfd, 1, -1) < 0) {
+                                        if (errno == EINTR)
+                                                continue;
+
+                                        return n > 0 ? n : -errno;
+                                }
+
+                                if (pollfd.revents != POLLIN)
+                                        return n > 0 ? n : -EIO;
+
+                                continue;
+                        }
+
+                        return n > 0 ? n : (k < 0 ? -errno : 0);
+                }
+
+                p += k;
+                nbytes -= k;
+                n += k;
+        }
+
+        return n;
+}
+
+int path_is_mount_point(const char *t) {
+        struct stat a, b;
+        char *copy;
+
+        if (lstat(t, &a) < 0) {
+
+                if (errno == ENOENT)
+                        return 0;
+
+                return -errno;
+        }
+
+        if (!(copy = strdup(t)))
+                return -ENOMEM;
+
+        if (lstat(dirname(copy), &b) < 0) {
+                free(copy);
+                return -errno;
+        }
+
+        free(copy);
+
+        return a.st_dev != b.st_dev;
+}
+
+int parse_usec(const char *t, usec_t *usec) {
+        static const struct {
+                const char *suffix;
+                usec_t usec;
+        } table[] = {
+                { "sec", USEC_PER_SEC },
+                { "s", USEC_PER_SEC },
+                { "min", USEC_PER_MINUTE },
+                { "hr", USEC_PER_HOUR },
+                { "h", USEC_PER_HOUR },
+                { "d", USEC_PER_DAY },
+                { "w", USEC_PER_WEEK },
+                { "msec", USEC_PER_MSEC },
+                { "ms", USEC_PER_MSEC },
+                { "m", USEC_PER_MINUTE },
+                { "usec", 1ULL },
+                { "us", 1ULL },
+                { "", USEC_PER_SEC },
+        };
+
+        const char *p;
+        usec_t r = 0;
+
+        assert(t);
+        assert(usec);
+
+        p = t;
+        do {
+                long long l;
+                char *e;
+                unsigned i;
+
+                errno = 0;
+                l = strtoll(p, &e, 10);
+
+                if (errno != 0)
+                        return -errno;
+
+                if (l < 0)
+                        return -ERANGE;
+
+                if (e == p)
+                        return -EINVAL;
+
+                e += strspn(e, WHITESPACE);
+
+                for (i = 0; i < ELEMENTSOF(table); i++)
+                        if (startswith(e, table[i].suffix)) {
+                                r += (usec_t) l * table[i].usec;
+                                p = e + strlen(table[i].suffix);
+                                break;
+                        }
+
+                if (i >= ELEMENTSOF(table))
+                        return -EINVAL;
+
+        } while (*p != 0);
+
+        *usec = r;
+
+        return 0;
+}
+
+int make_stdio(int fd) {
+        int r, s, t;
+
+        assert(fd >= 0);
+
+        r = dup2(fd, STDIN_FILENO);
+        s = dup2(fd, STDOUT_FILENO);
+        t = dup2(fd, STDERR_FILENO);
+
+        if (fd >= 3)
+                close_nointr_nofail(fd);
+
+        if (r < 0 || s < 0 || t < 0)
+                return -errno;
+
+        return 0;
+}
+
+bool is_clean_exit(int code, int status) {
+
+        if (code == CLD_EXITED)
+                return status == 0;
+
+        /* If a daemon does not implement handlers for some of the
+         * signals that's not considered an unclean shutdown */
+        if (code == CLD_KILLED)
+                return
+                        status == SIGHUP ||
+                        status == SIGINT ||
+                        status == SIGTERM ||
+                        status == SIGPIPE;
+
+        return false;
+}
+
+bool is_device_path(const char *path) {
+
+        /* Returns true on paths that refer to a device, either in
+         * sysfs or in /dev */
+
+        return
+                path_startswith(path, "/dev/") ||
+                path_startswith(path, "/sys/");
+}
+
+static const char *const ioprio_class_table[] = {
+        [IOPRIO_CLASS_NONE] = "none",
+        [IOPRIO_CLASS_RT] = "realtime",
+        [IOPRIO_CLASS_BE] = "best-effort",
+        [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
+
+static const char *const sigchld_code_table[] = {
+        [CLD_EXITED] = "exited",
+        [CLD_KILLED] = "killed",
+        [CLD_DUMPED] = "dumped",
+        [CLD_TRAPPED] = "trapped",
+        [CLD_STOPPED] = "stopped",
+        [CLD_CONTINUED] = "continued",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
+
+static const char *const log_facility_table[LOG_NFACILITIES] = {
+        [LOG_FAC(LOG_KERN)] = "kern",
+        [LOG_FAC(LOG_USER)] = "user",
+        [LOG_FAC(LOG_MAIL)] = "mail",
+        [LOG_FAC(LOG_DAEMON)] = "daemon",
+        [LOG_FAC(LOG_AUTH)] = "auth",
+        [LOG_FAC(LOG_SYSLOG)] = "syslog",
+        [LOG_FAC(LOG_LPR)] = "lpr",
+        [LOG_FAC(LOG_NEWS)] = "news",
+        [LOG_FAC(LOG_UUCP)] = "uucp",
+        [LOG_FAC(LOG_CRON)] = "cron",
+        [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
+        [LOG_FAC(LOG_FTP)] = "ftp",
+        [LOG_FAC(LOG_LOCAL0)] = "local0",
+        [LOG_FAC(LOG_LOCAL1)] = "local1",
+        [LOG_FAC(LOG_LOCAL2)] = "local2",
+        [LOG_FAC(LOG_LOCAL3)] = "local3",
+        [LOG_FAC(LOG_LOCAL4)] = "local4",
+        [LOG_FAC(LOG_LOCAL5)] = "local5",
+        [LOG_FAC(LOG_LOCAL6)] = "local6",
+        [LOG_FAC(LOG_LOCAL7)] = "local7"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
+
+static const char *const log_level_table[] = {
+        [LOG_EMERG] = "emerg",
+        [LOG_ALERT] = "alert",
+        [LOG_CRIT] = "crit",
+        [LOG_ERR] = "err",
+        [LOG_WARNING] = "warning",
+        [LOG_NOTICE] = "notice",
+        [LOG_INFO] = "info",
+        [LOG_DEBUG] = "debug"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(log_level, int);
+
+static const char* const sched_policy_table[] = {
+        [SCHED_OTHER] = "other",
+        [SCHED_BATCH] = "batch",
+        [SCHED_IDLE] = "idle",
+        [SCHED_FIFO] = "fifo",
+        [SCHED_RR] = "rr"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
+
+static const char* const rlimit_table[] = {
+        [RLIMIT_CPU] = "LimitCPU",
+        [RLIMIT_FSIZE] = "LimitFSIZE",
+        [RLIMIT_DATA] = "LimitDATA",
+        [RLIMIT_STACK] = "LimitSTACK",
+        [RLIMIT_CORE] = "LimitCORE",
+        [RLIMIT_RSS] = "LimitRSS",
+        [RLIMIT_NOFILE] = "LimitNOFILE",
+        [RLIMIT_AS] = "LimitAS",
+        [RLIMIT_NPROC] = "LimitNPROC",
+        [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
+        [RLIMIT_LOCKS] = "LimitLOCKS",
+        [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
+        [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
+        [RLIMIT_NICE] = "LimitNICE",
+        [RLIMIT_RTPRIO] = "LimitRTPRIO",
+        [RLIMIT_RTTIME] = "LimitRTTIME"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..a77a952
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,256 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooutilhfoo
+#define fooutilhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef uint64_t usec_t;
+
+#define MSEC_PER_SEC  1000ULL
+#define USEC_PER_SEC  1000000ULL
+#define USEC_PER_MSEC 1000ULL
+#define NSEC_PER_SEC  1000000000ULL
+#define NSEC_PER_MSEC 1000000ULL
+#define NSEC_PER_USEC 1000ULL
+
+#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC)
+#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE)
+#define USEC_PER_DAY (24ULL*USEC_PER_HOUR)
+#define USEC_PER_WEEK (7ULL*USEC_PER_DAY)
+
+/* What is interpreted as whitespace? */
+#define WHITESPACE " \t\n\r"
+#define NEWLINE "\n\r"
+
+#define FORMAT_TIMESTAMP_MAX 64
+
+usec_t now(clockid_t clock);
+
+usec_t timespec_load(const struct timespec *ts);
+struct timespec *timespec_store(struct timespec *ts, usec_t u);
+
+usec_t timeval_load(const struct timeval *tv);
+struct timeval *timeval_store(struct timeval *tv, usec_t u);
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+bool streq_ptr(const char *a, const char *b);
+
+#define new(t, n) ((t*) malloc(sizeof(t)*(n)))
+
+#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+
+#define malloc0(n) (calloc((n), 1))
+
+static inline const char* yes_no(bool b) {
+        return b ? "yes" : "no";
+}
+
+static inline const char* strempty(const char *s) {
+        return s ? s : "";
+}
+
+static inline const char* strnull(const char *s) {
+        return s ? s : "(null)";
+}
+
+static inline const char *strna(const char *s) {
+        return s ? s : "n/a";
+}
+
+static inline bool is_path_absolute(const char *p) {
+        return *p == '/';
+}
+
+bool endswith(const char *s, const char *postfix);
+bool startswith(const char *s, const char *prefix);
+bool startswith_no_case(const char *s, const char *prefix);
+
+bool first_word(const char *s, const char *word);
+
+int close_nointr(int fd);
+void close_nointr_nofail(int fd);
+
+int parse_boolean(const char *v);
+int parse_usec(const char *t, usec_t *usec);
+
+int safe_atou(const char *s, unsigned *ret_u);
+int safe_atoi(const char *s, int *ret_i);
+
+int safe_atolu(const char *s, unsigned long *ret_u);
+int safe_atoli(const char *s, long int *ret_i);
+
+int safe_atollu(const char *s, unsigned long long *ret_u);
+int safe_atolli(const char *s, long long int *ret_i);
+
+char *split(const char *c, size_t *l, const char *separator, char **state);
+char *split_quoted(const char *c, size_t *l, char **state);
+
+#define FOREACH_WORD(word, length, s, state)                            \
+        for ((state) = NULL, (word) = split((s), &(length), WHITESPACE, &(state)); (word); (word) = split((s), &(length), WHITESPACE, &(state)))
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
+        for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state)))
+
+#define FOREACH_WORD_QUOTED(word, length, s, state)                     \
+        for ((state) = NULL, (word) = split_quoted((s), &(length), &(state)); (word); (word) = split_quoted((s), &(length), &(state)))
+
+char **split_path_and_make_absolute(const char *p);
+
+pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
+
+int write_one_line_file(const char *fn, const char *line);
+int read_one_line_file(const char *fn, char **line);
+
+char *strappend(const char *s, const char *suffix);
+
+int readlink_malloc(const char *p, char **r);
+
+char *file_name_from_path(const char *p);
+bool is_path(const char *p);
+
+bool path_is_absolute(const char *p);
+char *path_make_absolute(const char *p, const char *prefix);
+char *path_make_absolute_cwd(const char *p);
+char **strv_path_make_absolute_cwd(char **l);
+
+int reset_all_signal_handlers(void);
+
+char *strstrip(char *s);
+char *delete_chars(char *s, const char *bad);
+char *truncate_nl(char *s);
+
+char *file_in_same_dir(const char *path, const char *filename);
+int mkdir_parents(const char *path, mode_t mode);
+int mkdir_p(const char *path, mode_t mode);
+
+int get_process_name(pid_t pid, char **name);
+
+char hexchar(int x);
+int unhexchar(char c);
+char octchar(int x);
+int unoctchar(char c);
+char decchar(int x);
+int undecchar(char c);
+
+char *cescape(const char *s);
+char *cunescape(const char *s);
+
+char *path_kill_slashes(char *path);
+
+bool path_startswith(const char *path, const char *prefix);
+bool path_equal(const char *a, const char *b);
+
+char *ascii_strlower(char *path);
+
+char *xescape(const char *s, const char *bad);
+
+char *bus_path_escape(const char *s);
+char *bus_path_unescape(const char *s);
+
+bool ignore_file(const char *filename);
+
+bool chars_intersect(const char *a, const char *b);
+
+char *format_timestamp(char *buf, size_t l, usec_t t);
+
+int make_stdio(int fd);
+
+bool is_clean_exit(int code, int status);
+
+#define DEFINE_STRING_TABLE_LOOKUP(name,type)                           \
+        const char *name##_to_string(type i) {                          \
+                if (i < 0 || i >= (type) ELEMENTSOF(name##_table))      \
+                        return NULL;                                    \
+                return name##_table[i];                                 \
+        }                                                               \
+        type name##_from_string(const char *s) {                        \
+                type i;                                                 \
+                unsigned u = 0;                                         \
+                assert(s);                                              \
+                for (i = 0; i < (type)ELEMENTSOF(name##_table); i++)    \
+                        if (streq(name##_table[i], s))                  \
+                                return i;                               \
+                if (safe_atou(s, &u) >= 0 &&                            \
+                    u < ELEMENTSOF(name##_table))                       \
+                        return (type) u;                                \
+                return (type) -1;                                       \
+        }                                                               \
+        struct __useless_struct_to_allow_trailing_semicolon__
+
+
+int fd_nonblock(int fd, bool nonblock);
+int fd_cloexec(int fd, bool cloexec);
+
+int close_all_fds(const int except[], unsigned n_except);
+
+bool fstype_is_network(const char *fstype);
+
+int chvt(int vt);
+
+int read_one_char(FILE *f, char *ret, bool *need_nl);
+int ask(char *ret, const char *replies, const char *text, ...);
+
+int reset_terminal(int fd);
+int open_terminal(const char *name, int mode);
+int acquire_terminal(const char *name, bool fail, bool force);
+int release_terminal(void);
+
+int flush_fd(int fd);
+
+int ignore_signal(int sig);
+
+int close_pipe(int p[]);
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes);
+
+int path_is_mount_point(const char *path);
+
+bool is_device_path(const char *path);
+
+extern char * __progname;
+
+const char *ioprio_class_to_string(int i);
+int ioprio_class_from_string(const char *s);
+
+const char *sigchld_code_to_string(int i);
+int sigchld_code_from_string(const char *s);
+
+const char *log_facility_to_string(int i);
+int log_facility_from_string(const char *s);
+
+const char *log_level_to_string(int i);
+int log_level_from_string(const char *s);
+
+const char *sched_policy_to_string(int i);
+int sched_policy_from_string(const char *s);
+
+const char *rlimit_to_string(int i);
+int rlimit_from_string(const char *s);
+
+#endif
diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c
new file mode 100644
index 0000000..cb3f201
--- /dev/null
+++ b/src/utmp-wtmp.c
@@ -0,0 +1,214 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <utmpx.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+#include "macro.h"
+#include "utmp-wtmp.h"
+
+int utmp_get_runlevel(int *runlevel, int *previous) {
+        struct utmpx lookup, *found;
+        int r;
+        const char *e;
+
+        assert(runlevel);
+
+        /* If these values are set in the environment this takes
+         * precedence. Presumably, sysvinit does this to work around a
+         * race condition that would otherwise exist where we'd always
+         * go to disk and hence might read runlevel data that might be
+         * very new and does not apply to the current script being
+         * executed. */
+
+        if ((e = getenv("RUNLEVEL")) && e[0] > 0) {
+                *runlevel = e[0];
+
+                if (previous) {
+                        /* $PREVLEVEL seems to be an Upstart thing */
+
+                        if ((e = getenv("PREVLEVEL")) && e[0] > 0)
+                                *previous = e[0];
+                        else
+                                *previous = 0;
+                }
+
+                return 0;
+        }
+
+        if (utmpxname(_PATH_UTMPX) < 0)
+                return -errno;
+
+        setutxent();
+
+        zero(lookup);
+        lookup.ut_type = RUN_LVL;
+
+        if (!(found = getutxid(&lookup)))
+                r = -errno;
+        else {
+                int a, b;
+
+                a = found->ut_pid & 0xFF;
+                b = (found->ut_pid >> 8) & 0xFF;
+
+                if (a < 0 || b < 0)
+                        r = -EIO;
+                else {
+                        *runlevel = a;
+
+                        if (previous)
+                                *previous = b;
+                        r = 0;
+                }
+        }
+
+        endutxent();
+
+        return r;
+}
+
+static void init_entry(struct utmpx *store, usec_t timestamp) {
+        struct utsname uts;
+
+        assert(store);
+
+        zero(*store);
+        zero(uts);
+
+        if (timestamp <= 0)
+                timestamp = now(CLOCK_REALTIME);
+
+        store->ut_tv.tv_sec = timestamp / USEC_PER_SEC;
+        store->ut_tv.tv_usec = timestamp % USEC_PER_SEC;
+
+        if (uname(&uts) >= 0)
+                strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
+
+        strncpy(store->ut_line, "~", sizeof(store->ut_line));  /* or ~~ ? */
+        strncpy(store->ut_id, "~~", sizeof(store->ut_id));
+}
+
+static int write_entry_utmp(const struct utmpx *store) {
+        int r;
+
+        assert(store);
+
+        /* utmp is similar to wtmp, but there is only one entry for
+         * each entry type resp. user; i.e. basically a key/value
+         * table. */
+
+        if (utmpxname(_PATH_UTMPX) < 0)
+                return -errno;
+
+        setutxent();
+
+        if (!pututxline(store))
+                r = -errno;
+        else
+                r = 0;
+
+        endutxent();
+
+        return r;
+}
+
+static int write_entry_wtmp(const struct utmpx *store) {
+        assert(store);
+
+        /* wtmp is a simple append-only file where each entry is
+        simply appended to * the end; i.e. basically a log. */
+
+        errno = 0;
+        updwtmpx(_PATH_WTMPX, store);
+        return -errno;
+}
+
+static int write_entry_both(const struct utmpx *store) {
+        int r, s;
+
+        r = write_entry_utmp(store);
+        s = write_entry_wtmp(store);
+
+        if (r >= 0)
+                r = s;
+
+        /* If utmp/wtmp have been disabled, that's a good thing, hence
+         * ignore the errors */
+        if (r == -ENOENT)
+                r = 0;
+
+        return r;
+}
+
+int utmp_put_shutdown(usec_t timestamp) {
+        struct utmpx store;
+
+        init_entry(&store, timestamp);
+
+        store.ut_type = RUN_LVL;
+        strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
+
+        return write_entry_both(&store);
+}
+
+int utmp_put_reboot(usec_t timestamp) {
+        struct utmpx store;
+
+        init_entry(&store, timestamp);
+
+        store.ut_type = BOOT_TIME;
+        strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
+
+        return write_entry_both(&store);
+}
+
+int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous) {
+        struct utmpx store;
+        int r;
+
+        assert(runlevel > 0);
+
+        if (previous <= 0) {
+                /* Find the old runlevel automatically */
+
+                if ((r = utmp_get_runlevel(&previous, NULL)) < 0) {
+                        if (r != -ESRCH)
+                                return r;
+
+                        previous = 0;
+                }
+
+                if (previous == runlevel)
+                        return 0;
+        }
+
+        init_entry(&store, timestamp);
+
+        store.ut_type = RUN_LVL;
+        store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
+        strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
+
+        return write_entry_both(&store);
+}
diff --git a/src/utmp-wtmp.h b/src/utmp-wtmp.h
new file mode 100644
index 0000000..34c3222
--- /dev/null
+++ b/src/utmp-wtmp.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef fooutmpwtmphfoo
+#define fooutmpwtmphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+int utmp_get_runlevel(int *runlevel, int *previous);
+
+int utmp_put_shutdown(usec_t timestamp);
+int utmp_put_reboot(usec_t timestamp);
+int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous);
+
+#endif
diff --git a/strv.c b/strv.c
deleted file mode 100644
index a749096..0000000
--- a/strv.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-
-#include "util.h"
-#include "strv.h"
-
-char *strv_find(char **l, const char *name) {
-        char **i;
-
-        assert(l);
-        assert(name);
-
-        STRV_FOREACH(i, l)
-                if (streq(*i, name))
-                        return *i;
-
-        return NULL;
-}
-
-void strv_free(char **l) {
-        char **k;
-
-        if (!l)
-                return;
-
-        for (k = l; *k; k++)
-                free(*k);
-
-        free(l);
-}
-
-char **strv_copy(char **l) {
-        char **r, **k;
-
-        if (!(r = new(char*, strv_length(l)+1)))
-                return NULL;
-
-        for (k = r; *l; k++, l++)
-                if (!(*k = strdup(*l)))
-                        goto fail;
-
-        *k = NULL;
-        return r;
-
-fail:
-        for (k--, l--; k >= r; k--, l--)
-                free(*k);
-
-        return NULL;
-}
-
-unsigned strv_length(char **l) {
-        unsigned n = 0;
-
-        if (!l)
-                return 0;
-
-        for (; *l; l++)
-                n++;
-
-        return n;
-}
-
-char **strv_new_ap(const char *x, va_list ap) {
-        const char *s;
-        char **a;
-        unsigned n = 0, i = 0;
-        va_list aq;
-
-
-        if (x) {
-                n = 1;
-
-                va_copy(aq, ap);
-                while (va_arg(aq, const char*))
-                        n++;
-                va_end(aq);
-        }
-
-        if (!(a = new(char*, n+1)))
-                return NULL;
-
-        if (x) {
-                if (!(a[i] = strdup(x))) {
-                        free(a);
-                        return NULL;
-                }
-
-                i++;
-
-                while ((s = va_arg(ap, const char*))) {
-                        if (!(a[i] = strdup(s)))
-                                goto fail;
-
-                        i++;
-                }
-        }
-
-        a[i] = NULL;
-
-        return a;
-
-fail:
-
-        for (; i > 0; i--)
-                if (a[i-1])
-                        free(a[i-1]);
-
-        free(a);
-
-        return NULL;
-}
-
-char **strv_new(const char *x, ...) {
-        char **r;
-        va_list ap;
-
-        va_start(ap, x);
-        r = strv_new_ap(x, ap);
-        va_end(ap);
-
-        return r;
-}
-
-char **strv_merge(char **a, char **b) {
-        char **r, **k;
-
-        if (!a)
-                return strv_copy(b);
-
-        if (!b)
-                return strv_copy(a);
-
-        if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
-                return NULL;
-
-        for (k = r; *a; k++, a++)
-                if (!(*k = strdup(*a)))
-                        goto fail;
-        for (; *b; k++, b++)
-                if (!(*k = strdup(*b)))
-                        goto fail;
-
-        *k = NULL;
-        return r;
-
-fail:
-        for (k--; k >= r; k--)
-                free(*k);
-
-        free(r);
-
-        return NULL;
-}
-
-char **strv_merge_concat(char **a, char **b, const char *suffix) {
-        char **r, **k;
-
-        /* Like strv_merge(), but appends suffix to all strings in b, before adding */
-
-        if (!b)
-                return strv_copy(a);
-
-        if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
-                return NULL;
-
-        for (k = r; *a; k++, a++)
-                if (!(*k = strdup(*a)))
-                        goto fail;
-        for (; *b; k++, b++)
-                if (!(*k = strappend(*b, suffix)))
-                        goto fail;
-
-        *k = NULL;
-        return r;
-
-fail:
-        for (k--; k >= r; k--)
-                free(*k);
-
-        free(r);
-
-        return NULL;
-
-}
-
-char **strv_split(const char *s, const char *separator) {
-        char *state;
-        char *w;
-        size_t l;
-        unsigned n, i;
-        char **r;
-
-        assert(s);
-
-        n = 0;
-        FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
-                n++;
-
-        if (!(r = new(char*, n+1)))
-                return NULL;
-
-        i = 0;
-        FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
-                if (!(r[i++] = strndup(w, l))) {
-                        strv_free(r);
-                        return NULL;
-                }
-
-        r[i] = NULL;
-        return r;
-}
-
-char **strv_split_quoted(const char *s) {
-        char *state;
-        char *w;
-        size_t l;
-        unsigned n, i;
-        char **r;
-
-        assert(s);
-
-        n = 0;
-        FOREACH_WORD_QUOTED(w, l, s, state)
-                n++;
-
-        if (!(r = new(char*, n+1)))
-                return NULL;
-
-        i = 0;
-        FOREACH_WORD_QUOTED(w, l, s, state)
-                if (!(r[i++] = strndup(w, l))) {
-                        strv_free(r);
-                        return NULL;
-                }
-
-        r[i] = NULL;
-        return r;
-}
-
-char *strv_join(char **l, const char *separator) {
-        char *r, *e;
-        char **s;
-        size_t n, k;
-
-        if (!separator)
-                separator = " ";
-
-        k = strlen(separator);
-
-        n = 0;
-        STRV_FOREACH(s, l) {
-                if (n != 0)
-                        n += k;
-                n += strlen(*s);
-        }
-
-        if (!(r = new(char, n+1)))
-                return NULL;
-
-        e = r;
-        STRV_FOREACH(s, l) {
-                if (e != r)
-                        e = stpcpy(e, separator);
-
-                e = stpcpy(e, *s);
-        }
-
-        *e = 0;
-
-        return r;
-}
-
-char **strv_append(char **l, const char *s) {
-        char **r, **k;
-
-        if (!l)
-                return strv_new(s, NULL);
-
-        if (!s)
-                return strv_copy(l);
-
-        if (!(r = new(char*, strv_length(l)+2)))
-                return NULL;
-
-        for (k = r; *l; k++, l++)
-                if (!(*k = strdup(*l)))
-                        goto fail;
-
-        if (!(*(k++) = strdup(s)))
-                goto fail;
-
-        *k = NULL;
-        return r;
-
-fail:
-        for (k--; k >= r; k--)
-                free(*k);
-
-        free(r);
-
-        return NULL;
-}
-
-char **strv_uniq(char **l) {
-        char **i;
-
-        /* Drops duplicate entries. The first identical string will be
-         * kept, the others dropped */
-
-        STRV_FOREACH(i, l)
-                strv_remove(i+1, *i);
-
-        return l;
-}
-
-char **strv_remove(char **l, const char *s) {
-        char **f, **t;
-
-        if (!l)
-                return NULL;
-
-        /* Drops every occurence of s in the string list */
-
-        for (f = t = l; *f; f++) {
-
-                if (streq(*f, s)) {
-                        free(*f);
-                        continue;
-                }
-
-                *(t++) = *f;
-        }
-
-        *t = NULL;
-        return l;
-}
-
-static int env_append(char **r, char ***k, char **a) {
-        assert(r);
-        assert(k);
-        assert(a);
-
-        /* Add the entries of a to *k unless they already exist in *r
-         * in which case they are overriden instead. This assumes
-         * there is enough space in the r */
-
-        for (; *a; a++) {
-                char **j;
-                size_t n = strcspn(*a, "=") + 1;
-
-                for (j = r; j < *k; j++)
-                        if (strncmp(*j, *a, n) == 0)
-                                break;
-
-                if (j >= *k)
-                        (*k)++;
-                else
-                        free(*j);
-
-                if (!(*j = strdup(*a)))
-                        return -ENOMEM;
-        }
-
-        return 0;
-}
-
-char **strv_env_merge(char **x, ...) {
-        size_t n = 0;
-        char **l, **k, **r;
-        va_list ap;
-
-        /* Merges an arbitrary number of environment sets */
-
-        if (x) {
-                n += strv_length(x);
-
-                va_start(ap, x);
-                while ((l = va_arg(ap, char**)))
-                        n += strv_length(l);
-                va_end(ap);
-        }
-
-
-        if (!(r = new(char*, n+1)))
-                return NULL;
-
-        k = r;
-
-        if (x) {
-                if (env_append(r, &k, x) < 0)
-                        goto fail;
-
-                va_start(ap, x);
-                while ((l = va_arg(ap, char**)))
-                        if (env_append(r, &k, l) < 0)
-                                goto fail;
-                va_end(ap);
-        }
-
-        *k = NULL;
-
-        return r;
-
-fail:
-        for (k--; k >= r; k--)
-                free(*k);
-
-        free(r);
-
-        return NULL;
-}
-
-static bool env_match(const char *t, const char *pattern) {
-        assert(t);
-        assert(pattern);
-
-        /* pattern a matches string a
-         *         a matches a=
-         *         a matches a=b
-         *         a= matches a=
-         *         a=b matches a=b
-         *         a= does not match a
-         *         a=b does not match a=
-         *         a=b does not match a
-         *         a=b does not match a=c */
-
-        if (streq(t, pattern))
-                return true;
-
-        if (!strchr(pattern, '=')) {
-                size_t l = strlen(pattern);
-
-                return strncmp(t, pattern, l) == 0 && t[l] == '=';
-        }
-
-        return false;
-}
-
-char **strv_env_delete(char **x, ...) {
-        size_t n = 0, i = 0;
-        char **l, **k, **r, **j;
-        va_list ap;
-
-        /* Deletes every entry fromx that is mentioned in the other
-         * string lists */
-
-        n = strv_length(x);
-
-        if (!(r = new(char*, n+1)))
-                return NULL;
-
-        STRV_FOREACH(k, x) {
-                va_start(ap, x);
-
-                while ((l = va_arg(ap, char**)))
-                        STRV_FOREACH(j, l)
-                                if (env_match(*k, *j))
-                                        goto delete;
-
-                va_end(ap);
-
-                if (!(r[i++] = strdup(*k))) {
-                        strv_free(r);
-                        return NULL;
-                }
-
-                continue;
-
-        delete:
-                va_end(ap);
-        }
-
-        r[i] = NULL;
-
-        assert(i <= n);
-
-        return r;
-}
diff --git a/strv.h b/strv.h
deleted file mode 100644
index f0be83d..0000000
--- a/strv.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foostrvhfoo
-#define foostrvhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdarg.h>
-#include <stdbool.h>
-
-#include "macro.h"
-
-char *strv_find(char **l, const char *name);
-void strv_free(char **l);
-char **strv_copy(char **l) _malloc;
-unsigned strv_length(char **l);
-
-char **strv_merge(char **a, char **b);
-char **strv_merge_concat(char **a, char **b, const char *suffix);
-char **strv_append(char **l, const char *s);
-
-char **strv_remove(char **l, const char *s);
-char **strv_uniq(char **l);
-
-#define strv_contains(l, s) (!!strv_find((l), (s)))
-
-char **strv_new(const char *x, ...) _sentinel _malloc;
-char **strv_new_ap(const char *x, va_list ap) _malloc;
-
-static inline bool strv_isempty(char **l) {
-        return !l || !*l;
-}
-
-char **strv_split(const char *s, const char *separator) _malloc;
-char **strv_split_quoted(const char *s) _malloc;
-
-char *strv_join(char **l, const char *separator) _malloc;
-
-char **strv_env_merge(char **x, ...) _sentinel;
-char **strv_env_delete(char **x, ...) _sentinel;
-
-#define STRV_FOREACH(s, l)                      \
-        for ((s) = (l); (s) && *(s); (s)++)
-
-#define STRV_FOREACH_BACKWARDS(s, l)            \
-        for (; (l) && ((s) >= (l)); (s)--)
-
-#endif
diff --git a/swap.c b/swap.c
deleted file mode 100644
index bd49e1e..0000000
--- a/swap.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <sys/swap.h>
-
-#include "unit.h"
-#include "swap.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "unit-name.h"
-#include "dbus-swap.h"
-
-static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
-        [SWAP_DEAD] = UNIT_INACTIVE,
-        [SWAP_ACTIVE] = UNIT_ACTIVE,
-        [SWAP_MAINTAINANCE] = UNIT_INACTIVE
-};
-
-static void swap_init(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(s->meta.load_state == UNIT_STUB);
-
-        s->parameters_etc_fstab.priority = s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
-}
-
-static void swap_done(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        free(s->what);
-        free(s->parameters_etc_fstab.what);
-        free(s->parameters_proc_swaps.what);
-        free(s->parameters_fragment.what);
-}
-
-int swap_add_one_mount_link(Swap *s, Mount *m) {
-         int r;
-
-        assert(s);
-        assert(m);
-
-        if (s->meta.load_state != UNIT_LOADED ||
-            m->meta.load_state != UNIT_LOADED)
-                return 0;
-
-        if (is_device_path(s->what))
-                return 0;
-
-        if (!path_startswith(s->what, m->where))
-                return 0;
-
-        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
-                return r;
-
-        if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
-                return r;
-
-        return 0;
-}
-
-static int swap_add_mount_links(Swap *s) {
-        Meta *other;
-        int r;
-
-        assert(s);
-
-        LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_MOUNT])
-                if ((r = swap_add_one_mount_link(s, (Mount*) other)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int swap_add_target_links(Swap *s) {
-        Unit *tu;
-        SwapParameters *p;
-        int r;
-
-        assert(s);
-
-        if (s->from_fragment)
-                p = &s->parameters_fragment;
-        else if (s->from_etc_fstab)
-                p = &s->parameters_etc_fstab;
-        else
-                return 0;
-
-        if ((r = manager_load_unit(s->meta.manager, SPECIAL_SWAP_TARGET, NULL, &tu)) < 0)
-                return r;
-
-        if (!p->noauto && p->handle)
-                if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(s), true)) < 0)
-                        return r;
-
-        return unit_add_dependency(UNIT(s), UNIT_BEFORE, tu, true);
-}
-
-static int swap_verify(Swap *s) {
-        bool b;
-        char *e;
-
-        if (UNIT(s)->meta.load_state != UNIT_LOADED)
-                  return 0;
-
-        if (!(e = unit_name_from_path(s->what, ".swap")))
-                  return -ENOMEM;
-
-        b = unit_has_name(UNIT(s), e);
-        free(e);
-
-        if (!b) {
-                log_error("%s: Value of \"What\" and unit name do not match, not loading.\n", UNIT(s)->meta.id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int swap_load(Unit *u) {
-        int r;
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(u->meta.load_state == UNIT_STUB);
-
-        /* Load a .swap file */
-        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
-                return r;
-
-        if (u->meta.load_state == UNIT_LOADED) {
-
-                if (s->meta.fragment_path)
-                        s->from_fragment = true;
-
-                if (!s->what) {
-                        if (s->parameters_fragment.what)
-                                s->what = strdup(s->parameters_fragment.what);
-                        else if (s->parameters_etc_fstab.what)
-                                s->what = strdup(s->parameters_etc_fstab.what);
-                        else if (s->parameters_proc_swaps.what)
-                                s->what = strdup(s->parameters_proc_swaps.what);
-                        else
-                                s->what = unit_name_to_path(u->meta.id);
-
-                        if (!s->what)
-                                return -ENOMEM;
-                }
-
-                path_kill_slashes(s->what);
-
-                if (!s->meta.description)
-                        if ((r = unit_set_description(u, s->what)) < 0)
-                                return r;
-
-                if ((r = unit_add_node_link(u, s->what,
-                                            (u->meta.manager->running_as == MANAGER_INIT ||
-                                             u->meta.manager->running_as == MANAGER_SYSTEM))) < 0)
-                        return r;
-
-                if ((r = swap_add_mount_links(s)) < 0)
-                        return r;
-
-                if ((r = swap_add_target_links(s)) < 0)
-                        return r;
-        }
-
-        return swap_verify(s);
-}
-
-static int swap_find(Manager *m, const char *what, Unit **_u) {
-        Unit *u;
-        char *e;
-
-        assert(m);
-        assert(what);
-        assert(_u);
-
-        /* /proc/swaps and /etc/fstab might refer to this device by
-         * different names (e.g. one by uuid, the other by the kernel
-         * name), we hence need to look for all aliases we are aware
-         * of for this device */
-
-        if (!(e = unit_name_from_path(what, ".device")))
-                return -ENOMEM;
-
-        u = manager_get_unit(m, e);
-        free(e);
-
-        if (u) {
-                Iterator i;
-                const char *d;
-
-                SET_FOREACH(d, u->meta.names, i) {
-                        Unit *k;
-
-                        if (!(e = unit_name_change_suffix(d, ".swap")))
-                                return -ENOMEM;
-
-                        k = manager_get_unit(m, e);
-                        free(e);
-
-                        if (k) {
-                                *_u = k;
-                                return 0;
-                        }
-                }
-        }
-
-        *_u = NULL;
-        return 0;
-}
-
-int swap_add_one(
-                Manager *m,
-                const char *what,
-                int priority,
-                bool noauto,
-                bool handle,
-                bool from_proc_swaps) {
-        Unit *u = NULL;
-        char *e = NULL, *w = NULL;
-        bool delete;
-        int r;
-        SwapParameters *p;
-
-        assert(m);
-        assert(what);
-
-        if (!(e = unit_name_from_path(what, ".swap")))
-                return -ENOMEM;
-
-        if (!(u = manager_get_unit(m, e)))
-                if ((r = swap_find(m, what, &u)) < 0)
-                        goto fail;
-
-        if (!u) {
-                delete = true;
-
-                if (!(u = unit_new(m))) {
-                        free(e);
-                        return -ENOMEM;
-                }
-        } else
-                delete = false;
-
-        if ((r = unit_add_name(u, e)) < 0)
-                goto fail;
-
-        if (!(w = strdup(what))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (from_proc_swaps) {
-                p = &SWAP(u)->parameters_proc_swaps;
-                SWAP(u)->from_proc_swaps = true;
-        } else {
-                p = &SWAP(u)->parameters_etc_fstab;
-                SWAP(u)->from_etc_fstab = true;
-        }
-
-        free(p->what);
-        p->what = w;
-
-        p->priority = priority;
-        p->noauto = noauto;
-        p->handle = handle;
-
-        if (delete)
-                unit_add_to_load_queue(u);
-
-        unit_add_to_dbus_queue(u);
-
-        free(e);
-
-        return 0;
-
-fail:
-        free(w);
-        free(e);
-
-        if (delete && u)
-                unit_free(u);
-
-        return r;
-}
-
-static void swap_set_state(Swap *s, SwapState state) {
-        SwapState old_state;
-        assert(s);
-
-        old_state = s->state;
-        s->state = state;
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(s)->meta.id,
-                          swap_state_to_string(old_state),
-                          swap_state_to_string(state));
-
-        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int swap_coldplug(Unit *u) {
-        Swap *s = SWAP(u);
-        SwapState new_state = SWAP_DEAD;
-
-        assert(s);
-        assert(s->state == SWAP_DEAD);
-
-        if (s->deserialized_state != s->state)
-                new_state = s->deserialized_state;
-        else if (s->from_proc_swaps)
-                new_state = SWAP_ACTIVE;
-
-        if (new_state != s->state)
-                swap_set_state(s, new_state);
-
-        return 0;
-}
-
-static void swap_dump(Unit *u, FILE *f, const char *prefix) {
-        Swap *s = SWAP(u);
-        SwapParameters *p;
-
-        assert(s);
-        assert(f);
-
-        if (s->from_proc_swaps)
-                p = &s->parameters_proc_swaps;
-        else if (s->from_fragment)
-                p = &s->parameters_fragment;
-        else
-                p = &s->parameters_etc_fstab;
-
-        fprintf(f,
-                "%sSwap State: %s\n"
-                "%sWhat: %s\n"
-                "%sPriority: %i\n"
-                "%sNoAuto: %s\n"
-                "%sHandle: %s\n"
-                "%sFrom /etc/fstab: %s\n"
-                "%sFrom /proc/swaps: %s\n"
-                "%sFrom fragment: %s\n",
-                prefix, swap_state_to_string(s->state),
-                prefix, s->what,
-                prefix, p->priority,
-                prefix, yes_no(p->noauto),
-                prefix, yes_no(p->handle),
-                prefix, yes_no(s->from_etc_fstab),
-                prefix, yes_no(s->from_proc_swaps),
-                prefix, yes_no(s->from_fragment));
-}
-
-static void swap_enter_dead(Swap *s, bool success) {
-        assert(s);
-
-        swap_set_state(s, success ? SWAP_MAINTAINANCE : SWAP_DEAD);
-}
-
-static int swap_start(Unit *u) {
-        Swap *s = SWAP(u);
-        int priority = -1;
-        int r;
-
-        assert(s);
-        assert(s->state == SWAP_DEAD || s->state == SWAP_MAINTAINANCE);
-
-        if (s->from_fragment)
-                priority = s->parameters_fragment.priority;
-        else if (s->from_etc_fstab)
-                priority = s->parameters_etc_fstab.priority;
-
-        r = swapon(s->what, (priority << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK);
-
-        if (r < 0 && errno != EBUSY) {
-                r = -errno;
-                swap_enter_dead(s, false);
-                return r;
-        }
-
-        swap_set_state(s, SWAP_ACTIVE);
-        return 0;
-}
-
-static int swap_stop(Unit *u) {
-        Swap *s = SWAP(u);
-        int r;
-
-        assert(s);
-
-        assert(s->state == SWAP_ACTIVE);
-
-        r = swapoff(s->what);
-        swap_enter_dead(s, r >= 0 || errno == EINVAL);
-
-        return 0;
-}
-
-static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", swap_state_to_string(s->state));
-
-        return 0;
-}
-
-static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                SwapState state;
-
-                if ((state = swap_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        s->deserialized_state = state;
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState swap_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[SWAP(u)->state];
-}
-
-static const char *swap_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return swap_state_to_string(SWAP(u)->state);
-}
-
-static bool swap_check_gc(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        return s->from_etc_fstab || s->from_proc_swaps;
-}
-
-static int swap_load_proc_swaps(Manager *m) {
-        rewind(m->proc_swaps);
-
-        (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
-
-        for (;;) {
-                char *dev = NULL, *d;
-                int prio = 0, k;
-
-                if ((k = fscanf(m->proc_swaps,
-                                "%ms " /* device/file */
-                                "%*s " /* type of swap */
-                                "%*s " /* swap size */
-                                "%*s " /* used */
-                                "%i\n", /* priority */
-                                &dev, &prio)) != 2) {
-
-                        if (k == EOF)
-                                break;
-
-                        free(dev);
-                        return -EBADMSG;
-                }
-
-                d = cunescape(dev);
-                free(dev);
-
-                if (!d)
-                        return -ENOMEM;
-
-                k = swap_add_one(m, d, prio, false, false, true);
-                free(d);
-
-                if (k < 0)
-                        return k;
-        }
-
-        return 0;
-}
-
-static void swap_shutdown(Manager *m) {
-        assert(m);
-
-        if (m->proc_swaps) {
-                fclose(m->proc_swaps);
-                m->proc_swaps = NULL;
-        }
-}
-
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
-        [SWAP_DEAD] = "dead",
-        [SWAP_ACTIVE] = "active",
-        [SWAP_MAINTAINANCE] = "maintainance"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
-static int swap_enumerate(Manager *m) {
-        int r;
-        assert(m);
-
-        if (!m->proc_swaps)
-                if (!(m->proc_swaps = fopen("/proc/swaps", "re")))
-                        return -errno;
-
-        if ((r = swap_load_proc_swaps(m)) < 0)
-                swap_shutdown(m);
-
-        return r;
-}
-
-const UnitVTable swap_vtable = {
-        .suffix = ".swap",
-
-        .no_instances = true,
-        .no_isolate = true,
-
-        .init = swap_init,
-        .load = swap_load,
-        .done = swap_done,
-
-        .coldplug = swap_coldplug,
-
-        .dump = swap_dump,
-
-        .start = swap_start,
-        .stop = swap_stop,
-
-        .serialize = swap_serialize,
-        .deserialize_item = swap_deserialize_item,
-
-        .active_state = swap_active_state,
-        .sub_state_to_string = swap_sub_state_to_string,
-
-        .check_gc = swap_check_gc,
-
-        .bus_message_handler = bus_swap_message_handler,
-
-        .enumerate = swap_enumerate,
-        .shutdown = swap_shutdown
-};
diff --git a/swap.h b/swap.h
deleted file mode 100644
index f54a9ee..0000000
--- a/swap.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooswaphfoo
-#define fooswaphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-  Copyright 2010 Maarten Lankhorst
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Swap Swap;
-
-#include "unit.h"
-
-typedef enum SwapState {
-        SWAP_DEAD,
-        SWAP_ACTIVE,
-        SWAP_MAINTAINANCE,
-        _SWAP_STATE_MAX,
-        _SWAP_STATE_INVALID = -1
-} SwapState;
-
-typedef struct SwapParameters {
-        char *what;
-        int priority;
-        bool noauto:1;
-        bool handle:1;
-} SwapParameters;
-
-struct Swap {
-        Meta meta;
-
-        SwapParameters parameters_etc_fstab;
-        SwapParameters parameters_proc_swaps;
-        SwapParameters parameters_fragment;
-
-        char *what;
-
-        bool from_etc_fstab:1;
-        bool from_proc_swaps:1;
-        bool from_fragment:1;
-
-        SwapState state, deserialized_state;
-};
-
-extern const UnitVTable swap_vtable;
-
-int swap_add_one(Manager *m, const char *what, int prio, bool no_auto, bool handle, bool from_proc_swap);
-
-int swap_add_one_mount_link(Swap *s, Mount *m);
-
-const char* swap_state_to_string(SwapState i);
-SwapState swap_state_from_string(const char *s);
-
-
-#endif
diff --git a/systemadm.vala b/systemadm.vala
deleted file mode 100644
index bd0062a..0000000
--- a/systemadm.vala
+++ /dev/null
@@ -1,956 +0,0 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-using Gtk;
-using GLib;
-using DBus;
-using Pango;
-
-static bool session = false;
-
-public class LeftLabel : Label {
-        public LeftLabel(string? text = null) {
-                if (text != null)
-                        set_markup("<b>%s</b>".printf(text));
-                set_alignment(0, 0);
-                set_padding(6, 0);
-        }
-}
-
-public class RightLabel : Label {
-        public RightLabel(string? text = null) {
-                set_text_or_na(text);
-                set_alignment(0, 0);
-                set_ellipsize(EllipsizeMode.START);
-                set_selectable(true);
-        }
-
-        public void set_text_or_na(string? text = null) {
-                if (text == null || text == "")
-                        set_markup("<i>n/a</i>");
-                else
-                        set_text(text);
-        }
-
-        public void set_markup_or_na(string? text = null) {
-                if (text == null || text == "")
-                        set_markup("<i>n/a</i>");
-                else
-                        set_markup(text);
-        }
-}
-
-public class MainWindow : Window {
-
-        private string? current_unit_id;
-        private uint32 current_job_id;
-
-        private TreeView unit_view;
-        private TreeView job_view;
-
-        private ListStore unit_model;
-        private ListStore job_model;
-
-        private Button start_button;
-        private Button stop_button;
-        private Button restart_button;
-        private Button reload_button;
-        private Button cancel_button;
-
-        private Entry unit_load_entry;
-        private Button unit_load_button;
-
-        private Button server_snapshot_button;
-        private Button server_reload_button;
-
-        private Connection bus;
-        private Manager manager;
-
-        private RightLabel unit_id_label;
-        private RightLabel unit_aliases_label;
-        private RightLabel unit_dependency_label;
-        private RightLabel unit_description_label;
-        private RightLabel unit_load_state_label;
-        private RightLabel unit_active_state_label;
-        private RightLabel unit_sub_state_label;
-        private RightLabel unit_fragment_path_label;
-        private RightLabel unit_active_enter_timestamp_label;
-        private RightLabel unit_active_exit_timestamp_label;
-        private RightLabel unit_can_start_label;
-        private RightLabel unit_can_reload_label;
-        private RightLabel unit_cgroup_label;
-
-        private RightLabel job_id_label;
-        private RightLabel job_state_label;
-        private RightLabel job_type_label;
-
-        private ComboBox unit_type_combo_box;
-
-        public MainWindow() throws DBus.Error {
-                title = session ? "systemd Session Manager" : "systemd System Manager";
-                position = WindowPosition.CENTER;
-                set_default_size(1000, 700);
-                set_border_width(12);
-                destroy += Gtk.main_quit;
-
-                Notebook notebook = new Notebook();
-                add(notebook);
-
-                Box unit_vbox = new VBox(false, 12);
-                notebook.append_page(unit_vbox, new Label("Units"));
-                unit_vbox.set_border_width(12);
-
-                Box job_vbox = new VBox(false, 12);
-                notebook.append_page(job_vbox, new Label("Jobs"));
-                job_vbox.set_border_width(12);
-
-                unit_type_combo_box = new ComboBox.text();
-                Box type_hbox = new HBox(false, 6);
-                type_hbox.pack_start(unit_type_combo_box, false, false, 0);
-                unit_vbox.pack_start(type_hbox, false, false, 0);
-
-                unit_type_combo_box.append_text("Show All Units");
-                unit_type_combo_box.append_text("Show Only Live Units");
-                unit_type_combo_box.append_text("Services");
-                unit_type_combo_box.append_text("Sockets");
-                unit_type_combo_box.append_text("Devices");
-                unit_type_combo_box.append_text("Mounts");
-                unit_type_combo_box.append_text("Automounts");
-                unit_type_combo_box.append_text("Targets");
-                unit_type_combo_box.append_text("Snapshots");
-                unit_type_combo_box.set_active(1);
-                unit_type_combo_box.changed += unit_type_changed;
-
-                unit_load_entry = new Entry();
-                unit_load_button = new Button.with_mnemonic("_Load");
-                unit_load_button.set_sensitive(false);
-
-                unit_load_entry.changed += on_unit_load_entry_changed;
-                unit_load_entry.activate += on_unit_load;
-                unit_load_button.clicked += on_unit_load;
-
-                Box unit_load_hbox = new HBox(false, 6);
-                unit_load_hbox.pack_start(unit_load_entry, false, true, 0);
-                unit_load_hbox.pack_start(unit_load_button, false, true, 0);
-
-                server_snapshot_button = new Button.with_mnemonic("Take S_napshot");
-                server_reload_button = new Button.with_mnemonic("Reload _Configuration");
-
-                server_snapshot_button.clicked += on_server_snapshot;
-                server_reload_button.clicked += on_server_reload;
-
-                type_hbox.pack_end(server_snapshot_button, false, true, 0);
-                type_hbox.pack_end(server_reload_button, false, true, 0);
-                type_hbox.pack_end(unit_load_hbox, false, true, 24);
-
-                unit_model = new ListStore(7, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(Unit));
-                job_model = new ListStore(6, typeof(string), typeof(string), typeof(string), typeof(string), typeof(Job), typeof(uint32));
-
-                TreeModelFilter unit_model_filter;
-                unit_model_filter = new TreeModelFilter(unit_model, null);
-                unit_model_filter.set_visible_func(unit_filter);
-
-                unit_view = new TreeView.with_model(unit_model_filter);
-                job_view = new TreeView.with_model(job_model);
-
-                unit_view.cursor_changed += unit_changed;
-                job_view.cursor_changed += job_changed;
-
-                unit_view.insert_column_with_attributes(-1, "Load State", new CellRendererText(), "text", 2);
-                unit_view.insert_column_with_attributes(-1, "Active State", new CellRendererText(), "text", 3);
-                unit_view.insert_column_with_attributes(-1, "Unit State", new CellRendererText(), "text", 4);
-                unit_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 0);
-                unit_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 5);
-
-                job_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 0);
-                job_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 1);
-                job_view.insert_column_with_attributes(-1, "Type", new CellRendererText(), "text", 2);
-                job_view.insert_column_with_attributes(-1, "State", new CellRendererText(), "text", 3);
-
-                ScrolledWindow scroll = new ScrolledWindow(null, null);
-                scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
-                scroll.set_shadow_type(ShadowType.IN);
-                scroll.add(unit_view);
-                unit_vbox.pack_start(scroll, true, true, 0);
-
-                scroll = new ScrolledWindow(null, null);
-                scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
-                scroll.set_shadow_type(ShadowType.IN);
-                scroll.add(job_view);
-                job_vbox.pack_start(scroll, true, true, 0);
-
-                unit_id_label = new RightLabel();
-                unit_aliases_label = new RightLabel();
-                unit_dependency_label = new RightLabel();
-                unit_description_label = new RightLabel();
-                unit_load_state_label = new RightLabel();
-                unit_active_state_label = new RightLabel();
-                unit_sub_state_label = new RightLabel();
-                unit_fragment_path_label = new RightLabel();
-                unit_active_enter_timestamp_label = new RightLabel();
-                unit_active_exit_timestamp_label = new RightLabel();
-                unit_can_start_label = new RightLabel();
-                unit_can_reload_label = new RightLabel();
-                unit_cgroup_label = new RightLabel();
-
-                job_id_label = new RightLabel();
-                job_state_label = new RightLabel();
-                job_type_label = new RightLabel();
-
-                unit_dependency_label.set_track_visited_links(false);
-                unit_dependency_label.set_selectable(false);
-                unit_dependency_label.activate_link += on_activate_link;
-
-                Table unit_table = new Table(8, 6, false);
-                unit_table.set_row_spacings(6);
-                unit_table.set_border_width(0);
-                unit_vbox.pack_start(unit_table, false, true, 0);
-
-                Table job_table = new Table(2, 2, false);
-                job_table.set_row_spacings(6);
-                job_table.set_border_width(0);
-                job_vbox.pack_start(job_table, false, true, 0);
-
-                unit_table.attach(new LeftLabel("Id:"),                     0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_id_label,                            1, 6, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Aliases:"),                0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_aliases_label,                       1, 6, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Description:"),            0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_description_label,                   1, 6, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Dependencies:"),           0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_dependency_label,                    1, 6, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Fragment Path:"),          0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_fragment_path_label,                 1, 6, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Control Group:"),          0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_cgroup_label,                        1, 6, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-
-                unit_table.attach(new LeftLabel("Load State:"),             0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_load_state_label,                    1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Active State:"),           0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_active_state_label,                  1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Unit State:"),             0, 1, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_sub_state_label,                     1, 2, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-
-                unit_table.attach(new LeftLabel("Active Enter Timestamp:"), 2, 3, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_active_enter_timestamp_label,        3, 4, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Active Exit Timestamp:"),  2, 3, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_active_exit_timestamp_label,         3, 4, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-
-                unit_table.attach(new LeftLabel("Can Start/Stop:"),         4, 5, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_can_start_label,                     5, 6, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(new LeftLabel("Can Reload:"),             4, 5, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                unit_table.attach(unit_can_reload_label,                    5, 6, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-
-                job_table.attach(new LeftLabel("Id:"),                      0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                job_table.attach(job_id_label,                              1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                job_table.attach(new LeftLabel("State:"),                   0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                job_table.attach(job_state_label,                           1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                job_table.attach(new LeftLabel("Type:"),                    0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-                job_table.attach(job_type_label,                            1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
-
-                ButtonBox bbox = new HButtonBox();
-                bbox.set_layout(ButtonBoxStyle.START);
-                bbox.set_spacing(6);
-                unit_vbox.pack_start(bbox, false, true, 0);
-
-                start_button = new Button.with_mnemonic("_Start");
-                stop_button = new Button.with_mnemonic("Sto_p");
-                reload_button = new Button.with_mnemonic("_Reload");
-                restart_button = new Button.with_mnemonic("Res_tart");
-
-                start_button.clicked += on_start;
-                stop_button.clicked += on_stop;
-                reload_button.clicked += on_reload;
-                restart_button.clicked += on_restart;
-
-                bbox.pack_start(start_button, false, true, 0);
-                bbox.pack_start(stop_button, false, true, 0);
-                bbox.pack_start(restart_button, false, true, 0);
-                bbox.pack_start(reload_button, false, true, 0);
-
-                bbox = new HButtonBox();
-                bbox.set_layout(ButtonBoxStyle.START);
-                bbox.set_spacing(6);
-                job_vbox.pack_start(bbox, false, true, 0);
-
-                cancel_button = new Button.with_mnemonic("_Cancel");
-
-                cancel_button.clicked += on_cancel;
-
-                bbox.pack_start(cancel_button, false, true, 0);
-
-                bus = Bus.get(session ? BusType.SESSION : BusType.SYSTEM);
-
-                manager = bus.get_object(
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager") as Manager;
-
-                manager.unit_new += on_unit_new;
-                manager.job_new += on_job_new;
-                manager.unit_removed += on_unit_removed;
-                manager.job_removed += on_job_removed;
-
-                manager.subscribe();
-
-                clear_unit();
-                clear_job();
-                populate_unit_model();
-                populate_job_model();
-        }
-
-        public void populate_unit_model() throws DBus.Error {
-                unit_model.clear();
-
-                var list = manager.list_units();
-
-                foreach (var i in list) {
-                        TreeIter iter;
-
-                        Unit u = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        i.unit_path,
-                                        "org.freedesktop.systemd1.Unit") as Unit;
-
-                        u.changed += on_unit_changed;
-
-                        unit_model.append(out iter);
-                        unit_model.set(iter,
-                                       0, i.id,
-                                       1, i.description,
-                                       2, i.load_state,
-                                       3, i.active_state,
-                                       4, i.sub_state,
-                                       5, i.job_type != "" ? "→ %s".printf(i.job_type) : "",
-                                       6, u);
-                }
-        }
-
-        public void populate_job_model() throws DBus.Error {
-                job_model.clear();
-
-                var list = manager.list_jobs();
-
-                foreach (var i in list) {
-                        TreeIter iter;
-
-                        Job j = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        i.job_path,
-                                        "org.freedesktop.systemd1.Job") as Job;
-
-                        j.changed += on_job_changed;
-
-                        job_model.append(out iter);
-                        job_model.set(iter,
-                                      0, "%u".printf(i.id),
-                                      1, i.name,
-                                      2, "→ %s".printf(i.type),
-                                      3, i.state,
-                                      4, j,
-                                      5, i.id);
-                }
-        }
-
-        public Unit? get_current_unit() {
-                TreePath p;
-                unit_view.get_cursor(out p, null);
-
-                if (p == null)
-                        return null;
-
-                TreeModel model = unit_view.get_model();
-                TreeIter iter;
-                Unit u;
-
-                model.get_iter(out iter, p);
-                model.get(iter, 6, out u);
-
-                return u;
-        }
-
-        public void unit_changed() {
-                Unit u = get_current_unit();
-
-                if (u == null)
-                        clear_unit();
-                else
-                        show_unit(u);
-        }
-
-        public void clear_unit() {
-                current_unit_id = null;
-
-                start_button.set_sensitive(false);
-                stop_button.set_sensitive(false);
-                reload_button.set_sensitive(false);
-                restart_button.set_sensitive(false);
-
-                unit_id_label.set_text_or_na();
-                unit_aliases_label.set_text_or_na();
-                unit_description_label.set_text_or_na();
-                unit_description_label.set_text_or_na();
-                unit_load_state_label.set_text_or_na();
-                unit_active_state_label.set_text_or_na();
-                unit_sub_state_label.set_text_or_na();
-                unit_fragment_path_label.set_text_or_na();
-                unit_active_enter_timestamp_label.set_text_or_na();
-                unit_active_exit_timestamp_label.set_text_or_na();
-                unit_can_reload_label.set_text_or_na();
-                unit_can_start_label.set_text_or_na();
-                unit_cgroup_label.set_text_or_na();
-        }
-
-        public string make_dependency_string(string? prefix, string word, string[] dependencies) {
-                bool first = true;
-                string r;
-
-                if (prefix == null)
-                        r = "";
-                else
-                        r = prefix;
-
-                foreach (string i in dependencies) {
-                        if (r != "")
-                                r += first ? "\n" : ",";
-
-                        if (first) {
-                                r += word;
-                                first = false;
-                        }
-
-                        r += " <a href=\"" + i + "\">" + i + "</a>";
-                }
-
-                return r;
-        }
-
-        public void show_unit(Unit unit) {
-                current_unit_id = unit.id;
-
-                unit_id_label.set_text_or_na(current_unit_id);
-
-                string a = "";
-                foreach (string i in unit.names) {
-                        if (i == current_unit_id)
-                                continue;
-
-                        if (a == "")
-                                a = i;
-                        else
-                                a += "\n" + i;
-                }
-
-                unit_aliases_label.set_text_or_na(a);
-
-                string[]
-                        requires = unit.requires,
-                        requires_overridable = unit.requires_overridable,
-                        requisite = unit.requisite,
-                        requisite_overridable = unit.requisite_overridable,
-                        wants = unit.wants,
-                        required_by = unit.required_by,
-                        required_by_overridable = unit.required_by_overridable,
-                        wanted_by = unit.wanted_by,
-                        conflicts = unit.conflicts,
-                        before = unit.before,
-                        after = unit.after;
-
-                unit_dependency_label.set_markup_or_na(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(
-                                make_dependency_string(null,
-                                "requires", requires),
-                                "overridable requires", requires_overridable),
-                                "requisite", requisite),
-                                "overridable requisite", requisite_overridable),
-                                "wants", wants),
-                                "conflicts", conflicts),
-                                "required by", required_by),
-                                "overridable required by", required_by_overridable),
-                                "wanted by", wanted_by),
-                                "after", after),
-                                "before", before));
-
-                unit_description_label.set_text_or_na(unit.description);
-                unit_load_state_label.set_text_or_na(unit.load_state);
-                unit_active_state_label.set_text_or_na(unit.active_state);
-                unit_sub_state_label.set_text_or_na(unit.sub_state);
-                unit_fragment_path_label.set_text_or_na(unit.fragment_path);
-
-                uint64 t = unit.active_enter_timestamp;
-                if (t > 0) {
-                        Time timestamp = Time.local((time_t) (t / 1000000));
-                        unit_active_enter_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z"));
-                } else
-                        unit_active_enter_timestamp_label.set_text_or_na();
-
-                t = unit.active_exit_timestamp;
-                if (t > 0) {
-                        Time timestamp = Time.local((time_t) (t / 1000000));
-                        unit_active_exit_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z"));
-                } else
-                        unit_active_exit_timestamp_label.set_text_or_na();
-
-                bool b = unit.can_start;
-                start_button.set_sensitive(b);
-                stop_button.set_sensitive(b);
-                restart_button.set_sensitive(b);
-                unit_can_start_label.set_text_or_na(b ? "Yes" : "No");
-
-                b = unit.can_reload;
-                reload_button.set_sensitive(b);
-                unit_can_reload_label.set_text_or_na(b ? "Yes" : "No");
-
-                unit_cgroup_label.set_text_or_na(unit.default_control_group);
-        }
-
-        public Job? get_current_job() {
-                TreePath p;
-                job_view.get_cursor(out p, null);
-
-                if (p == null)
-                        return null;
-
-                TreeIter iter;
-                TreeModel model = job_view.get_model();
-                Job *j;
-
-                model.get_iter(out iter, p);
-                model.get(iter, 4, out j);
-
-                return j;
-        }
-
-        public void job_changed() {
-                Job j = get_current_job();
-
-                if (j == null)
-                        clear_job();
-                else
-                        show_job(j);
-        }
-
-        public void clear_job() {
-                current_job_id = 0;
-
-                job_id_label.set_text_or_na();
-                job_state_label.set_text_or_na();
-                job_type_label.set_text_or_na();
-
-                cancel_button.set_sensitive(false);
-        }
-
-        public void show_job(Job job) {
-                current_job_id = job.id;
-
-                job_id_label.set_text_or_na("%u".printf(current_job_id));
-                job_state_label.set_text_or_na(job.state);
-                job_type_label.set_text_or_na(job.job_type);
-
-                cancel_button.set_sensitive(true);
-        }
-
-        public void on_start() {
-                Unit u = get_current_unit();
-
-                if (u == null)
-                        return;
-
-                try {
-                        u.start("replace");
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_stop() {
-                Unit u = get_current_unit();
-
-                if (u == null)
-                        return;
-
-                try {
-                        u.stop("replace");
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_reload() {
-                Unit u = get_current_unit();
-
-                if (u == null)
-                        return;
-
-                try {
-                        u.reload("replace");
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_restart() {
-                Unit u = get_current_unit();
-
-                if (u == null)
-                        return;
-
-                try {
-                        u.restart("replace");
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_cancel() {
-                Job j = get_current_job();
-
-                if (j == null)
-                        return;
-
-                try {
-                        j.cancel();
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void update_unit_iter(TreeIter iter, string id, Unit u) {
-
-                string t = "";
-                Unit.JobLink jl = u.job;
-
-                if (jl.id != 0) {
-                        Job j = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        jl.path,
-                                        "org.freedesktop.systemd1.Job") as Job;
-
-                        t = j.job_type;
-                }
-
-                unit_model.set(iter,
-                               0, id,
-                               1, u.description,
-                               2, u.load_state,
-                               3, u.active_state,
-                               4, u.sub_state,
-                               5, t != "" ? "→ %s".printf(t) : "",
-                               6, u);
-        }
-
-        public void on_unit_new(string id, ObjectPath path) {
-                Unit u = bus.get_object(
-                                "org.freedesktop.systemd1",
-                                path,
-                                "org.freedesktop.systemd1.Unit") as Unit;
-
-                u.changed += on_unit_changed;
-
-                TreeIter iter;
-                unit_model.append(out iter);
-                update_unit_iter(iter, id, u);
-        }
-
-        public void update_job_iter(TreeIter iter, uint32 id, Job j) {
-                job_model.set(iter,
-                              0, "%u".printf(id),
-                              1, j.unit.id,
-                              2, "→ %s".printf(j.job_type),
-                              3, j.state,
-                              4, j,
-                              5, id);
-        }
-
-        public void on_job_new(uint32 id, ObjectPath path) {
-                Job j = bus.get_object(
-                                "org.freedesktop.systemd1",
-                                path,
-                                "org.freedesktop.systemd1.Job") as Job;
-
-                j.changed += on_job_changed;
-
-                TreeIter iter;
-                job_model.append(out iter);
-                update_job_iter(iter, id, j);
-        }
-
-        public void on_unit_removed(string id, ObjectPath path) {
-                TreeIter iter;
-                if (!(unit_model.get_iter_first(out iter)))
-                        return;
-
-                do {
-                        string name;
-
-                        unit_model.get(iter, 0, out name);
-
-                        if (id == name) {
-                                if (current_unit_id == name)
-                                        clear_unit();
-
-                                unit_model.remove(iter);
-                                break;
-                        }
-
-                } while (unit_model.iter_next(ref iter));
-        }
-
-        public void on_job_removed(uint32 id, ObjectPath path) {
-                TreeIter iter;
-                if (!(job_model.get_iter_first(out iter)))
-                        return;
-
-                do {
-                        uint32 j;
-
-                        job_model.get(iter, 5, out j);
-
-                        if (id == j) {
-                                if (current_job_id == j)
-                                        clear_job();
-
-                                job_model.remove(iter);
-
-                                break;
-                        }
-
-                } while (job_model.iter_next(ref iter));
-        }
-
-        public void on_unit_changed(Unit u) {
-                TreeIter iter;
-                string id;
-
-                if (!(unit_model.get_iter_first(out iter)))
-                        return;
-
-                id = u.id;
-
-                do {
-                        string name;
-
-                        unit_model.get(iter, 0, out name);
-
-                        if (id == name) {
-                                update_unit_iter(iter, id, u);
-
-                                if (current_unit_id == id)
-                                        show_unit(u);
-
-                                break;
-                        }
-
-                } while (unit_model.iter_next(ref iter));
-        }
-
-        public void on_job_changed(Job j) {
-                TreeIter iter;
-                uint32 id;
-
-                if (!(job_model.get_iter_first(out iter)))
-                        return;
-
-                id = j.id;
-
-                do {
-                        uint32 k;
-
-                        job_model.get(iter, 5, out k);
-
-                        if (id == k) {
-                                update_job_iter(iter, id, j);
-
-                                if (current_job_id == id)
-                                        show_job(j);
-
-                                break;
-                        }
-
-                } while (job_model.iter_next(ref iter));
-        }
-
-        public bool unit_filter(TreeModel model, TreeIter iter) {
-                string id, active_state, job;
-
-                model.get(iter, 0, out id, 3, out active_state, 5, out job);
-
-                if (id == null)
-                        return false;
-
-                switch (unit_type_combo_box.get_active()) {
-
-                        case 0:
-                                return true;
-
-                        case 1:
-                                return active_state != "inactive" || job != "";
-
-                        case 2:
-                                return id.has_suffix(".service");
-
-                        case 3:
-                                return id.has_suffix(".socket");
-
-                        case 4:
-                                return id.has_suffix(".device");
-
-                        case 5:
-                                return id.has_suffix(".mount");
-
-                        case 6:
-                                return id.has_suffix(".automount");
-
-                        case 7:
-                                return id.has_suffix(".target");
-
-                        case 8:
-                                return id.has_suffix(".snapshot");
-                }
-
-                return false;
-        }
-
-        public void unit_type_changed() {
-                TreeModelFilter model = (TreeModelFilter) unit_view.get_model();
-
-                model.refilter();
-        }
-
-        public void on_server_reload() {
-                try {
-                        manager.reload();
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_server_snapshot() {
-                try {
-                        manager.create_snapshot();
-
-                        if (unit_type_combo_box.get_active() != 0)
-                                unit_type_combo_box.set_active(8);
-
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_unit_load() {
-                string t = unit_load_entry.get_text();
-
-                if (t == "")
-                        return;
-
-                try {
-                        var path = manager.load_unit(t);
-
-                        Unit u = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        path,
-                                        "org.freedesktop.systemd1.Unit") as Unit;
-
-                        var m = new MessageDialog(this,
-                                                  DialogFlags.DESTROY_WITH_PARENT,
-                                                  MessageType.INFO,
-                                                  ButtonsType.CLOSE,
-                                                  "Unit available as id %s", u.id);
-                        m.title = "Unit";
-                        m.run();
-                        m.destroy();
-
-                        show_unit(u);
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-        }
-
-        public void on_unit_load_entry_changed() {
-                unit_load_button.set_sensitive(unit_load_entry.get_text() != "");
-        }
-
-        public bool on_activate_link(string uri) {
-
-                try {
-                        string path = manager.get_unit(uri);
-
-                        Unit u = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        path,
-                                        "org.freedesktop.systemd1.Unit") as Unit;
-
-                        show_unit(u);
-                } catch (DBus.Error e) {
-                        show_error(e.message);
-                }
-
-                return true;
-        }
-
-        public void show_error(string e) {
-                var m = new MessageDialog(this,
-                                          DialogFlags.DESTROY_WITH_PARENT,
-                                          MessageType.ERROR,
-                                          ButtonsType.CLOSE, "%s", e);
-                m.title = "Error";
-                m.run();
-                m.destroy();
-        }
-
-}
-
-static const OptionEntry entries[] = {
-        { "session", 0,   0,                   OptionArg.NONE,   out session, "Connect to session bus", null },
-        { "system",  0,   OptionFlags.REVERSE, OptionArg.NONE,   out session, "Connect to system bus", null },
-        { null }
-};
-
-void show_error(string e) {
-        var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
-        m.run();
-        m.destroy();
-}
-
-int main (string[] args) {
-
-        try {
-                Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm");
-
-                MainWindow window = new MainWindow();
-                window.show_all();
-
-                Gtk.main();
-        } catch (DBus.Error e) {
-                show_error(e.message);
-        } catch (GLib.Error e) {
-                show_error(e.message);
-        }
-
-        return 0;
-}
diff --git a/systemctl.vala b/systemctl.vala
deleted file mode 100644
index 821be5a..0000000
--- a/systemctl.vala
+++ /dev/null
@@ -1,321 +0,0 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-using DBus;
-using GLib;
-
-static string type = null;
-static bool all = false;
-static bool replace = false;
-static bool session = false;
-static Connection bus = null;
-
-public static int job_info_compare(void* key1, void* key2) {
-        Manager.JobInfo *j1 = (Manager.JobInfo*) key1;
-        Manager.JobInfo *j2 = (Manager.JobInfo*) key2;
-
-        return j1->id < j2->id ? -1 : (j1->id > j2->id ? 1 : 0);
-}
-
-public static int unit_info_compare(void* key1, void* key2) {
-        Manager.UnitInfo *u1 = (Manager.UnitInfo*) key1;
-        Manager.UnitInfo *u2 = (Manager.UnitInfo*) key2;
-
-        int r = Posix.strcmp(Posix.strrchr(u1->id, '.'), Posix.strrchr(u2->id, '.'));
-        if (r != 0)
-                return r;
-
-        return Posix.strcmp(u1->id, u2->id);
-}
-
-public void on_unit_changed(Unit u) {
-        stdout.printf("Unit %s changed.\n", u.id);
-}
-
-public void on_unit_new(string id, ObjectPath path) {
-        stdout.printf("Unit %s added.\n", id);
-
-        Unit u = bus.get_object(
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Unit") as Unit;
-
-        u.changed += on_unit_changed;
-
-        /* FIXME: We leak memory here */
-        u.ref();
-}
-
-public void on_job_changed(Job j) {
-        stdout.printf("Job %u changed.\n", j.id);
-}
-
-public void on_job_new(uint32 id, ObjectPath path) {
-        stdout.printf("Job %u added.\n", id);
-
-        Job j = bus.get_object(
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Job") as Job;
-
-        j.changed += on_job_changed;
-
-        /* FIXME: We leak memory here */
-        j.ref();
-}
-
-public void on_unit_removed(string id, ObjectPath path) {
-        stdout.printf("Unit %s removed.\n", id);
-}
-
-public void on_job_removed(uint32 id, ObjectPath path) {
-        stdout.printf("Job %u removed.\n", id);
-}
-
-static const OptionEntry entries[] = {
-        { "type",    't', 0,                   OptionArg.STRING, out type,    "List only particular type of units", "TYPE" },
-        { "all",     'a', 0,                   OptionArg.NONE,   out all,     "Show all units, including dead ones", null  },
-        { "replace", 0,   0,                   OptionArg.NONE,   out replace, "When installing a new job, replace existing conflicting ones", null },
-        { "session", 0,   0,                   OptionArg.NONE,   out session, "Connect to session bus", null },
-        { "system",  0,   OptionFlags.REVERSE, OptionArg.NONE,   out session, "Connect to system bus", null },
-        { null }
-};
-
-int main (string[] args) {
-
-        OptionContext context = new OptionContext("[COMMAND [ARGUMENT...]]");
-        context.add_main_entries(entries, null);
-        context.set_description(
-                        "Commands:\n" +
-                        "  list-units                      List units\n" +
-                        "  list-jobs                       List jobs\n" +
-                        "  clear-jobs                      Cancel all jobs\n" +
-                        "  load [NAME...]                  Load one or more units\n" +
-                        "  cancel [JOB...]                 Cancel one or more jobs\n" +
-                        "  start [NAME...]                 Start on or more units\n" +
-                        "  stop [NAME...]                  Stop on or more units\n" +
-                        "  enter [NAME]                    Start one unit and stop all others\n" +
-                        "  restart [NAME...]               Restart on or more units\n" +
-                        "  reload [NAME...]                Reload on or more units\n" +
-                        "  monitor                         Monitor unit/job changes\n" +
-                        "  dump                            Dump server status\n" +
-                        "  snapshot [NAME]                 Create a snapshot\n" +
-                        "  daemon-reload                   Reload daemon configuration\n" +
-                        "  daemon-reexecute                Reexecute daemon\n" +
-                        "  show-environment                Dump environment\n" +
-                        "  set-environment [NAME=VALUE...] Set one or more environment variables\n" +
-                        "  unset-environment [NAME...]     Unset one or more environment variables\n");
-
-        try {
-                context.parse(ref args);
-        } catch (GLib.OptionError e) {
-                message("Failed to parse command line: %s".printf(e.message));
-        }
-
-        try {
-                bus = Bus.get(session ? BusType.SESSION : BusType.SYSTEM);
-
-                Manager manager = bus.get_object (
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager") as Manager;
-
-                if (args[1] == "list-units" || args.length <= 1) {
-                        var list = manager.list_units();
-                        uint n = 0;
-                        Posix.qsort(list, list.length, sizeof(Manager.UnitInfo), unit_info_compare);
-
-                        stdout.printf("%-45s %-6s %-12s %-12s %-17s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB");
-
-                        foreach (var i in list) {
-
-                                if (type != null && !i.id.has_suffix(".%s".printf(type)))
-                                        continue;
-
-                                if (!all && i.active_state == "inactive")
-                                        continue;
-
-                                stdout.printf("%-45s %-6s %-12s %-12s", i.id, i.load_state, i.active_state, i.sub_state);
-
-                                if (i.job_id != 0)
-                                        stdout.printf(" -> %-15s", i.job_type);
-
-                                stdout.puts("\n");
-                                n++;
-                        }
-
-                        if (all)
-                                stdout.printf("\n%u units listed.\n", n);
-                        else
-                                stdout.printf("\n%u live units listed. Pass --all to see dead units, too.\n", n);
-
-
-                } else if (args[1] == "list-jobs") {
-                        var list = manager.list_jobs();
-                        Posix.qsort(list, list.length, sizeof(Manager.JobInfo), job_info_compare);
-
-                        stdout.printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
-
-                        foreach (var i in list)
-                                stdout.printf("%4u %-45s → %-15s %-7s\n", i.id, i.name, i.type, i.state);
-
-                        stdout.printf("\n%u jobs listed.\n", list.length);
-
-                } else if (args[1] == "clear-jobs") {
-
-                        manager.clear_jobs();
-
-                } else if (args[1] == "load") {
-
-                        if (args.length < 3) {
-                                stderr.printf("Missing argument.\n");
-                                return 1;
-                        }
-
-                        for (int i = 2; i < args.length; i++)
-                                manager.load_unit(args[i]);
-
-                } else if (args[1] == "cancel") {
-
-                        if (args.length < 3) {
-                                stderr.printf("Missing argument.\n");
-                                return 1;
-                        }
-
-                        for (int i = 2; i < args.length; i++) {
-                                uint32 id;
-
-                                if (args[i].scanf("%u", out id) != 1) {
-                                        stderr.printf("Failed to parse argument.\n");
-                                        return 1;
-                                }
-
-                                ObjectPath p = manager.get_job(id);
-
-                                Job j = bus.get_object (
-                                                "org.freedesktop.systemd1",
-                                                p,
-                                                "org.freedesktop.systemd1.Job") as Job;
-
-                                j.cancel();
-                        }
-
-                } else if (args[1] == "start" ||
-                           args[1] == "stop" ||
-                           args[1] == "reload" ||
-                           args[1] == "restart") {
-
-                        if (args.length < 3) {
-                                stderr.printf("Missing argument.\n");
-                                return 1;
-                        }
-
-                        for (int i = 2; i < args.length; i++) {
-
-                                ObjectPath p = manager.load_unit(args[i]);
-
-                                Unit u = bus.get_object(
-                                                "org.freedesktop.systemd1",
-                                                p,
-                                                "org.freedesktop.systemd1.Unit") as Unit;
-
-                                string mode = replace ? "replace" : "fail";
-
-                                if (args[1] == "start")
-                                        u.start(mode);
-                                else if (args[1] == "stop")
-                                        u.stop(mode);
-                                else if (args[1] == "restart")
-                                        u.restart(mode);
-                                else if (args[1] == "reload")
-                                        u.reload(mode);
-                        }
-
-                } else if (args[1] == "isolate") {
-
-                        if (args.length != 3) {
-                                stderr.printf("Missing argument.\n");
-                                return 1;
-                        }
-
-                        ObjectPath p = manager.load_unit(args[2]);
-
-                        Unit u = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        p,
-                                        "org.freedesktop.systemd1.Unit") as Unit;
-
-                        u.start("isolate");
-
-                } else if (args[1] == "monitor") {
-
-                        manager.subscribe();
-
-                        manager.unit_new += on_unit_new;
-                        manager.unit_removed += on_unit_removed;
-                        manager.job_new += on_job_new;
-                        manager.job_removed += on_job_removed;
-
-                        MainLoop l = new MainLoop();
-                        l.run();
-
-                } else if (args[1] == "dump")
-                        stdout.puts(manager.dump());
-
-                else if (args[1] == "snapshot") {
-
-                        ObjectPath p = manager.create_snapshot(args.length > 2 ? args[2] : "");
-
-                        Unit u = bus.get_object(
-                                        "org.freedesktop.systemd1",
-                                        p,
-                                        "org.freedesktop.systemd1.Unit") as Unit;
-
-                        stdout.printf("%s\n", u.id);
-
-                } else if (args[1] == "daemon-reload")
-                        manager.reload();
-
-                else if (args[1] == "daemon-reexecute" || args[1] == "daemon-reexec")
-                        manager.reexecute();
-
-                else if (args[1] == "daemon-exit")
-                        manager.exit();
-
-                else if (args[1] == "show-environment") {
-                        foreach(var x in manager.environment)
-                                stderr.printf("%s\n", x);
-
-                } else if (args[1] == "set-environment")
-                        manager.set_environment(args[2:args.length]);
-
-                else if (args[1] == "unset-environment")
-                        manager.unset_environment(args[2:args.length]);
-
-                else {
-                        stderr.printf("Unknown command %s.\n", args[1]);
-                        return 1;
-                }
-
-        } catch (DBus.Error e) {
-                stderr.printf("%s\n".printf(e.message));
-        }
-
-        return 0;
-}
diff --git a/systemd-interfaces.vala b/systemd-interfaces.vala
deleted file mode 100644
index 7282bf3..0000000
--- a/systemd-interfaces.vala
+++ /dev/null
@@ -1,137 +0,0 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-using DBus;
-
-[DBus (name = "org.freedesktop.systemd1.Manager")]
-public interface Manager : DBus.Object {
-
-        public struct UnitInfo {
-                string id;
-                string description;
-                string load_state;
-                string active_state;
-                string sub_state;
-                ObjectPath unit_path;
-                uint32 job_id;
-                string job_type;
-                ObjectPath job_path;
-        }
-
-        public struct JobInfo {
-                uint32 id;
-                string name;
-                string type;
-                string state;
-                ObjectPath job_path;
-                ObjectPath unit_path;
-        }
-
-        public abstract string[] environment { owned get; }
-
-        public abstract UnitInfo[] list_units() throws DBus.Error;
-        public abstract JobInfo[] list_jobs() throws DBus.Error;
-
-        public abstract ObjectPath get_unit(string name) throws DBus.Error;
-        public abstract ObjectPath load_unit(string name) throws DBus.Error;
-        public abstract ObjectPath get_job(uint32 id) throws DBus.Error;
-
-        public abstract void clear_jobs() throws DBus.Error;
-
-        public abstract void subscribe() throws DBus.Error;
-        public abstract void unsubscribe() throws DBus.Error;
-
-        public abstract string dump() throws DBus.Error;
-
-        public abstract void reload() throws DBus.Error;
-        public abstract void reexecute() throws DBus.Error;
-        public abstract void exit() throws DBus.Error;
-
-        public abstract ObjectPath create_snapshot(string name = "", bool cleanup = false) throws DBus.Error;
-
-        public abstract void set_environment(string[] names) throws DBus.Error;
-        public abstract void unset_environment(string[] names) throws DBus.Error;
-
-        public abstract signal void unit_new(string id, ObjectPath path);
-        public abstract signal void unit_removed(string id, ObjectPath path);
-        public abstract signal void job_new(uint32 id, ObjectPath path);
-        public abstract signal void job_removed(uint32 id, ObjectPath path);
-}
-
-[DBus (name = "org.freedesktop.systemd1.Unit")]
-public interface Unit : DBus.Object {
-        public struct JobLink {
-                uint32 id;
-                ObjectPath path;
-        }
-
-        public abstract string id { owned get; }
-        public abstract string[] names { owned get; }
-        public abstract string[] requires { owned get; }
-        public abstract string[] requires_overridable { owned get; }
-        public abstract string[] requisite { owned get; }
-        public abstract string[] requisite_overridable { owned get; }
-        public abstract string[] wants { owned get; }
-        public abstract string[] required_by { owned get; }
-        public abstract string[] required_by_overridable { owned get; }
-        public abstract string[] wanted_by { owned get; }
-        public abstract string[] conflicts { owned get; }
-        public abstract string[] before { owned get; }
-        public abstract string[] after { owned get; }
-        public abstract string description { owned get; }
-        public abstract string load_state { owned get; }
-        public abstract string active_state { owned get; }
-        public abstract string sub_state { owned get; }
-        public abstract string fragment_path { owned get; }
-        public abstract uint64 inactive_exit_timestamp { owned get; }
-        public abstract uint64 active_enter_timestamp { owned get; }
-        public abstract uint64 active_exit_timestamp { owned get; }
-        public abstract uint64 inactive_enter_timestamp { owned get; }
-        public abstract bool can_start { owned get; }
-        public abstract bool can_reload { owned get; }
-        public abstract JobLink job { owned get; }
-        public abstract bool recursive_stop { owned get; }
-        public abstract bool stop_when_unneeded { owned get; }
-        public abstract string default_control_group { owned get; }
-        public abstract string[] control_groups { owned get; }
-
-        public abstract ObjectPath start(string mode) throws DBus.Error;
-        public abstract ObjectPath stop(string mode) throws DBus.Error;
-        public abstract ObjectPath restart(string mode) throws DBus.Error;
-        public abstract ObjectPath reload(string mode) throws DBus.Error;
-
-        public abstract signal void changed();
-}
-
-[DBus (name = "org.freedesktop.systemd1.Job")]
-public interface Job : DBus.Object {
-        public struct UnitLink {
-                string id;
-                ObjectPath path;
-        }
-
-        public abstract uint32 id { owned get; }
-        public abstract string state { owned get; }
-        public abstract string job_type { owned get; }
-        public abstract UnitLink unit { owned get; }
-
-        public abstract void cancel() throws DBus.Error;
-
-        public abstract signal void changed();
-}
diff --git a/target.c b/target.c
deleted file mode 100644
index 75f8ef8..0000000
--- a/target.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <signal.h>
-
-#include "unit.h"
-#include "target.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "dbus-target.h"
-
-static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
-        [TARGET_DEAD] = UNIT_INACTIVE,
-        [TARGET_ACTIVE] = UNIT_ACTIVE
-};
-
-static void target_set_state(Target *t, TargetState state) {
-        TargetState old_state;
-        assert(t);
-
-        old_state = t->state;
-        t->state = state;
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(t)->meta.id,
-                          target_state_to_string(old_state),
-                          target_state_to_string(state));
-
-        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state]);
-}
-
-static int target_coldplug(Unit *u) {
-        Target *t = TARGET(u);
-
-        assert(t);
-        assert(t->state == TARGET_DEAD);
-
-        if (t->deserialized_state != t->state)
-                target_set_state(t, t->deserialized_state);
-
-        return 0;
-}
-
-static void target_dump(Unit *u, FILE *f, const char *prefix) {
-        Target *t = TARGET(u);
-
-        assert(t);
-        assert(f);
-
-        fprintf(f,
-                "%sTarget State: %s\n",
-                prefix, target_state_to_string(t->state));
-}
-
-static int target_start(Unit *u) {
-        Target *t = TARGET(u);
-
-        assert(t);
-        assert(t->state == TARGET_DEAD);
-
-        target_set_state(t, TARGET_ACTIVE);
-        return 0;
-}
-
-static int target_stop(Unit *u) {
-        Target *t = TARGET(u);
-
-        assert(t);
-        assert(t->state == TARGET_ACTIVE);
-
-        target_set_state(t, TARGET_DEAD);
-        return 0;
-}
-
-static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Target *s = TARGET(u);
-
-        assert(s);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", target_state_to_string(s->state));
-        return 0;
-}
-
-static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Target *s = TARGET(u);
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                TargetState state;
-
-                if ((state = target_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        s->deserialized_state = state;
-
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState target_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[TARGET(u)->state];
-}
-
-static const char *target_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return target_state_to_string(TARGET(u)->state);
-}
-
-int target_get_runlevel(Target *t) {
-
-        static const struct {
-                const char *special;
-                const int runlevel;
-        } table[] = {
-                { SPECIAL_RUNLEVEL5_TARGET, '5' },
-                { SPECIAL_RUNLEVEL4_TARGET, '4' },
-                { SPECIAL_RUNLEVEL3_TARGET, '3' },
-                { SPECIAL_RUNLEVEL2_TARGET, '2' },
-                { SPECIAL_RUNLEVEL1_TARGET, '1' },
-                { SPECIAL_RUNLEVEL0_TARGET, '0' },
-                { SPECIAL_RUNLEVEL6_TARGET, '6' },
-        };
-
-        unsigned i;
-
-        assert(t);
-
-        /* Tries to determine if this is a SysV runlevel and returns
-         * it if that is so. */
-
-        for (i = 0; i < ELEMENTSOF(table); i++)
-                if (unit_has_name(UNIT(t), table[i].special))
-                        return table[i].runlevel;
-
-        return 0;
-}
-
-static const char* const target_state_table[_TARGET_STATE_MAX] = {
-        [TARGET_DEAD] = "dead",
-        [TARGET_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
-
-const UnitVTable target_vtable = {
-        .suffix = ".target",
-
-        .load = unit_load_fragment_and_dropin,
-        .coldplug = target_coldplug,
-
-        .dump = target_dump,
-
-        .start = target_start,
-        .stop = target_stop,
-
-        .serialize = target_serialize,
-        .deserialize_item = target_deserialize_item,
-
-        .active_state = target_active_state,
-        .sub_state_to_string = target_sub_state_to_string,
-
-        .bus_message_handler = bus_target_message_handler
-};
diff --git a/target.h b/target.h
deleted file mode 100644
index 5397d50..0000000
--- a/target.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef footargethfoo
-#define footargethfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Target Target;
-
-#include "unit.h"
-
-typedef enum TargetState {
-        TARGET_DEAD,
-        TARGET_ACTIVE,
-        _TARGET_STATE_MAX,
-        _TARGET_STATE_INVALID = -1
-} TargetState;
-
-struct Target {
-        Meta meta;
-
-        TargetState state, deserialized_state;
-};
-
-extern const UnitVTable target_vtable;
-
-int target_get_runlevel(Target *t);
-
-const char* target_state_to_string(TargetState i);
-TargetState target_state_from_string(const char *s);
-
-#endif
diff --git a/test-engine.c b/test-engine.c
deleted file mode 100644
index 27e16f3..0000000
--- a/test-engine.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "manager.h"
-
-int main(int argc, char *argv[]) {
-        Manager *m = NULL;
-        Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
-        Job *j;
-
-        assert_se(set_unit_path("test2") >= 0);
-
-        assert_se(manager_new(MANAGER_INIT, false, &m) >= 0);
-
-        printf("Load1:\n");
-        assert_se(manager_load_unit(m, "a.service", NULL, &a) == 0);
-        assert_se(manager_load_unit(m, "b.service", NULL, &b) == 0);
-        assert_se(manager_load_unit(m, "c.service", NULL, &c) == 0);
-        manager_dump_units(m, stdout, "\t");
-
-        printf("Test1: (Trivial)\n");
-        assert_se(manager_add_job(m, JOB_START, c, JOB_REPLACE, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Load2:\n");
-        manager_clear_jobs(m);
-        assert_se(manager_load_unit(m, "d.service", NULL, &d) == 0);
-        assert_se(manager_load_unit(m, "e.service", NULL, &e) == 0);
-        manager_dump_units(m, stdout, "\t");
-
-        printf("Test2: (Cyclic Order, Unfixable)\n");
-        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, &j) == -ENOEXEC);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Test4: (Identical transaction)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Load3:\n");
-        assert_se(manager_load_unit(m, "g.service", NULL, &g) == 0);
-        manager_dump_units(m, stdout, "\t");
-
-        printf("Test5: (Colliding transaction, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, &j) == -EEXIST);
-
-        printf("Test6: (Colliding transaction, replace)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Test7: (Unmeargable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, &j) == -EEXIST);
-
-        printf("Test8: (Mergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Test9: (Unmeargable job type, replace)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        printf("Load4:\n");
-        assert_se(manager_load_unit(m, "h.service", NULL, &h) == 0);
-        manager_dump_units(m, stdout, "\t");
-
-        printf("Test10: (Unmeargable job type of auxiliary job, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, &j) == 0);
-        manager_dump_jobs(m, stdout, "\t");
-
-        manager_free(m);
-
-        return 0;
-}
diff --git a/test-job-type.c b/test-job-type.c
deleted file mode 100644
index b531262..0000000
--- a/test-job-type.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "job.h"
-
-int main(int argc, char*argv[]) {
-        JobType a, b, c, d, e, f, g;
-
-        for (a = 0; a < _JOB_TYPE_MAX; a++)
-                for (b = 0; b < _JOB_TYPE_MAX; b++) {
-
-                        if (!job_type_is_mergeable(a, b))
-                                printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b));
-
-                        for (c = 0; c < _JOB_TYPE_MAX; c++) {
-
-                                /* Verify transitivity of mergeability
-                                 * of job types */
-                                assert(!job_type_is_mergeable(a, b) ||
-                                       !job_type_is_mergeable(b, c) ||
-                                       job_type_is_mergeable(a, c));
-
-                                d = a;
-                                if (job_type_merge(&d, b) >= 0) {
-
-                                        printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(d));
-
-                                        /* Verify that merged entries can be
-                                         * merged with the same entries they
-                                         * can be merged with seperately */
-                                        assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(d, c));
-                                        assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(d, c));
-
-                                        /* Verify that if a merged
-                                         * with b is not mergable with
-                                         * c then either a or b is not
-                                         * mergeable with c either. */
-                                        assert(job_type_is_mergeable(d, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c));
-
-                                        e = b;
-                                        if (job_type_merge(&e, c) >= 0) {
-
-                                                /* Verify associativity */
-
-                                                f = d;
-                                                assert(job_type_merge(&f, c) == 0);
-
-                                                g = e;
-                                                assert(job_type_merge(&g, a) == 0);
-
-                                                assert(f == g);
-
-                                                printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(d));
-                                        }
-                                }
-                        }
-                }
-
-
-        return 0;
-}
diff --git a/test-loopback.c b/test-loopback.c
deleted file mode 100644
index 5cd7b41..0000000
--- a/test-loopback.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "loopback-setup.h"
-
-int main(int argc, char* argv[]) {
-        int r;
-
-        if ((r = loopback_setup()) < 0)
-                fprintf(stderr, "loopback: %s\n", strerror(-r));
-
-        return 0;
-}
diff --git a/test-ns.c b/test-ns.c
deleted file mode 100644
index a54011e..0000000
--- a/test-ns.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-
-#include "namespace.h"
-#include "log.h"
-
-int main(int argc, char *argv[]) {
-        const char * const writable[] = {
-                "/home",
-                NULL
-        };
-
-        const char * const readable[] = {
-                "/",
-                "/usr",
-                "/boot",
-                NULL
-        };
-
-        const char * const inaccessible[] = {
-                "/home/lennart/projects",
-                NULL
-        };
-
-        int r;
-
-        if ((r = setup_namespace((char**) writable, (char**) readable, (char**) inaccessible, true, MS_SHARED)) < 0) {
-                log_error("Failed to setup namespace: %s", strerror(-r));
-                return 1;
-        }
-
-        execl("/bin/sh", "/bin/sh", NULL);
-        log_error("execl(): %m");
-
-        return 1;
-}
diff --git a/timer.c b/timer.c
deleted file mode 100644
index 41aeb7f..0000000
--- a/timer.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "unit.h"
-#include "timer.h"
-
-static void timer_done(Unit *u) {
-        Timer *t = TIMER(u);
-
-        assert(t);
-}
-
-static UnitActiveState timer_active_state(Unit *u) {
-
-        static const UnitActiveState table[_TIMER_STATE_MAX] = {
-                [TIMER_DEAD] = UNIT_INACTIVE,
-                [TIMER_WAITING] = UNIT_ACTIVE,
-                [TIMER_RUNNING] = UNIT_ACTIVE
-        };
-
-        return table[TIMER(u)->state];
-}
-
-const UnitVTable timer_vtable = {
-        .suffix = ".timer",
-
-        .load = unit_load_fragment_and_dropin,
-        .done = timer_done,
-
-        .active_state = timer_active_state
-};
diff --git a/timer.h b/timer.h
deleted file mode 100644
index 0ec3e0d..0000000
--- a/timer.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef footimerhfoo
-#define footimerhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Timer Timer;
-
-#include "unit.h"
-
-typedef enum TimerState {
-        TIMER_DEAD,
-        TIMER_WAITING,
-        TIMER_RUNNING,
-        _TIMER_STATE_MAX
-} TimerState;
-
-struct Timer {
-        Meta meta;
-
-        TimerState state;
-
-        clockid_t clock_id;
-        usec_t next_elapse;
-
-        Service *service;
-};
-
-extern const UnitVTable timer_vtable;
-
-#endif
diff --git a/unit-name.c b/unit-name.c
deleted file mode 100644
index c5901ca..0000000
--- a/unit-name.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <string.h>
-
-#include "unit.h"
-#include "unit-name.h"
-
-#define VALID_CHARS                             \
-        "0123456789"                            \
-        "abcdefghijklmnopqrstuvwxyz"            \
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
-        ":-_.\\"
-
-UnitType unit_name_to_type(const char *n) {
-        UnitType t;
-
-        assert(n);
-
-        for (t = 0; t < _UNIT_TYPE_MAX; t++)
-                if (endswith(n, unit_vtable[t]->suffix))
-                        return t;
-
-        return _UNIT_TYPE_INVALID;
-}
-
-bool unit_name_is_valid(const char *n) {
-        UnitType t;
-        const char *e, *i, *at;
-
-        /* Valid formats:
-         *
-         *         string at instance.suffix
-         *         string.suffix
-         */
-
-        assert(n);
-
-        if (strlen(n) >= UNIT_NAME_MAX)
-                return false;
-
-        t = unit_name_to_type(n);
-        if (t < 0 || t >= _UNIT_TYPE_MAX)
-                return false;
-
-        assert_se(e = strrchr(n, '.'));
-
-        if (e == n)
-                return false;
-
-        for (i = n, at = NULL; i < e; i++) {
-
-                if (*i == '@' && !at)
-                        at = i;
-
-                if (!strchr("@" VALID_CHARS, *i))
-                        return false;
-        }
-
-        if (at) {
-                if (at == n)
-                        return false;
-
-                if (at[1] == '.')
-                        return false;
-        }
-
-        return true;
-}
-
-bool unit_instance_is_valid(const char *i) {
-        assert(i);
-
-        /* The max length depends on the length of the string, so we
-         * don't really check this here. */
-
-        if (i[0] == 0)
-                return false;
-
-        /* We allow additional @ in the instance string, we do not
-         * allow them in the prefix! */
-
-        for (; *i; i++)
-                if (!strchr("@" VALID_CHARS, *i))
-                        return false;
-
-        return true;
-}
-
-bool unit_prefix_is_valid(const char *p) {
-
-        /* We don't allow additional @ in the instance string */
-
-        if (p[0] == 0)
-                return false;
-
-        for (; *p; p++)
-                if (!strchr(VALID_CHARS, *p))
-                        return false;
-
-        return true;
-}
-
-int unit_name_to_instance(const char *n, char **instance) {
-        const char *p, *d;
-        char *i;
-
-        assert(n);
-        assert(instance);
-
-        /* Everything past the first @ and before the last . is the instance */
-        if (!(p = strchr(n, '@'))) {
-                *instance = NULL;
-                return 0;
-        }
-
-        assert_se(d = strrchr(n, '.'));
-        assert(p < d);
-
-        if (!(i = strndup(p+1, d-p-1)))
-                return -ENOMEM;
-
-        *instance = i;
-        return 0;
-}
-
-char *unit_name_to_prefix_and_instance(const char *n) {
-        const char *d;
-
-        assert(n);
-
-        assert_se(d = strrchr(n, '.'));
-
-        return strndup(n, d - n);
-}
-
-char *unit_name_to_prefix(const char *n) {
-        const char *p;
-
-        if ((p = strchr(n, '@')))
-                return strndup(n, p - n);
-
-        return unit_name_to_prefix_and_instance(n);
-}
-
-char *unit_name_change_suffix(const char *n, const char *suffix) {
-        char *e, *r;
-        size_t a, b;
-
-        assert(n);
-        assert(unit_name_is_valid(n));
-        assert(suffix);
-
-        assert_se(e = strrchr(n, '.'));
-        a = e - n;
-        b = strlen(suffix);
-
-        if (!(r = new(char, a + b + 1)))
-                return NULL;
-
-        memcpy(r, n, a);
-        memcpy(r+a, suffix, b+1);
-
-        return r;
-}
-
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
-        char *r;
-
-        assert(prefix);
-        assert(unit_prefix_is_valid(prefix));
-        assert(!instance || unit_instance_is_valid(instance));
-        assert(suffix);
-        assert(unit_name_to_type(suffix) >= 0);
-
-        if (!instance)
-                return strappend(prefix, suffix);
-
-        if (asprintf(&r, "%s@%s%s", prefix, instance, suffix) < 0)
-                return NULL;
-
-        return r;
-}
-
-static char* do_escape(const char *f, char *t) {
-        assert(f);
-        assert(t);
-
-        for (; *f; f++) {
-                if (*f == '/')
-                        *(t++) = '-';
-                else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f > 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        return t;
-}
-
-char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
-        char *r, *t;
-        size_t a, b, c;
-
-        assert(prefix);
-        assert(suffix);
-        assert(unit_name_to_type(suffix) >= 0);
-
-        /* Takes a arbitrary string for prefix and instance plus a
-         * suffix and makes a nice string suitable as unit name of it,
-         * escaping all weird chars on the way.
-         *
-         * / becomes ., and all chars not alloweed in a unit name get
-         * escaped as \xFF, including \ and ., of course. This
-         * escaping is hence reversible.
-         *
-         * This is primarily useful to make nice unit names from
-         * strings, but is actually useful for any kind of string.
-         */
-
-        a = strlen(prefix);
-        c = strlen(suffix);
-
-        if (instance) {
-                b = strlen(instance);
-
-                if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
-                        return NULL;
-
-                t = do_escape(prefix, r);
-                *(t++) = '@';
-                t = do_escape(instance, t);
-        } else {
-
-                if (!(r = new(char, a*4 + c + 1)))
-                        return NULL;
-
-                t = do_escape(prefix, r);
-        }
-
-        strcpy(t, suffix);
-        return r;
-}
-
-char *unit_name_escape(const char *f) {
-        char *r, *t;
-
-        if (!(r = new(char, strlen(f)*4+1)))
-                return NULL;
-
-        t = do_escape(f, r);
-        *t = 0;
-
-        return r;
-
-}
-
-char *unit_name_unescape(const char *f) {
-        char *r, *t;
-
-        assert(f);
-
-        if (!(r = strdup(f)))
-                return NULL;
-
-        for (t = r; *f; f++) {
-                if (*f == '-')
-                        *(t++) = '/';
-                else 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;
-}
-
-bool unit_name_is_template(const char *n) {
-        const char *p;
-
-        assert(n);
-
-        if (!(p = strchr(n, '@')))
-                return false;
-
-        return p[1] == '.';
-}
-
-char *unit_name_replace_instance(const char *f, const char *i) {
-        const char *p, *e;
-        char *r, *k;
-        size_t a;
-
-        assert(f);
-
-        p = strchr(f, '@');
-        assert_se(e = strrchr(f, '.'));
-
-        a = p - f;
-
-        if (p) {
-                size_t b;
-
-                b = strlen(i);
-
-                if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
-                        return NULL;
-
-                k = mempcpy(r, f, a + 1);
-                k = mempcpy(k, i, b);
-        } else {
-
-                if (!(r = new(char, a + strlen(e) + 1)))
-                        return NULL;
-
-                k = mempcpy(r, f, a);
-        }
-
-        strcpy(k, e);
-        return r;
-}
-
-char *unit_name_template(const char *f) {
-        const char *p, *e;
-        char *r;
-        size_t a;
-
-        if (!(p = strchr(f, '@')))
-                return strdup(f);
-
-        assert_se(e = strrchr(f, '.'));
-        a = p - f + 1;
-
-        if (!(r = new(char, a + strlen(e) + 1)))
-                return NULL;
-
-        strcpy(mempcpy(r, f, a), e);
-        return r;
-
-}
-
-char *unit_name_from_path(const char *path, const char *suffix) {
-        char *p, *r;
-
-        assert(path);
-        assert(suffix);
-
-        if (!(p = strdup(path)))
-                return NULL;
-
-        path_kill_slashes(p);
-
-        path = p[0] == '/' ? p + 1 : p;
-
-        if (path[0] == 0) {
-                free(p);
-                return strappend("-", suffix);
-        }
-
-        r = unit_name_build_escape(path, NULL, suffix);
-        free(p);
-
-        return r;
-}
-
-char *unit_name_to_path(const char *name) {
-        char *w, *e;
-
-        assert(name);
-
-        if (!(w = unit_name_to_prefix(name)))
-                return NULL;
-
-        e = unit_name_unescape(w);
-        free(w);
-
-        if (!e)
-                return NULL;
-
-        if (e[0] != '/') {
-                w = strappend("/", e);
-                free(e);
-
-                if (!w)
-                        return NULL;
-
-                e = w;
-        }
-
-        return e;
-}
diff --git a/unit-name.h b/unit-name.h
deleted file mode 100644
index b6dd2c9..0000000
--- a/unit-name.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foounitnamehfoo
-#define foounitnamehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
-
-UnitType unit_name_to_type(const char *n);
-
-int unit_name_to_instance(const char *n, char **instance);
-char* unit_name_to_prefix(const char *n);
-char* unit_name_to_prefix_and_instance(const char *n);
-
-bool unit_name_is_valid(const char *n);
-bool unit_prefix_is_valid(const char *p);
-bool unit_instance_is_valid(const char *i);
-
-char *unit_name_change_suffix(const char *n, const char *suffix);
-
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
-char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix);
-
-char *unit_name_escape(const char *f);
-char *unit_name_unescape(const char *f);
-
-bool unit_name_is_template(const char *n);
-
-char *unit_name_replace_instance(const char *f, const char *i);
-
-char *unit_name_template(const char *f);
-
-char *unit_name_from_path(const char *path, const char *suffix);
-char *unit_name_to_path(const char *name);
-
-#endif
diff --git a/unit.c b/unit.c
deleted file mode 100644
index 1959b1b..0000000
--- a/unit.c
+++ /dev/null
@@ -1,1949 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <sys/poll.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "unit-name.h"
-#include "specifier.h"
-#include "dbus-unit.h"
-
-const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
-        [UNIT_SERVICE] = &service_vtable,
-        [UNIT_TIMER] = &timer_vtable,
-        [UNIT_SOCKET] = &socket_vtable,
-        [UNIT_TARGET] = &target_vtable,
-        [UNIT_DEVICE] = &device_vtable,
-        [UNIT_MOUNT] = &mount_vtable,
-        [UNIT_AUTOMOUNT] = &automount_vtable,
-        [UNIT_SNAPSHOT] = &snapshot_vtable,
-        [UNIT_SWAP] = &swap_vtable
-};
-
-Unit *unit_new(Manager *m) {
-        Unit *u;
-
-        assert(m);
-
-        if (!(u = new0(Unit, 1)))
-                return NULL;
-
-        if (!(u->meta.names = set_new(string_hash_func, string_compare_func))) {
-                free(u);
-                return NULL;
-        }
-
-        u->meta.manager = m;
-        u->meta.type = _UNIT_TYPE_INVALID;
-
-        return u;
-}
-
-bool unit_has_name(Unit *u, const char *name) {
-        assert(u);
-        assert(name);
-
-        return !!set_get(u->meta.names, (char*) name);
-}
-
-int unit_add_name(Unit *u, const char *text) {
-        UnitType t;
-        char *s = NULL, *i = NULL;
-        int r;
-
-        assert(u);
-        assert(text);
-
-        if (unit_name_is_template(text)) {
-                if (!u->meta.instance)
-                        return -EINVAL;
-
-                s = unit_name_replace_instance(text, u->meta.instance);
-        } else
-                s = strdup(text);
-
-        if (!s)
-                return -ENOMEM;
-
-        if (!unit_name_is_valid(s)) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        assert_se((t = unit_name_to_type(s)) >= 0);
-
-        if (u->meta.type != _UNIT_TYPE_INVALID && t != u->meta.type) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        if ((r = unit_name_to_instance(s, &i)) < 0)
-                goto fail;
-
-        if (i && unit_vtable[t]->no_instances)
-                goto fail;
-
-        if (u->meta.type != _UNIT_TYPE_INVALID && !streq_ptr(u->meta.instance, i)) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        if (unit_vtable[t]->no_alias &&
-            !set_isempty(u->meta.names) &&
-            !set_get(u->meta.names, s)) {
-                r = -EEXIST;
-                goto fail;
-        }
-
-        if (hashmap_size(u->meta.manager->units) >= MANAGER_MAX_NAMES) {
-                r = -E2BIG;
-                goto fail;
-        }
-
-        if ((r = set_put(u->meta.names, s)) < 0) {
-                if (r == -EEXIST)
-                        r = 0;
-                goto fail;
-        }
-
-        if ((r = hashmap_put(u->meta.manager->units, s, u)) < 0) {
-                set_remove(u->meta.names, s);
-                goto fail;
-        }
-
-        if (u->meta.type == _UNIT_TYPE_INVALID) {
-
-                u->meta.type = t;
-                u->meta.id = s;
-                u->meta.instance = i;
-
-                LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta);
-
-                if (UNIT_VTABLE(u)->init)
-                        UNIT_VTABLE(u)->init(u);
-        } else
-                free(i);
-
-        unit_add_to_dbus_queue(u);
-        return 0;
-
-fail:
-        free(s);
-        free(i);
-
-        return r;
-}
-
-int unit_choose_id(Unit *u, const char *name) {
-        char *s, *t = NULL;
-
-        assert(u);
-        assert(name);
-
-        if (unit_name_is_template(name)) {
-
-                if (!u->meta.instance)
-                        return -EINVAL;
-
-                if (!(t = unit_name_replace_instance(name, u->meta.instance)))
-                        return -ENOMEM;
-
-                name = t;
-        }
-
-        /* Selects one of the names of this unit as the id */
-        s = set_get(u->meta.names, (char*) name);
-        free(t);
-
-        if (!s)
-                return -ENOENT;
-
-        u->meta.id = s;
-        unit_add_to_dbus_queue(u);
-
-        return 0;
-}
-
-int unit_set_description(Unit *u, const char *description) {
-        char *s;
-
-        assert(u);
-
-        if (!(s = strdup(description)))
-                return -ENOMEM;
-
-        free(u->meta.description);
-        u->meta.description = s;
-
-        unit_add_to_dbus_queue(u);
-        return 0;
-}
-
-bool unit_check_gc(Unit *u) {
-        assert(u);
-
-        if (UNIT_VTABLE(u)->no_gc)
-                return true;
-
-        if (u->meta.job)
-                return true;
-
-        if (unit_active_state(u) != UNIT_INACTIVE)
-                return true;
-
-        if (UNIT_VTABLE(u)->check_gc)
-                if (UNIT_VTABLE(u)->check_gc(u))
-                        return true;
-
-        return false;
-}
-
-void unit_add_to_load_queue(Unit *u) {
-        assert(u);
-        assert(u->meta.type != _UNIT_TYPE_INVALID);
-
-        if (u->meta.load_state != UNIT_STUB || u->meta.in_load_queue)
-                return;
-
-        LIST_PREPEND(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
-        u->meta.in_load_queue = true;
-}
-
-void unit_add_to_cleanup_queue(Unit *u) {
-        assert(u);
-
-        if (u->meta.in_cleanup_queue)
-                return;
-
-        LIST_PREPEND(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta);
-        u->meta.in_cleanup_queue = true;
-}
-
-void unit_add_to_gc_queue(Unit *u) {
-        assert(u);
-
-        if (u->meta.in_gc_queue || u->meta.in_cleanup_queue)
-                return;
-
-        if (unit_check_gc(u))
-                return;
-
-        LIST_PREPEND(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta);
-        u->meta.in_gc_queue = true;
-
-        u->meta.manager->n_in_gc_queue ++;
-
-        if (u->meta.manager->gc_queue_timestamp <= 0)
-                u->meta.manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
-}
-
-void unit_add_to_dbus_queue(Unit *u) {
-        assert(u);
-        assert(u->meta.type != _UNIT_TYPE_INVALID);
-
-        if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue)
-                return;
-
-        if (set_isempty(u->meta.manager->subscribed)) {
-                u->meta.sent_dbus_new_signal = true;
-                return;
-        }
-
-        LIST_PREPEND(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
-        u->meta.in_dbus_queue = true;
-}
-
-static void bidi_set_free(Unit *u, Set *s) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-
-        /* Frees the set and makes sure we are dropped from the
-         * inverse pointers */
-
-        SET_FOREACH(other, s, i) {
-                UnitDependency d;
-
-                for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
-                        set_remove(other->meta.dependencies[d], u);
-
-                unit_add_to_gc_queue(other);
-        }
-
-        set_free(s);
-}
-
-void unit_free(Unit *u) {
-        UnitDependency d;
-        Iterator i;
-        char *t;
-
-        assert(u);
-
-        bus_unit_send_removed_signal(u);
-
-        /* Detach from next 'bigger' objects */
-        SET_FOREACH(t, u->meta.names, i)
-                hashmap_remove_value(u->meta.manager->units, t, u);
-
-        if (u->meta.type != _UNIT_TYPE_INVALID)
-                LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta);
-
-        if (u->meta.in_load_queue)
-                LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
-
-        if (u->meta.in_dbus_queue)
-                LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
-
-        if (u->meta.in_cleanup_queue)
-                LIST_REMOVE(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta);
-
-        if (u->meta.in_gc_queue) {
-                LIST_REMOVE(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta);
-                u->meta.manager->n_in_gc_queue--;
-        }
-
-        /* Free data and next 'smaller' objects */
-        if (u->meta.job)
-                job_free(u->meta.job);
-
-        if (u->meta.load_state != UNIT_STUB)
-                if (UNIT_VTABLE(u)->done)
-                        UNIT_VTABLE(u)->done(u);
-
-        cgroup_bonding_free_list(u->meta.cgroup_bondings);
-
-        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
-                bidi_set_free(u, u->meta.dependencies[d]);
-
-        free(u->meta.description);
-        free(u->meta.fragment_path);
-
-        while ((t = set_steal_first(u->meta.names)))
-                free(t);
-        set_free(u->meta.names);
-
-        free(u->meta.instance);
-
-        free(u);
-}
-
-UnitActiveState unit_active_state(Unit *u) {
-        assert(u);
-
-        if (u->meta.load_state != UNIT_LOADED)
-                return UNIT_INACTIVE;
-
-        return UNIT_VTABLE(u)->active_state(u);
-}
-
-const char* unit_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return UNIT_VTABLE(u)->sub_state_to_string(u);
-}
-
-static void complete_move(Set **s, Set **other) {
-        assert(s);
-        assert(other);
-
-        if (!*other)
-                return;
-
-        if (*s)
-                set_move(*s, *other);
-        else {
-                *s = *other;
-                *other = NULL;
-        }
-}
-
-static void merge_names(Unit *u, Unit *other) {
-        char *t;
-        Iterator i;
-
-        assert(u);
-        assert(other);
-
-        complete_move(&u->meta.names, &other->meta.names);
-
-        while ((t = set_steal_first(other->meta.names)))
-                free(t);
-
-        set_free(other->meta.names);
-        other->meta.names = NULL;
-        other->meta.id = NULL;
-
-        SET_FOREACH(t, u->meta.names, i)
-                assert_se(hashmap_replace(u->meta.manager->units, t, u) == 0);
-}
-
-static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) {
-        Iterator i;
-        Unit *back;
-        int r;
-
-        assert(u);
-        assert(other);
-        assert(d < _UNIT_DEPENDENCY_MAX);
-
-        SET_FOREACH(back, other->meta.dependencies[d], i) {
-                UnitDependency k;
-
-                for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
-                        if ((r = set_remove_and_put(back->meta.dependencies[k], other, u)) < 0) {
-
-                                if (r == -EEXIST)
-                                        set_remove(back->meta.dependencies[k], other);
-                                else
-                                        assert(r == -ENOENT);
-                        }
-        }
-
-        complete_move(&u->meta.dependencies[d], &other->meta.dependencies[d]);
-
-        set_free(other->meta.dependencies[d]);
-        other->meta.dependencies[d] = NULL;
-}
-
-int unit_merge(Unit *u, Unit *other) {
-        UnitDependency d;
-
-        assert(u);
-        assert(other);
-        assert(u->meta.manager == other->meta.manager);
-        assert(u->meta.type != _UNIT_TYPE_INVALID);
-
-        other = unit_follow_merge(other);
-
-        if (other == u)
-                return 0;
-
-        if (u->meta.type != other->meta.type)
-                return -EINVAL;
-
-        if (!streq_ptr(u->meta.instance, other->meta.instance))
-                return -EINVAL;
-
-        if (other->meta.load_state != UNIT_STUB &&
-            other->meta.load_state != UNIT_FAILED)
-                return -EEXIST;
-
-        if (other->meta.job)
-                return -EEXIST;
-
-        if (unit_active_state(other) != UNIT_INACTIVE)
-                return -EEXIST;
-
-        /* Merge names */
-        merge_names(u, other);
-
-        /* Merge dependencies */
-        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
-                merge_dependencies(u, other, d);
-
-        other->meta.load_state = UNIT_MERGED;
-        other->meta.merged_into = u;
-
-        /* If there is still some data attached to the other node, we
-         * don't need it anymore, and can free it. */
-        if (other->meta.load_state != UNIT_STUB)
-                if (UNIT_VTABLE(other)->done)
-                        UNIT_VTABLE(other)->done(other);
-
-        unit_add_to_dbus_queue(u);
-        unit_add_to_cleanup_queue(other);
-
-        return 0;
-}
-
-int unit_merge_by_name(Unit *u, const char *name) {
-        Unit *other;
-        int r;
-        char *s = NULL;
-
-        assert(u);
-        assert(name);
-
-        if (unit_name_is_template(name)) {
-                if (!u->meta.instance)
-                        return -EINVAL;
-
-                if (!(s = unit_name_replace_instance(name, u->meta.instance)))
-                        return -ENOMEM;
-
-                name = s;
-        }
-
-        if (!(other = manager_get_unit(u->meta.manager, name)))
-                r = unit_add_name(u, name);
-        else
-                r = unit_merge(u, other);
-
-        free(s);
-        return r;
-}
-
-Unit* unit_follow_merge(Unit *u) {
-        assert(u);
-
-        while (u->meta.load_state == UNIT_MERGED)
-                assert_se(u = u->meta.merged_into);
-
-        return u;
-}
-
-int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
-        int r;
-
-        assert(u);
-        assert(c);
-
-        if (c->std_output != EXEC_OUTPUT_KERNEL && c->std_output != EXEC_OUTPUT_SYSLOG)
-                return 0;
-
-        /* If syslog or kernel logging is requested, make sure our own
-         * logging daemon is run first. */
-
-        if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
-                return r;
-
-        if (u->meta.manager->running_as != MANAGER_SESSION)
-                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
-                        return r;
-
-        return 0;
-}
-
-const char *unit_description(Unit *u) {
-        assert(u);
-
-        if (u->meta.description)
-                return u->meta.description;
-
-        return u->meta.id;
-}
-
-void unit_dump(Unit *u, FILE *f, const char *prefix) {
-        char *t;
-        UnitDependency d;
-        Iterator i;
-        char *p2;
-        const char *prefix2;
-        CGroupBonding *b;
-        char
-                timestamp1[FORMAT_TIMESTAMP_MAX],
-                timestamp2[FORMAT_TIMESTAMP_MAX],
-                timestamp3[FORMAT_TIMESTAMP_MAX],
-                timestamp4[FORMAT_TIMESTAMP_MAX];
-
-        assert(u);
-        assert(u->meta.type >= 0);
-
-        if (!prefix)
-                prefix = "";
-        p2 = strappend(prefix, "\t");
-        prefix2 = p2 ? p2 : prefix;
-
-        fprintf(f,
-                "%s-> Unit %s:\n"
-                "%s\tDescription: %s\n"
-                "%s\tInstance: %s\n"
-                "%s\tUnit Load State: %s\n"
-                "%s\tUnit Active State: %s\n"
-                "%s\tInactive Exit Timestamp: %s\n"
-                "%s\tActive Enter Timestamp: %s\n"
-                "%s\tActive Exit Timestamp: %s\n"
-                "%s\tInactive Enter Timestamp: %s\n"
-                "%s\tGC Check Good: %s\n",
-                prefix, u->meta.id,
-                prefix, unit_description(u),
-                prefix, strna(u->meta.instance),
-                prefix, unit_load_state_to_string(u->meta.load_state),
-                prefix, unit_active_state_to_string(unit_active_state(u)),
-                prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.inactive_exit_timestamp)),
-                prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp)),
-                prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp)),
-                prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp)),
-                prefix, yes_no(unit_check_gc(u)));
-
-        SET_FOREACH(t, u->meta.names, i)
-                fprintf(f, "%s\tName: %s\n", prefix, t);
-
-        if (u->meta.fragment_path)
-                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->meta.fragment_path);
-
-        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
-                Unit *other;
-
-                SET_FOREACH(other, u->meta.dependencies[d], i)
-                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->meta.id);
-        }
-
-        if (u->meta.load_state == UNIT_LOADED) {
-                fprintf(f,
-                        "%s\tRecursive Stop: %s\n"
-                        "%s\tStop When Unneeded: %s\n",
-                        prefix, yes_no(u->meta.recursive_stop),
-                        prefix, yes_no(u->meta.stop_when_unneeded));
-
-                LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings)
-                        fprintf(f, "%s\tControlGroup: %s:%s\n",
-                                prefix, b->controller, b->path);
-
-                if (UNIT_VTABLE(u)->dump)
-                        UNIT_VTABLE(u)->dump(u, f, prefix2);
-
-        } else if (u->meta.load_state == UNIT_MERGED)
-                fprintf(f,
-                        "%s\tMerged into: %s\n",
-                        prefix, u->meta.merged_into->meta.id);
-
-        if (u->meta.job)
-                job_dump(u->meta.job, f, prefix2);
-
-        free(p2);
-}
-
-/* Common implementation for multiple backends */
-int unit_load_fragment_and_dropin(Unit *u) {
-        int r;
-
-        assert(u);
-
-        /* Load a .service file */
-        if ((r = unit_load_fragment(u)) < 0)
-                return r;
-
-        if (u->meta.load_state == UNIT_STUB)
-                return -ENOENT;
-
-        /* Load drop-in directory data */
-        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
-                return r;
-
-        return 0;
-}
-
-/* Common implementation for multiple backends */
-int unit_load_fragment_and_dropin_optional(Unit *u) {
-        int r;
-
-        assert(u);
-
-        /* Same as unit_load_fragment_and_dropin(), but whether
-         * something can be loaded or not doesn't matter. */
-
-        /* Load a .service file */
-        if ((r = unit_load_fragment(u)) < 0)
-                return r;
-
-        if (u->meta.load_state == UNIT_STUB)
-                u->meta.load_state = UNIT_LOADED;
-
-        /* Load drop-in directory data */
-        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
-                return r;
-
-        return 0;
-}
-
-/* Common implementation for multiple backends */
-int unit_load_nop(Unit *u) {
-        assert(u);
-
-        if (u->meta.load_state == UNIT_STUB)
-                u->meta.load_state = UNIT_LOADED;
-
-        return 0;
-}
-
-int unit_load(Unit *u) {
-        int r;
-
-        assert(u);
-
-        if (u->meta.in_load_queue) {
-                LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
-                u->meta.in_load_queue = false;
-        }
-
-        if (u->meta.type == _UNIT_TYPE_INVALID)
-                return -EINVAL;
-
-        if (u->meta.load_state != UNIT_STUB)
-                return 0;
-
-        if (UNIT_VTABLE(u)->load)
-                if ((r = UNIT_VTABLE(u)->load(u)) < 0)
-                        goto fail;
-
-        if (u->meta.load_state == UNIT_STUB) {
-                r = -ENOENT;
-                goto fail;
-        }
-
-        assert((u->meta.load_state != UNIT_MERGED) == !u->meta.merged_into);
-
-        unit_add_to_dbus_queue(unit_follow_merge(u));
-        unit_add_to_gc_queue(u);
-
-        return 0;
-
-fail:
-        u->meta.load_state = UNIT_FAILED;
-        unit_add_to_dbus_queue(u);
-
-        log_debug("Failed to load configuration for %s: %s", u->meta.id, strerror(-r));
-
-        return r;
-}
-
-/* Errors:
- *         -EBADR:    This unit type does not support starting.
- *         -EALREADY: Unit is already started.
- *         -EAGAIN:   An operation is already in progress. Retry later.
- */
-int unit_start(Unit *u) {
-        UnitActiveState state;
-
-        assert(u);
-
-        /* If this is already (being) started, then this will
-         * succeed. Note that this will even succeed if this unit is
-         * not startable by the user. This is relied on to detect when
-         * we need to wait for units and when waiting is finished. */
-        state = unit_active_state(u);
-        if (UNIT_IS_ACTIVE_OR_RELOADING(state))
-                return -EALREADY;
-
-        /* If it is stopped, but we cannot start it, then fail */
-        if (!UNIT_VTABLE(u)->start)
-                return -EBADR;
-
-        /* We don't suppress calls to ->start() here when we are
-         * already starting, to allow this request to be used as a
-         * "hurry up" call, for example when the unit is in some "auto
-         * restart" state where it waits for a holdoff timer to elapse
-         * before it will start again. */
-
-        unit_add_to_dbus_queue(u);
-        return UNIT_VTABLE(u)->start(u);
-}
-
-bool unit_can_start(Unit *u) {
-        assert(u);
-
-        return !!UNIT_VTABLE(u)->start;
-}
-
-/* Errors:
- *         -EBADR:    This unit type does not support stopping.
- *         -EALREADY: Unit is already stopped.
- *         -EAGAIN:   An operation is already in progress. Retry later.
- */
-int unit_stop(Unit *u) {
-        UnitActiveState state;
-
-        assert(u);
-
-        state = unit_active_state(u);
-        if (state == UNIT_INACTIVE)
-                return -EALREADY;
-
-        if (!UNIT_VTABLE(u)->stop)
-                return -EBADR;
-
-        unit_add_to_dbus_queue(u);
-        return UNIT_VTABLE(u)->stop(u);
-}
-
-/* Errors:
- *         -EBADR:    This unit type does not support reloading.
- *         -ENOEXEC:  Unit is not started.
- *         -EAGAIN:   An operation is already in progress. Retry later.
- */
-int unit_reload(Unit *u) {
-        UnitActiveState state;
-
-        assert(u);
-
-        if (!unit_can_reload(u))
-                return -EBADR;
-
-        state = unit_active_state(u);
-        if (unit_active_state(u) == UNIT_ACTIVE_RELOADING)
-                return -EALREADY;
-
-        if (unit_active_state(u) != UNIT_ACTIVE)
-                return -ENOEXEC;
-
-        unit_add_to_dbus_queue(u);
-        return UNIT_VTABLE(u)->reload(u);
-}
-
-bool unit_can_reload(Unit *u) {
-        assert(u);
-
-        if (!UNIT_VTABLE(u)->reload)
-                return false;
-
-        if (!UNIT_VTABLE(u)->can_reload)
-                return true;
-
-        return UNIT_VTABLE(u)->can_reload(u);
-}
-
-static void unit_check_uneeded(Unit *u) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-
-        /* If this service shall be shut down when unneeded then do
-         * so. */
-
-        if (!u->meta.stop_when_unneeded)
-                return;
-
-        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
-                return;
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        return;
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        return;
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTED_BY], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        return;
-
-        log_debug("Service %s is not needed anymore. Stopping.", u->meta.id);
-
-        /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
-        manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL);
-}
-
-static void retroactively_start_dependencies(Unit *u) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-        assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i)
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
-
-        SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
-}
-
-static void retroactively_stop_dependencies(Unit *u) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
-        if (u->meta.recursive_stop) {
-                /* Pull down units need us recursively if enabled */
-                SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
-                        if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                                manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
-        }
-
-        /* Garbage collect services that might not be needed anymore, if enabled */
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_uneeded(other);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_uneeded(other);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_uneeded(other);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_uneeded(other);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_uneeded(other);
-}
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
-        bool unexpected = false;
-        usec_t ts;
-
-        assert(u);
-        assert(os < _UNIT_ACTIVE_STATE_MAX);
-        assert(ns < _UNIT_ACTIVE_STATE_MAX);
-
-        /* Note that this is called for all low-level state changes,
-         * even if they might map to the same high-level
-         * UnitActiveState! That means that ns == os is OK an expected
-         * behaviour here. For example: if a mount point is remounted
-         * this function will be called too and the utmp code below
-         * relies on that! */
-
-        ts = now(CLOCK_REALTIME);
-
-        if (os == UNIT_INACTIVE && ns != UNIT_INACTIVE)
-                u->meta.inactive_exit_timestamp = ts;
-        else if (os != UNIT_INACTIVE && ns == UNIT_INACTIVE)
-                u->meta.inactive_enter_timestamp = ts;
-
-        if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                u->meta.active_enter_timestamp = ts;
-        else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                u->meta.active_exit_timestamp = ts;
-
-        if (u->meta.job) {
-
-                if (u->meta.job->state == JOB_WAITING)
-
-                        /* So we reached a different state for this
-                         * job. Let's see if we can run it now if it
-                         * failed previously due to EAGAIN. */
-                        job_add_to_run_queue(u->meta.job);
-
-                else {
-                        assert(u->meta.job->state == JOB_RUNNING);
-
-                        /* Let's check whether this state change
-                         * constitutes a finished job, or maybe
-                         * cotradicts a running job and hence needs to
-                         * invalidate jobs. */
-
-                        switch (u->meta.job->type) {
-
-                        case JOB_START:
-                        case JOB_VERIFY_ACTIVE:
-
-                                if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                                        job_finish_and_invalidate(u->meta.job, true);
-                                else if (ns != UNIT_ACTIVATING) {
-                                        unexpected = true;
-                                        job_finish_and_invalidate(u->meta.job, false);
-                                }
-
-                                break;
-
-                        case JOB_RELOAD:
-                        case JOB_RELOAD_OR_START:
-
-                                if (ns == UNIT_ACTIVE)
-                                        job_finish_and_invalidate(u->meta.job, true);
-                                else if (ns != UNIT_ACTIVATING && ns != UNIT_ACTIVE_RELOADING) {
-                                        unexpected = true;
-                                        job_finish_and_invalidate(u->meta.job, false);
-                                }
-
-                                break;
-
-                        case JOB_STOP:
-                        case JOB_RESTART:
-                        case JOB_TRY_RESTART:
-
-                                if (ns == UNIT_INACTIVE)
-                                        job_finish_and_invalidate(u->meta.job, true);
-                                else if (ns != UNIT_DEACTIVATING) {
-                                        unexpected = true;
-                                        job_finish_and_invalidate(u->meta.job, false);
-                                }
-
-                                break;
-
-                        default:
-                                assert_not_reached("Job type unknown");
-                        }
-                }
-        }
-
-        /* If this state change happened without being requested by a
-         * job, then let's retroactively start or stop dependencies */
-
-        if (unexpected) {
-                if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
-                        retroactively_start_dependencies(u);
-                else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
-                        retroactively_stop_dependencies(u);
-        }
-
-        /* Some names are special */
-        if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
-                if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) {
-                        /* The bus just might have become available,
-                         * hence try to connect to it, if we aren't
-                         * yet connected. */
-                        bus_init_system(u->meta.manager);
-                        bus_init_api(u->meta.manager);
-                }
-
-                if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
-                        /* The syslog daemon just might have become
-                         * available, hence try to connect to it, if
-                         * we aren't yet connected. */
-                        log_open();
-
-                if (u->meta.type == UNIT_MOUNT)
-                        /* Another directory became available, let's
-                         * check if that is enough to write our utmp
-                         * entry. */
-                        manager_write_utmp_reboot(u->meta.manager);
-
-                if (u->meta.type == UNIT_TARGET)
-                        /* A target got activated, maybe this is a runlevel? */
-                        manager_write_utmp_runlevel(u->meta.manager, u);
-
-        } else if (!UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
-
-                if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
-                        /* The syslog daemon might just have
-                         * terminated, hence try to disconnect from
-                         * it. */
-                        log_close_syslog();
-
-                /* We don't care about D-Bus here, since we'll get an
-                 * asynchronous notification for it anyway. */
-        }
-
-        /* Maybe we finished startup and are now ready for being
-         * stopped because unneeded? */
-        unit_check_uneeded(u);
-
-        unit_add_to_dbus_queue(u);
-        unit_add_to_gc_queue(u);
-}
-
-int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
-        struct epoll_event ev;
-
-        assert(u);
-        assert(fd >= 0);
-        assert(w);
-        assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u));
-
-        zero(ev);
-        ev.data.ptr = w;
-        ev.events = events;
-
-        if (epoll_ctl(u->meta.manager->epoll_fd,
-                      w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD,
-                      fd,
-                      &ev) < 0)
-                return -errno;
-
-        w->fd = fd;
-        w->type = WATCH_FD;
-        w->data.unit = u;
-
-        return 0;
-}
-
-void unit_unwatch_fd(Unit *u, Watch *w) {
-        assert(u);
-        assert(w);
-
-        if (w->type == WATCH_INVALID)
-                return;
-
-        assert(w->type == WATCH_FD);
-        assert(w->data.unit == u);
-        assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-
-        w->fd = -1;
-        w->type = WATCH_INVALID;
-        w->data.unit = NULL;
-}
-
-int unit_watch_pid(Unit *u, pid_t pid) {
-        assert(u);
-        assert(pid >= 1);
-
-        /* Watch a specific PID. We only support one unit watching
-         * each PID for now. */
-
-        return hashmap_put(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
-}
-
-void unit_unwatch_pid(Unit *u, pid_t pid) {
-        assert(u);
-        assert(pid >= 1);
-
-        hashmap_remove_value(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
-}
-
-int unit_watch_timer(Unit *u, usec_t delay, Watch *w) {
-        struct itimerspec its;
-        int flags, fd;
-        bool ours;
-
-        assert(u);
-        assert(w);
-        assert(w->type == WATCH_INVALID || (w->type == WATCH_TIMER && w->data.unit == u));
-
-        /* This will try to reuse the old timer if there is one */
-
-        if (w->type == WATCH_TIMER) {
-                ours = false;
-                fd = w->fd;
-        } else {
-                ours = true;
-                if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
-                        return -errno;
-        }
-
-        zero(its);
-
-        if (delay <= 0) {
-                /* Set absolute time in the past, but not 0, since we
-                 * don't want to disarm the timer */
-                its.it_value.tv_sec = 0;
-                its.it_value.tv_nsec = 1;
-
-                flags = TFD_TIMER_ABSTIME;
-        } else {
-                timespec_store(&its.it_value, delay);
-                flags = 0;
-        }
-
-        /* This will also flush the elapse counter */
-        if (timerfd_settime(fd, flags, &its, NULL) < 0)
-                goto fail;
-
-        if (w->type == WATCH_INVALID) {
-                struct epoll_event ev;
-
-                zero(ev);
-                ev.data.ptr = w;
-                ev.events = EPOLLIN;
-
-                if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
-                        goto fail;
-        }
-
-        w->fd = fd;
-        w->type = WATCH_TIMER;
-        w->data.unit = u;
-
-        return 0;
-
-fail:
-        if (ours)
-                close_nointr_nofail(fd);
-
-        return -errno;
-}
-
-void unit_unwatch_timer(Unit *u, Watch *w) {
-        assert(u);
-        assert(w);
-
-        if (w->type == WATCH_INVALID)
-                return;
-
-        assert(w->type == WATCH_TIMER && w->data.unit == u);
-
-        assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-        close_nointr_nofail(w->fd);
-
-        w->fd = -1;
-        w->type = WATCH_INVALID;
-        w->data.unit = NULL;
-}
-
-bool unit_job_is_applicable(Unit *u, JobType j) {
-        assert(u);
-        assert(j >= 0 && j < _JOB_TYPE_MAX);
-
-        switch (j) {
-
-        case JOB_VERIFY_ACTIVE:
-        case JOB_START:
-                return true;
-
-        case JOB_STOP:
-        case JOB_RESTART:
-        case JOB_TRY_RESTART:
-                return unit_can_start(u);
-
-        case JOB_RELOAD:
-                return unit_can_reload(u);
-
-        case JOB_RELOAD_OR_START:
-                return unit_can_reload(u) && unit_can_start(u);
-
-        default:
-                assert_not_reached("Invalid job type");
-        }
-}
-
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
-
-        static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
-                [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
-                [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
-                [UNIT_WANTS] = UNIT_WANTED_BY,
-                [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
-                [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
-                [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_CONFLICTS] = UNIT_CONFLICTS,
-                [UNIT_BEFORE] = UNIT_AFTER,
-                [UNIT_AFTER] = UNIT_BEFORE,
-                [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
-                [UNIT_REFERENCED_BY] = UNIT_REFERENCES
-        };
-        int r, q = 0, v = 0, w = 0;
-
-        assert(u);
-        assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
-        assert(inverse_table[d] != _UNIT_DEPENDENCY_INVALID);
-        assert(other);
-
-        /* We won't allow dependencies on ourselves. We will not
-         * consider them an error however. */
-        if (u == other)
-                return 0;
-
-        if (UNIT_VTABLE(u)->no_requires &&
-            (d == UNIT_REQUIRES ||
-             d == UNIT_REQUIRES_OVERRIDABLE ||
-             d == UNIT_REQUISITE ||
-             d == UNIT_REQUISITE_OVERRIDABLE)) {
-                    return -EINVAL;
-        }
-
-        if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0 ||
-            (r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
-                return r;
-
-        if (add_reference)
-                if ((r = set_ensure_allocated(&u->meta.dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
-                    (r = set_ensure_allocated(&other->meta.dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
-                        return r;
-
-        if ((q = set_put(u->meta.dependencies[d], other)) < 0)
-                return q;
-
-        if ((v = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) {
-                r = v;
-                goto fail;
-        }
-
-        if (add_reference) {
-                if ((w = set_put(u->meta.dependencies[UNIT_REFERENCES], other)) < 0) {
-                        r = w;
-                        goto fail;
-                }
-
-                if ((r = set_put(other->meta.dependencies[UNIT_REFERENCED_BY], u)) < 0)
-                        goto fail;
-        }
-
-        unit_add_to_dbus_queue(u);
-        return 0;
-
-fail:
-        if (q > 0)
-                set_remove(u->meta.dependencies[d], other);
-
-        if (v > 0)
-                set_remove(other->meta.dependencies[inverse_table[d]], u);
-
-        if (w > 0)
-                set_remove(u->meta.dependencies[UNIT_REFERENCES], other);
-
-        return r;
-}
-
-static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
-        char *s;
-
-        assert(u);
-        assert(name || path);
-
-        if (!name)
-                name = file_name_from_path(path);
-
-        if (!unit_name_is_template(name)) {
-                *p = NULL;
-                return name;
-        }
-
-        if (u->meta.instance)
-                s = unit_name_replace_instance(name, u->meta.instance);
-        else {
-                char *i;
-
-                if (!(i = unit_name_to_prefix(u->meta.id)))
-                        return NULL;
-
-                s = unit_name_replace_instance(name, i);
-                free(i);
-        }
-
-        if (!s)
-                return NULL;
-
-        *p = s;
-        return s;
-}
-
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
-        Unit *other;
-        int r;
-        char *s;
-
-        assert(u);
-        assert(name || path);
-
-        if (!(name = resolve_template(u, name, path, &s)))
-                return -ENOMEM;
-
-        if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0)
-                goto finish;
-
-        r = unit_add_dependency(u, d, other, add_reference);
-
-finish:
-        free(s);
-        return r;
-}
-
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
-        Unit *other;
-        int r;
-        char *s;
-
-        assert(u);
-        assert(name || path);
-
-        if (!(name = resolve_template(u, name, path, &s)))
-                return -ENOMEM;
-
-        if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0)
-                goto finish;
-
-        r = unit_add_dependency(other, d, u, add_reference);
-
-finish:
-        free(s);
-        return r;
-}
-
-int set_unit_path(const char *p) {
-        char *cwd, *c;
-        int r;
-
-        /* This is mostly for debug purposes */
-
-        if (path_is_absolute(p)) {
-                if (!(c = strdup(p)))
-                        return -ENOMEM;
-        } else {
-                if (!(cwd = get_current_dir_name()))
-                        return -errno;
-
-                r = asprintf(&c, "%s/%s", cwd, p);
-                free(cwd);
-
-                if (r < 0)
-                        return -ENOMEM;
-        }
-
-        if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) {
-                r = -errno;
-                free(c);
-                return r;
-        }
-
-        return 0;
-}
-
-char *unit_dbus_path(Unit *u) {
-        char *p, *e;
-
-        assert(u);
-
-        if (!(e = bus_path_escape(u->meta.id)))
-                return NULL;
-
-        if (asprintf(&p, "/org/freedesktop/systemd1/unit/%s", e) < 0) {
-                free(e);
-                return NULL;
-        }
-
-        free(e);
-        return p;
-}
-
-int unit_add_cgroup(Unit *u, CGroupBonding *b) {
-        CGroupBonding *l;
-        int r;
-
-        assert(u);
-        assert(b);
-        assert(b->path);
-
-        /* Ensure this hasn't been added yet */
-        assert(!b->unit);
-
-        l = hashmap_get(u->meta.manager->cgroup_bondings, b->path);
-        LIST_PREPEND(CGroupBonding, by_path, l, b);
-
-        if ((r = hashmap_replace(u->meta.manager->cgroup_bondings, b->path, l)) < 0) {
-                LIST_REMOVE(CGroupBonding, by_path, l, b);
-                return r;
-        }
-
-        LIST_PREPEND(CGroupBonding, by_unit, u->meta.cgroup_bondings, b);
-        b->unit = u;
-
-        return 0;
-}
-
-static char *default_cgroup_path(Unit *u) {
-        char *p;
-        int r;
-
-        assert(u);
-
-        if (u->meta.instance) {
-                char *t;
-
-                if (!(t = unit_name_template(u->meta.id)))
-                        return NULL;
-
-                r = asprintf(&p, "%s/%s/%s", u->meta.manager->cgroup_hierarchy, t, u->meta.instance);
-                free(t);
-        } else
-                r = asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id);
-
-        return r < 0 ? NULL : p;
-}
-
-int unit_add_cgroup_from_text(Unit *u, const char *name) {
-        size_t n;
-        char *controller = NULL, *path = NULL;
-        CGroupBonding *b = NULL;
-        int r;
-
-        assert(u);
-        assert(name);
-
-        /* Detect controller name */
-        n = strcspn(name, ":");
-
-        if (name[n] == 0 ||
-            (name[n] == ':' && name[n+1] == 0)) {
-
-                /* Only controller name, no path? */
-
-                if (!(path = default_cgroup_path(u)))
-                        return -ENOMEM;
-
-        } else {
-                const char *p;
-
-                /* Controller name, and path. */
-                p = name+n+1;
-
-                if (!path_is_absolute(p))
-                        return -EINVAL;
-
-                if (!(path = strdup(p)))
-                        return -ENOMEM;
-        }
-
-        if (n > 0)
-                controller = strndup(name, n);
-        else
-                controller = strdup(u->meta.manager->cgroup_controller);
-
-        if (!controller) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (cgroup_bonding_find_list(u->meta.cgroup_bondings, controller)) {
-                r = -EEXIST;
-                goto fail;
-        }
-
-        if (!(b = new0(CGroupBonding, 1))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        b->controller = controller;
-        b->path = path;
-        b->only_us = false;
-        b->clean_up = false;
-
-        if ((r = unit_add_cgroup(u, b)) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        free(path);
-        free(controller);
-        free(b);
-
-        return r;
-}
-
-int unit_add_default_cgroup(Unit *u) {
-        CGroupBonding *b;
-        int r = -ENOMEM;
-
-        assert(u);
-
-        /* Adds in the default cgroup data, if it wasn't specified yet */
-
-        if (unit_get_default_cgroup(u))
-                return 0;
-
-        if (!(b = new0(CGroupBonding, 1)))
-                return -ENOMEM;
-
-        if (!(b->controller = strdup(u->meta.manager->cgroup_controller)))
-                goto fail;
-
-        if (!(b->path = default_cgroup_path(u)))
-                goto fail;
-
-        b->clean_up = true;
-        b->only_us = true;
-
-        if ((r = unit_add_cgroup(u, b)) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        free(b->path);
-        free(b->controller);
-        free(b);
-
-        return r;
-}
-
-CGroupBonding* unit_get_default_cgroup(Unit *u) {
-        assert(u);
-
-        return cgroup_bonding_find_list(u->meta.cgroup_bondings, u->meta.manager->cgroup_controller);
-}
-
-int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
-        char *t;
-        int r;
-
-        assert(u);
-        assert(type);
-        assert(_found);
-
-        if (!(t = unit_name_change_suffix(u->meta.id, type)))
-                return -ENOMEM;
-
-        assert(!unit_has_name(u, t));
-
-        r = manager_load_unit(u->meta.manager, t, NULL, _found);
-        free(t);
-
-        assert(r < 0 || *_found != u);
-
-        return r;
-}
-
-int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
-        Unit *found;
-        char *t;
-
-        assert(u);
-        assert(type);
-        assert(_found);
-
-        if (!(t = unit_name_change_suffix(u->meta.id, type)))
-                return -ENOMEM;
-
-        assert(!unit_has_name(u, t));
-
-        found = manager_get_unit(u->meta.manager, t);
-        free(t);
-
-        if (!found)
-                return -ENOENT;
-
-        *_found = found;
-        return 0;
-}
-
-static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        return unit_name_to_prefix_and_instance(u->meta.id);
-}
-
-static char *specifier_prefix(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        return unit_name_to_prefix(u->meta.id);
-}
-
-static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        char *p, *r;
-
-        assert(u);
-
-        if (!(p = unit_name_to_prefix(u->meta.id)))
-                return NULL;
-
-        r = unit_name_unescape(p);
-        free(p);
-
-        return r;
-}
-
-static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        if (u->meta.instance)
-                return unit_name_unescape(u->meta.instance);
-
-        return strdup("");
-}
-
-char *unit_name_printf(Unit *u, const char* format) {
-
-        /*
-         * This will use the passed string as format string and
-         * replace the following specifiers:
-         *
-         * %n: the full id of the unit                 (foo at bar.waldo)
-         * %N: the id of the unit without the suffix   (foo at bar)
-         * %p: the prefix                              (foo)
-         * %i: the instance                            (bar)
-         */
-
-        const Specifier table[] = {
-                { 'n', specifier_string,              u->meta.id },
-                { 'N', specifier_prefix_and_instance, NULL },
-                { 'p', specifier_prefix,              NULL },
-                { 'i', specifier_string,              u->meta.instance },
-                { 0, NULL, NULL }
-        };
-
-        assert(u);
-        assert(format);
-
-        return specifier_printf(format, table, u);
-}
-
-char *unit_full_printf(Unit *u, const char *format) {
-
-        /* This is similar to unit_name_printf() but also supports
-         * unescaping */
-
-        const Specifier table[] = {
-                { 'n', specifier_string,              u->meta.id },
-                { 'N', specifier_prefix_and_instance, NULL },
-                { 'p', specifier_prefix,              NULL },
-                { 'P', specifier_prefix_unescaped,    NULL },
-                { 'i', specifier_string,              u->meta.instance },
-                { 'I', specifier_instance_unescaped,  NULL },
-                { 0, NULL, NULL }
-        };
-
-        assert(u);
-        assert(format);
-
-        return specifier_printf(format, table, u);
-}
-
-char **unit_full_printf_strv(Unit *u, char **l) {
-        size_t n;
-        char **r, **i, **j;
-
-        /* Applies unit_full_printf to every entry in l */
-
-        assert(u);
-
-        n = strv_length(l);
-        if (!(r = new(char*, n+1)))
-                return NULL;
-
-        for (i = l, j = r; *i; i++, j++)
-                if (!(*j = unit_full_printf(u, *i)))
-                        goto fail;
-
-        *j = NULL;
-        return r;
-
-fail:
-        j--;
-        while (j >= r)
-                free(*j);
-
-        free(r);
-
-        return NULL;
-}
-
-int unit_watch_bus_name(Unit *u, const char *name) {
-        assert(u);
-        assert(name);
-
-        /* Watch a specific name on the bus. We only support one unit
-         * watching each name for now. */
-
-        return hashmap_put(u->meta.manager->watch_bus, name, u);
-}
-
-void unit_unwatch_bus_name(Unit *u, const char *name) {
-        assert(u);
-        assert(name);
-
-        hashmap_remove_value(u->meta.manager->watch_bus, name, u);
-}
-
-bool unit_can_serialize(Unit *u) {
-        assert(u);
-
-        return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
-}
-
-int unit_serialize(Unit *u, FILE *f, FDSet *fds) {
-        int r;
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        if (!unit_can_serialize(u))
-                return 0;
-
-        if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
-                return r;
-
-        /* End marker */
-        fputc('\n', f);
-        return 0;
-}
-
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
-        va_list ap;
-
-        assert(u);
-        assert(f);
-        assert(key);
-        assert(format);
-
-        fputs(key, f);
-        fputc('=', f);
-
-        va_start(ap, format);
-        vfprintf(f, format, ap);
-        va_end(ap);
-
-        fputc('\n', f);
-}
-
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
-        assert(u);
-        assert(f);
-        assert(key);
-        assert(value);
-
-        fprintf(f, "%s=%s\n", key, value);
-}
-
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
-        int r;
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        if (!unit_can_serialize(u))
-                return 0;
-
-        for (;;) {
-                char line[1024], *l, *v;
-                size_t k;
-
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                return 0;
-                        return -errno;
-                }
-
-                l = strstrip(line);
-
-                /* End marker */
-                if (l[0] == 0)
-                        return 0;
-
-                k = strcspn(l, "=");
-
-                if (l[k] == '=') {
-                        l[k] = 0;
-                        v = l+k+1;
-                } else
-                        v = l+k;
-
-                if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
-                        return r;
-        }
-}
-
-int unit_add_node_link(Unit *u, const char *what, bool wants) {
-        Unit *device;
-        char *e;
-        int r;
-
-        assert(u);
-
-        if (!what)
-                return 0;
-
-        /* Adds in links to the device node that this unit is based on */
-
-        if (!is_device_path(what))
-                return 0;
-
-        if (!(e = unit_name_build_escape(what+1, NULL, ".device")))
-                return -ENOMEM;
-
-        r = manager_load_unit(u->meta.manager, e, NULL, &device);
-        free(e);
-
-        if (r < 0)
-                return r;
-
-        if ((r = unit_add_dependency(u, UNIT_AFTER, device, true)) < 0)
-                return r;
-
-        if ((r = unit_add_dependency(u, UNIT_REQUIRES, device, true)) < 0)
-                return r;
-
-        if (wants)
-                if ((r = unit_add_dependency(device, UNIT_WANTS, u, false)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
-        [UNIT_SERVICE] = "service",
-        [UNIT_TIMER] = "timer",
-        [UNIT_SOCKET] = "socket",
-        [UNIT_TARGET] = "target",
-        [UNIT_DEVICE] = "device",
-        [UNIT_MOUNT] = "mount",
-        [UNIT_AUTOMOUNT] = "automount",
-        [UNIT_SNAPSHOT] = "snapshot",
-        [UNIT_SWAP] = "swap"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
-
-static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
-        [UNIT_STUB] = "stub",
-        [UNIT_LOADED] = "loaded",
-        [UNIT_FAILED] = "failed",
-        [UNIT_MERGED] = "merged"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
-        [UNIT_ACTIVE] = "active",
-        [UNIT_INACTIVE] = "inactive",
-        [UNIT_ACTIVATING] = "activating",
-        [UNIT_DEACTIVATING] = "deactivating"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
-
-static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
-        [UNIT_REQUIRES] = "Requires",
-        [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
-        [UNIT_WANTS] = "Wants",
-        [UNIT_REQUISITE] = "Requisite",
-        [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
-        [UNIT_REQUIRED_BY] = "RequiredBy",
-        [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
-        [UNIT_WANTED_BY] = "WantedBy",
-        [UNIT_CONFLICTS] = "Conflicts",
-        [UNIT_BEFORE] = "Before",
-        [UNIT_AFTER] = "After",
-        [UNIT_REFERENCES] = "References",
-        [UNIT_REFERENCED_BY] = "ReferencedBy"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
-
-static const char* const kill_mode_table[_KILL_MODE_MAX] = {
-        [KILL_CONTROL_GROUP] = "control-group",
-        [KILL_PROCESS_GROUP] = "process-group",
-        [KILL_PROCESS] = "process",
-        [KILL_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
diff --git a/unit.h b/unit.h
deleted file mode 100644
index 8f9d9e9..0000000
--- a/unit.h
+++ /dev/null
@@ -1,448 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef foounithfoo
-#define foounithfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <stdlib.h>
-
-typedef union Unit Unit;
-typedef struct Meta Meta;
-typedef struct UnitVTable UnitVTable;
-typedef enum UnitType UnitType;
-typedef enum UnitLoadState UnitLoadState;
-typedef enum UnitActiveState UnitActiveState;
-typedef enum UnitDependency UnitDependency;
-
-#include "set.h"
-#include "util.h"
-#include "list.h"
-#include "socket-util.h"
-#include "execute.h"
-
-#define UNIT_NAME_MAX 128
-#define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC)
-#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
-
-typedef enum KillMode {
-        KILL_CONTROL_GROUP = 0,
-        KILL_PROCESS_GROUP,
-        KILL_PROCESS,
-        KILL_NONE,
-        _KILL_MODE_MAX,
-        _KILL_MODE_INVALID = -1
-} KillMode;
-
-enum UnitType {
-        UNIT_SERVICE = 0,
-        UNIT_SOCKET,
-        UNIT_TARGET,
-        UNIT_DEVICE,
-        UNIT_MOUNT,
-        UNIT_AUTOMOUNT,
-        UNIT_SNAPSHOT,
-        UNIT_TIMER,
-        UNIT_SWAP,
-        _UNIT_TYPE_MAX,
-        _UNIT_TYPE_INVALID = -1
-};
-
-enum UnitLoadState {
-        UNIT_STUB,
-        UNIT_LOADED,
-        UNIT_FAILED,
-        UNIT_MERGED,
-        _UNIT_LOAD_STATE_MAX,
-        _UNIT_LOAD_STATE_INVALID = -1
-};
-
-enum UnitActiveState {
-        UNIT_ACTIVE,
-        UNIT_ACTIVE_RELOADING,
-        UNIT_INACTIVE,
-        UNIT_ACTIVATING,
-        UNIT_DEACTIVATING,
-        _UNIT_ACTIVE_STATE_MAX,
-        _UNIT_ACTIVE_STATE_INVALID = -1
-};
-
-static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) {
-        return t == UNIT_ACTIVE || t == UNIT_ACTIVE_RELOADING;
-}
-
-static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) {
-        return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_ACTIVE_RELOADING;
-}
-
-static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
-        return t == UNIT_INACTIVE || t == UNIT_DEACTIVATING;
-}
-
-enum UnitDependency {
-        /* Positive dependencies */
-        UNIT_REQUIRES,
-        UNIT_REQUIRES_OVERRIDABLE,
-        UNIT_REQUISITE,
-        UNIT_REQUISITE_OVERRIDABLE,
-        UNIT_WANTS,
-
-        /* Inverse of the above */
-        UNIT_REQUIRED_BY,             /* inverse of 'requires' and 'requisite' is 'required_by' */
-        UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'soft_requires' and 'soft_requisite' is 'soft_required_by' */
-        UNIT_WANTED_BY,               /* inverse of 'wants' */
-
-        /* Negative dependencies */
-        UNIT_CONFLICTS,               /* inverse of 'conflicts' is 'conflicts' */
-
-        /* Order */
-        UNIT_BEFORE,                  /* inverse of 'before' is 'after' and vice versa */
-        UNIT_AFTER,
-
-        /* Reference information for GC logic */
-        UNIT_REFERENCES,              /* Inverse of 'references' is 'referenced_by' */
-        UNIT_REFERENCED_BY,
-
-        _UNIT_DEPENDENCY_MAX,
-        _UNIT_DEPENDENCY_INVALID = -1
-};
-
-#include "manager.h"
-#include "job.h"
-#include "cgroup.h"
-
-struct Meta {
-        Manager *manager;
-
-        UnitType type;
-        UnitLoadState load_state;
-        Unit *merged_into;
-
-        char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
-        char *instance;
-
-        Set *names;
-        Set *dependencies[_UNIT_DEPENDENCY_MAX];
-
-        char *description;
-        char *fragment_path; /* if loaded from a config file this is the primary path to it */
-
-        /* If there is something to do with this unit, then this is
-         * the job for it */
-        Job *job;
-
-        usec_t inactive_exit_timestamp;
-        usec_t active_enter_timestamp;
-        usec_t active_exit_timestamp;
-        usec_t inactive_enter_timestamp;
-
-        /* Counterparts in the cgroup filesystem */
-        CGroupBonding *cgroup_bondings;
-
-        /* Per type list */
-        LIST_FIELDS(Meta, units_per_type);
-
-        /* Load queue */
-        LIST_FIELDS(Meta, load_queue);
-
-        /* D-Bus queue */
-        LIST_FIELDS(Meta, dbus_queue);
-
-        /* Cleanup queue */
-        LIST_FIELDS(Meta, cleanup_queue);
-
-        /* GC queue */
-        LIST_FIELDS(Meta, gc_queue);
-
-        /* Used during GC sweeps */
-        unsigned gc_marker;
-
-        /* If we go down, pull down everything that depends on us, too */
-        bool recursive_stop;
-
-        /* Garbage collect us we nobody wants or requires us anymore */
-        bool stop_when_unneeded;
-
-        bool in_load_queue:1;
-        bool in_dbus_queue:1;
-        bool in_cleanup_queue:1;
-        bool in_gc_queue:1;
-
-        bool sent_dbus_new_signal:1;
-};
-
-#include "service.h"
-#include "timer.h"
-#include "socket.h"
-#include "target.h"
-#include "device.h"
-#include "mount.h"
-#include "automount.h"
-#include "snapshot.h"
-#include "swap.h"
-
-union Unit {
-        Meta meta;
-        Service service;
-        Timer timer;
-        Socket socket;
-        Target target;
-        Device device;
-        Mount mount;
-        Automount automount;
-        Snapshot snapshot;
-        Swap swap;
-};
-
-struct UnitVTable {
-        const char *suffix;
-
-        /* This should reset all type-specific variables. This should
-         * not allocate memory, and is called with zero-initialized
-         * data. It should hence only initialize variables that need
-         * to be set != 0. */
-        void (*init)(Unit *u);
-
-        /* This should free all type-specific variables. It should be
-         * idempotent. */
-        void (*done)(Unit *u);
-
-        /* Actually load data from disk. This may fail, and should set
-         * load_state to UNIT_LOADED, UNIT_MERGED or leave it at
-         * UNIT_STUB if no configuration could be found. */
-        int (*load)(Unit *u);
-
-        /* If a a lot of units got created via enumerate(), this is
-         * where to actually set the state and call unit_notify(). */
-        int (*coldplug)(Unit *u);
-
-        void (*dump)(Unit *u, FILE *f, const char *prefix);
-
-        int (*start)(Unit *u);
-        int (*stop)(Unit *u);
-        int (*reload)(Unit *u);
-
-        bool (*can_reload)(Unit *u);
-
-        /* Write all data that cannot be restored from other sources
-         * away using unit_serialize_item() */
-        int (*serialize)(Unit *u, FILE *f, FDSet *fds);
-
-        /* Restore one item from the serialization */
-        int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds);
-
-        /* Boils down the more complex internal state of this unit to
-         * a simpler one that the engine can understand */
-        UnitActiveState (*active_state)(Unit *u);
-
-        /* Returns the substate specific to this unit type as
-         * string. This is purely information so that we can give the
-         * user a more finegrained explanation in which actual state a
-         * unit is in. */
-        const char* (*sub_state_to_string)(Unit *u);
-
-        /* Return true when there is reason to keep this entry around
-         * even nothing references it and it isn't active in any
-         * way */
-        bool (*check_gc)(Unit *u);
-
-        /* Return true when this unit is suitable for snapshotting */
-        bool (*check_snapshot)(Unit *u);
-
-        void (*fd_event)(Unit *u, int fd, uint32_t events, Watch *w);
-        void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
-        void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
-
-        /* Called whenever any of the cgroups this unit watches for
-         * ran empty */
-        void (*cgroup_notify_empty)(Unit *u);
-
-        /* Called whenever a name thus Unit registered for comes or
-         * goes away. */
-        void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner);
-
-        /* Called whenever a bus PID lookup finishes */
-        void (*bus_query_pid_done)(Unit *u, const char *name, pid_t pid);
-
-        /* Called for each message received on the bus */
-        DBusHandlerResult (*bus_message_handler)(Unit *u, DBusMessage *message);
-
-        /* This is called for each unit type and should be used to
-         * enumerate existing devices and load them. However,
-         * everything that is loaded here should still stay in
-         * inactive state. It is the job of the coldplug() call above
-         * to put the units into the initial state.  */
-        int (*enumerate)(Manager *m);
-
-        /* Type specific cleanups. */
-        void (*shutdown)(Manager *m);
-
-        /* Can units of this type have multiple names? */
-        bool no_alias:1;
-
-        /* If true units of this types can never have "Requires"
-         * dependencies, because state changes can only be observed,
-         * not triggered */
-        bool no_requires:1;
-
-        /* Instances make no sense for this type */
-        bool no_instances:1;
-
-        /* Exclude this type from snapshots */
-        bool no_snapshots:1;
-
-        /* Exclude from automatic gc */
-        bool no_gc:1;
-
-        /* Exclude from isolation requests */
-        bool no_isolate:1;
-};
-
-extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
-
-#define UNIT_VTABLE(u) unit_vtable[(u)->meta.type]
-
-/* For casting a unit into the various unit types */
-#define DEFINE_CAST(UPPERCASE, MixedCase)                               \
-        static inline MixedCase* UPPERCASE(Unit *u) {                   \
-                if (!u || u->meta.type != UNIT_##UPPERCASE)             \
-                        return NULL;                                    \
-                                                                        \
-                return (MixedCase*) u;                                  \
-        }
-
-/* For casting the various unit types into a unit */
-#define UNIT(u) ((Unit*) (u))
-
-DEFINE_CAST(SOCKET, Socket);
-DEFINE_CAST(TIMER, Timer);
-DEFINE_CAST(SERVICE, Service);
-DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(DEVICE, Device);
-DEFINE_CAST(MOUNT, Mount);
-DEFINE_CAST(AUTOMOUNT, Automount);
-DEFINE_CAST(SNAPSHOT, Snapshot);
-DEFINE_CAST(SWAP, Swap);
-
-Unit *unit_new(Manager *m);
-void unit_free(Unit *u);
-
-int unit_add_name(Unit *u, const char *name);
-
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference);
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-
-int unit_add_exec_dependencies(Unit *u, ExecContext *c);
-
-int unit_add_cgroup(Unit *u, CGroupBonding *b);
-int unit_add_cgroup_from_text(Unit *u, const char *name);
-int unit_add_default_cgroup(Unit *u);
-CGroupBonding* unit_get_default_cgroup(Unit *u);
-
-int unit_choose_id(Unit *u, const char *name);
-int unit_set_description(Unit *u, const char *description);
-
-bool unit_check_gc(Unit *u);
-
-void unit_add_to_load_queue(Unit *u);
-void unit_add_to_dbus_queue(Unit *u);
-void unit_add_to_cleanup_queue(Unit *u);
-void unit_add_to_gc_queue(Unit *u);
-
-int unit_merge(Unit *u, Unit *other);
-int unit_merge_by_name(Unit *u, const char *other);
-
-Unit *unit_follow_merge(Unit *u);
-
-int unit_load_fragment_and_dropin(Unit *u);
-int unit_load_fragment_and_dropin_optional(Unit *u);
-int unit_load_nop(Unit *u);
-int unit_load(Unit *unit);
-
-const char *unit_description(Unit *u);
-
-bool unit_has_name(Unit *u, const char *name);
-
-UnitActiveState unit_active_state(Unit *u);
-
-const char* unit_sub_state_to_string(Unit *u);
-
-void unit_dump(Unit *u, FILE *f, const char *prefix);
-
-bool unit_can_reload(Unit *u);
-bool unit_can_start(Unit *u);
-
-int unit_start(Unit *u);
-int unit_stop(Unit *u);
-int unit_reload(Unit *u);
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns);
-
-int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w);
-void unit_unwatch_fd(Unit *u, Watch *w);
-
-int unit_watch_pid(Unit *u, pid_t pid);
-void unit_unwatch_pid(Unit *u, pid_t pid);
-
-int unit_watch_timer(Unit *u, usec_t delay, Watch *w);
-void unit_unwatch_timer(Unit *u, Watch *w);
-
-int unit_watch_bus_name(Unit *u, const char *name);
-void unit_unwatch_bus_name(Unit *u, const char *name);
-
-bool unit_job_is_applicable(Unit *u, JobType j);
-
-int set_unit_path(const char *p);
-
-char *unit_dbus_path(Unit *u);
-
-int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
-int unit_get_related_unit(Unit *u, const char *type, Unit **_found);
-
-char *unit_name_printf(Unit *u, const char* text);
-char *unit_full_printf(Unit *u, const char *text);
-char **unit_full_printf_strv(Unit *u, char **l);
-
-bool unit_can_serialize(Unit *u);
-int unit_serialize(Unit *u, FILE *f, FDSet *fds);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr(4,5);
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
-
-int unit_add_node_link(Unit *u, const char *what, bool wants);
-
-const char *unit_type_to_string(UnitType i);
-UnitType unit_type_from_string(const char *s);
-
-const char *unit_load_state_to_string(UnitLoadState i);
-UnitLoadState unit_load_state_from_string(const char *s);
-
-const char *unit_active_state_to_string(UnitActiveState i);
-UnitActiveState unit_active_state_from_string(const char *s);
-
-const char *unit_dependency_to_string(UnitDependency i);
-UnitDependency unit_dependency_from_string(const char *s);
-
-const char *kill_mode_to_string(KillMode k);
-KillMode kill_mode_from_string(const char *s);
-
-#endif
diff --git a/util.c b/util.c
deleted file mode 100644
index f7d538a..0000000
--- a/util.c
+++ /dev/null
@@ -1,2027 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <sched.h>
-#include <sys/resource.h>
-#include <linux/sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <termios.h>
-#include <stdarg.h>
-#include <sys/inotify.h>
-#include <sys/poll.h>
-#include <libgen.h>
-#include <ctype.h>
-
-#include "macro.h"
-#include "util.h"
-#include "ioprio.h"
-#include "missing.h"
-#include "log.h"
-#include "strv.h"
-
-bool streq_ptr(const char *a, const char *b) {
-
-        /* Like streq(), but tries to make sense of NULL pointers */
-
-        if (a && b)
-                return streq(a, b);
-
-        if (!a && !b)
-                return true;
-
-        return false;
-}
-
-usec_t now(clockid_t clock_id) {
-        struct timespec ts;
-
-        assert_se(clock_gettime(clock_id, &ts) == 0);
-
-        return timespec_load(&ts);
-}
-
-usec_t timespec_load(const struct timespec *ts) {
-        assert(ts);
-
-        return
-                (usec_t) ts->tv_sec * USEC_PER_SEC +
-                (usec_t) ts->tv_nsec / NSEC_PER_USEC;
-}
-
-struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
-        assert(ts);
-
-        ts->tv_sec = (time_t) (u / USEC_PER_SEC);
-        ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
-
-        return ts;
-}
-
-usec_t timeval_load(const struct timeval *tv) {
-        assert(tv);
-
-        return
-                (usec_t) tv->tv_sec * USEC_PER_SEC +
-                (usec_t) tv->tv_usec;
-}
-
-struct timeval *timeval_store(struct timeval *tv, usec_t u) {
-        assert(tv);
-
-        tv->tv_sec = (time_t) (u / USEC_PER_SEC);
-        tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
-
-        return tv;
-}
-
-bool endswith(const char *s, const char *postfix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(postfix);
-
-        sl = strlen(s);
-        pl = strlen(postfix);
-
-        if (pl == 0)
-                return true;
-
-        if (sl < pl)
-                return false;
-
-        return memcmp(s + sl - pl, postfix, pl) == 0;
-}
-
-bool startswith(const char *s, const char *prefix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(prefix);
-
-        sl = strlen(s);
-        pl = strlen(prefix);
-
-        if (pl == 0)
-                return true;
-
-        if (sl < pl)
-                return false;
-
-        return memcmp(s, prefix, pl) == 0;
-}
-
-bool startswith_no_case(const char *s, const char *prefix) {
-        size_t sl, pl;
-        unsigned i;
-
-        assert(s);
-        assert(prefix);
-
-        sl = strlen(s);
-        pl = strlen(prefix);
-
-        if (pl == 0)
-                return true;
-
-        if (sl < pl)
-                return false;
-
-        for(i = 0; i < pl; ++i) {
-                if (tolower(s[i]) != tolower(prefix[i]))
-                        return false;
-        }
-
-        return true;
-}
-
-bool first_word(const char *s, const char *word) {
-        size_t sl, wl;
-
-        assert(s);
-        assert(word);
-
-        sl = strlen(s);
-        wl = strlen(word);
-
-        if (sl < wl)
-                return false;
-
-        if (wl == 0)
-                return true;
-
-        if (memcmp(s, word, wl) != 0)
-                return false;
-
-        return s[wl] == 0 ||
-                strchr(WHITESPACE, s[wl]);
-}
-
-int close_nointr(int fd) {
-        assert(fd >= 0);
-
-        for (;;) {
-                int r;
-
-                if ((r = close(fd)) >= 0)
-                        return r;
-
-                if (errno != EINTR)
-                        return r;
-        }
-}
-
-void close_nointr_nofail(int fd) {
-        int saved_errno = errno;
-
-        /* like close_nointr() but cannot fail, and guarantees errno
-         * is unchanged */
-
-        assert_se(close_nointr(fd) == 0);
-
-        errno = saved_errno;
-}
-
-int parse_boolean(const char *v) {
-        assert(v);
-
-        if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
-                return 1;
-        else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
-                return 0;
-
-        return -EINVAL;
-}
-
-int safe_atou(const char *s, unsigned *ret_u) {
-        char *x = NULL;
-        unsigned long l;
-
-        assert(s);
-        assert(ret_u);
-
-        errno = 0;
-        l = strtoul(s, &x, 0);
-
-        if (!x || *x || errno)
-                return errno ? -errno : -EINVAL;
-
-        if ((unsigned long) (unsigned) l != l)
-                return -ERANGE;
-
-        *ret_u = (unsigned) l;
-        return 0;
-}
-
-int safe_atoi(const char *s, int *ret_i) {
-        char *x = NULL;
-        long l;
-
-        assert(s);
-        assert(ret_i);
-
-        errno = 0;
-        l = strtol(s, &x, 0);
-
-        if (!x || *x || errno)
-                return errno ? -errno : -EINVAL;
-
-        if ((long) (int) l != l)
-                return -ERANGE;
-
-        *ret_i = (int) l;
-        return 0;
-}
-
-int safe_atolu(const char *s, long unsigned *ret_lu) {
-        char *x = NULL;
-        unsigned long l;
-
-        assert(s);
-        assert(ret_lu);
-
-        errno = 0;
-        l = strtoul(s, &x, 0);
-
-        if (!x || *x || errno)
-                return errno ? -errno : -EINVAL;
-
-        *ret_lu = l;
-        return 0;
-}
-
-int safe_atoli(const char *s, long int *ret_li) {
-        char *x = NULL;
-        long l;
-
-        assert(s);
-        assert(ret_li);
-
-        errno = 0;
-        l = strtol(s, &x, 0);
-
-        if (!x || *x || errno)
-                return errno ? -errno : -EINVAL;
-
-        *ret_li = l;
-        return 0;
-}
-
-int safe_atollu(const char *s, long long unsigned *ret_llu) {
-        char *x = NULL;
-        unsigned long long l;
-
-        assert(s);
-        assert(ret_llu);
-
-        errno = 0;
-        l = strtoull(s, &x, 0);
-
-        if (!x || *x || errno)
-                return errno ? -errno : -EINVAL;
-
-        *ret_llu = l;
-        return 0;
-}
-
-int safe_atolli(const char *s, long long int *ret_lli) {
-        char *x = NULL;
-        long long l;
-
-        assert(s);
-        assert(ret_lli);
-
-        errno = 0;
-        l = strtoll(s, &x, 0);
-
-        if (!x || *x || errno)
-                return errno ? -errno : -EINVAL;
-
-        *ret_lli = l;
-        return 0;
-}
-
-/* Split a string into words. */
-char *split(const char *c, size_t *l, const char *separator, char **state) {
-        char *current;
-
-        current = *state ? *state : (char*) c;
-
-        if (!*current || *c == 0)
-                return NULL;
-
-        current += strspn(current, separator);
-        *l = strcspn(current, separator);
-        *state = current+*l;
-
-        return (char*) current;
-}
-
-/* Split a string into words, but consider strings enclosed in '' and
- * "" as words even if they include spaces. */
-char *split_quoted(const char *c, size_t *l, char **state) {
-        char *current;
-
-        current = *state ? *state : (char*) c;
-
-        if (!*current || *c == 0)
-                return NULL;
-
-        current += strspn(current, WHITESPACE);
-
-        if (*current == '\'') {
-                current ++;
-                *l = strcspn(current, "'");
-                *state = current+*l;
-
-                if (**state == '\'')
-                        (*state)++;
-        } else if (*current == '\"') {
-                current ++;
-                *l = strcspn(current, "\"");
-                *state = current+*l;
-
-                if (**state == '\"')
-                        (*state)++;
-        } else {
-                *l = strcspn(current, WHITESPACE);
-                *state = current+*l;
-        }
-
-        /* FIXME: Cannot deal with strings that have spaces AND ticks
-         * in them */
-
-        return (char*) current;
-}
-
-char **split_path_and_make_absolute(const char *p) {
-        char **l;
-        assert(p);
-
-        if (!(l = strv_split(p, ":")))
-                return NULL;
-
-        if (!strv_path_make_absolute_cwd(l)) {
-                strv_free(l);
-                return NULL;
-        }
-
-        return l;
-}
-
-int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
-        int r;
-        FILE *f;
-        char fn[132], line[256], *p;
-        long long unsigned ppid;
-
-        assert(pid >= 0);
-        assert(_ppid);
-
-        assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
-        fn[sizeof(fn)-1] = 0;
-
-        if (!(f = fopen(fn, "r")))
-                return -errno;
-
-        if (!(fgets(line, sizeof(line), f))) {
-                r = -errno;
-                fclose(f);
-                return r;
-        }
-
-        fclose(f);
-
-        /* Let's skip the pid and comm fields. The latter is enclosed
-         * in () but does not escape any () in its value, so let's
-         * skip over it manually */
-
-        if (!(p = strrchr(line, ')')))
-                return -EIO;
-
-        p++;
-
-        if (sscanf(p, " "
-                   "%*c "  /* state */
-                   "%llu ", /* ppid */
-                   &ppid) != 1)
-                return -EIO;
-
-        if ((long long unsigned) (pid_t) ppid != ppid)
-                return -ERANGE;
-
-        *_ppid = (pid_t) ppid;
-
-        return 0;
-}
-
-int write_one_line_file(const char *fn, const char *line) {
-        FILE *f;
-        int r;
-
-        assert(fn);
-        assert(line);
-
-        if (!(f = fopen(fn, "we")))
-                return -errno;
-
-        if (fputs(line, f) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        r = 0;
-finish:
-        fclose(f);
-        return r;
-}
-
-int read_one_line_file(const char *fn, char **line) {
-        FILE *f;
-        int r;
-        char t[2048], *c;
-
-        assert(fn);
-        assert(line);
-
-        if (!(f = fopen(fn, "re")))
-                return -errno;
-
-        if (!(fgets(t, sizeof(t), f))) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (!(c = strdup(t))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        *line = c;
-        r = 0;
-
-finish:
-        fclose(f);
-        return r;
-}
-
-char *truncate_nl(char *s) {
-        assert(s);
-
-        s[strcspn(s, NEWLINE)] = 0;
-        return s;
-}
-
-int get_process_name(pid_t pid, char **name) {
-        char *p;
-        int r;
-
-        assert(pid >= 1);
-        assert(name);
-
-        if (asprintf(&p, "/proc/%llu/comm", (unsigned long long) pid) < 0)
-                return -ENOMEM;
-
-        r = read_one_line_file(p, name);
-        free(p);
-
-        if (r < 0)
-                return r;
-
-        truncate_nl(*name);
-        return 0;
-}
-
-char *strappend(const char *s, const char *suffix) {
-        size_t a, b;
-        char *r;
-
-        assert(s);
-        assert(suffix);
-
-        a = strlen(s);
-        b = strlen(suffix);
-
-        if (!(r = new(char, a+b+1)))
-                return NULL;
-
-        memcpy(r, s, a);
-        memcpy(r+a, suffix, b);
-        r[a+b] = 0;
-
-        return r;
-}
-
-int readlink_malloc(const char *p, char **r) {
-        size_t l = 100;
-
-        assert(p);
-        assert(r);
-
-        for (;;) {
-                char *c;
-                ssize_t n;
-
-                if (!(c = new(char, l)))
-                        return -ENOMEM;
-
-                if ((n = readlink(p, c, l-1)) < 0) {
-                        int ret = -errno;
-                        free(c);
-                        return ret;
-                }
-
-                if ((size_t) n < l-1) {
-                        c[n] = 0;
-                        *r = c;
-                        return 0;
-                }
-
-                free(c);
-                l *= 2;
-        }
-}
-
-char *file_name_from_path(const char *p) {
-        char *r;
-
-        assert(p);
-
-        if ((r = strrchr(p, '/')))
-                return r + 1;
-
-        return (char*) p;
-}
-
-bool path_is_absolute(const char *p) {
-        assert(p);
-
-        return p[0] == '/';
-}
-
-bool is_path(const char *p) {
-
-        return !!strchr(p, '/');
-}
-
-char *path_make_absolute(const char *p, const char *prefix) {
-        char *r;
-
-        assert(p);
-
-        /* Makes every item in the list an absolute path by prepending
-         * the prefix, if specified and necessary */
-
-        if (path_is_absolute(p) || !prefix)
-                return strdup(p);
-
-        if (asprintf(&r, "%s/%s", prefix, p) < 0)
-                return NULL;
-
-        return r;
-}
-
-char *path_make_absolute_cwd(const char *p) {
-        char *cwd, *r;
-
-        assert(p);
-
-        /* Similar to path_make_absolute(), but prefixes with the
-         * current working directory. */
-
-        if (path_is_absolute(p))
-                return strdup(p);
-
-        if (!(cwd = get_current_dir_name()))
-                return NULL;
-
-        r = path_make_absolute(p, cwd);
-        free(cwd);
-
-        return r;
-}
-
-char **strv_path_make_absolute_cwd(char **l) {
-        char **s;
-
-        /* Goes through every item in the string list and makes it
-         * absolute. This works in place and won't rollback any
-         * changes on failure. */
-
-        STRV_FOREACH(s, l) {
-                char *t;
-
-                if (!(t = path_make_absolute_cwd(*s)))
-                        return NULL;
-
-                free(*s);
-                *s = t;
-        }
-
-        return l;
-}
-
-int reset_all_signal_handlers(void) {
-        int sig;
-
-        for (sig = 1; sig < _NSIG; sig++) {
-                struct sigaction sa;
-
-                if (sig == SIGKILL || sig == SIGSTOP)
-                        continue;
-
-                zero(sa);
-                sa.sa_handler = SIG_DFL;
-                sa.sa_flags = SA_RESTART;
-
-                /* On Linux the first two RT signals are reserved by
-                 * glibc, and sigaction() will return EINVAL for them. */
-                if ((sigaction(sig, &sa, NULL) < 0))
-                        if (errno != EINVAL)
-                                return -errno;
-        }
-
-        return 0;
-}
-
-char *strstrip(char *s) {
-        char *e, *l = NULL;
-
-        /* Drops trailing whitespace. Modifies the string in
-         * place. Returns pointer to first non-space character */
-
-        s += strspn(s, WHITESPACE);
-
-        for (e = s; *e; e++)
-                if (!strchr(WHITESPACE, *e))
-                        l = e;
-
-        if (l)
-                *(l+1) = 0;
-        else
-                *s = 0;
-
-        return s;
-}
-
-char *delete_chars(char *s, const char *bad) {
-        char *f, *t;
-
-        /* Drops all whitespace, regardless where in the string */
-
-        for (f = s, t = s; *f; f++) {
-                if (strchr(bad, *f))
-                        continue;
-
-                *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return s;
-}
-
-char *file_in_same_dir(const char *path, const char *filename) {
-        char *e, *r;
-        size_t k;
-
-        assert(path);
-        assert(filename);
-
-        /* This removes the last component of path and appends
-         * filename, unless the latter is absolute anyway or the
-         * former isn't */
-
-        if (path_is_absolute(filename))
-                return strdup(filename);
-
-        if (!(e = strrchr(path, '/')))
-                return strdup(filename);
-
-        k = strlen(filename);
-        if (!(r = new(char, e-path+1+k+1)))
-                return NULL;
-
-        memcpy(r, path, e-path+1);
-        memcpy(r+(e-path)+1, filename, k+1);
-
-        return r;
-}
-
-int mkdir_parents(const char *path, mode_t mode) {
-        const char *p, *e;
-
-        assert(path);
-
-        /* Creates every parent directory in the path except the last
-         * component. */
-
-        p = path + strspn(path, "/");
-        for (;;) {
-                int r;
-                char *t;
-
-                e = p + strcspn(p, "/");
-                p = e + strspn(e, "/");
-
-                /* Is this the last component? If so, then we're
-                 * done */
-                if (*p == 0)
-                        return 0;
-
-                if (!(t = strndup(path, e - path)))
-                        return -ENOMEM;
-
-                r = mkdir(t, mode);
-
-                free(t);
-
-                if (r < 0 && errno != EEXIST)
-                        return -errno;
-        }
-}
-
-int mkdir_p(const char *path, mode_t mode) {
-        int r;
-
-        /* Like mkdir -p */
-
-        if ((r = mkdir_parents(path, mode)) < 0)
-                return r;
-
-        if (mkdir(path, mode) < 0)
-                return -errno;
-
-        return 0;
-}
-
-char hexchar(int x) {
-        static const char table[16] = "0123456789abcdef";
-
-        return table[x & 15];
-}
-
-int unhexchar(char c) {
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        if (c >= 'a' && c <= 'f')
-                return c - 'a' + 10;
-
-        if (c >= 'A' && c <= 'F')
-                return c - 'A' + 10;
-
-        return -1;
-}
-
-char octchar(int x) {
-        return '0' + (x & 7);
-}
-
-int unoctchar(char c) {
-
-        if (c >= '0' && c <= '7')
-                return c - '0';
-
-        return -1;
-}
-
-char decchar(int x) {
-        return '0' + (x % 10);
-}
-
-int undecchar(char c) {
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        return -1;
-}
-
-char *cescape(const char *s) {
-        char *r, *t;
-        const char *f;
-
-        assert(s);
-
-        /* Does C style string escaping. */
-
-        if (!(r = new(char, strlen(s)*4 + 1)))
-                return NULL;
-
-        for (f = s, t = r; *f; f++)
-
-                switch (*f) {
-
-                case '\a':
-                        *(t++) = '\\';
-                        *(t++) = 'a';
-                        break;
-                case '\b':
-                        *(t++) = '\\';
-                        *(t++) = 'b';
-                        break;
-                case '\f':
-                        *(t++) = '\\';
-                        *(t++) = 'f';
-                        break;
-                case '\n':
-                        *(t++) = '\\';
-                        *(t++) = 'n';
-                        break;
-                case '\r':
-                        *(t++) = '\\';
-                        *(t++) = 'r';
-                        break;
-                case '\t':
-                        *(t++) = '\\';
-                        *(t++) = 't';
-                        break;
-                case '\v':
-                        *(t++) = '\\';
-                        *(t++) = 'v';
-                        break;
-                case '\\':
-                        *(t++) = '\\';
-                        *(t++) = '\\';
-                        break;
-                case '"':
-                        *(t++) = '\\';
-                        *(t++) = '"';
-                        break;
-                case '\'':
-                        *(t++) = '\\';
-                        *(t++) = '\'';
-                        break;
-
-                default:
-                        /* For special chars we prefer octal over
-                         * hexadecimal encoding, simply because glib's
-                         * g_strescape() does the same */
-                        if ((*f < ' ') || (*f >= 127)) {
-                                *(t++) = '\\';
-                                *(t++) = octchar((unsigned char) *f >> 6);
-                                *(t++) = octchar((unsigned char) *f >> 3);
-                                *(t++) = octchar((unsigned char) *f);
-                        } else
-                                *(t++) = *f;
-                        break;
-                }
-
-        *t = 0;
-
-        return r;
-}
-
-char *cunescape(const char *s) {
-        char *r, *t;
-        const char *f;
-
-        assert(s);
-
-        /* Undoes C style string escaping */
-
-        if (!(r = new(char, strlen(s)+1)))
-                return r;
-
-        for (f = s, t = r; *f; f++) {
-
-                if (*f != '\\') {
-                        *(t++) = *f;
-                        continue;
-                }
-
-                f++;
-
-                switch (*f) {
-
-                case 'a':
-                        *(t++) = '\a';
-                        break;
-                case 'b':
-                        *(t++) = '\b';
-                        break;
-                case 'f':
-                        *(t++) = '\f';
-                        break;
-                case 'n':
-                        *(t++) = '\n';
-                        break;
-                case 'r':
-                        *(t++) = '\r';
-                        break;
-                case 't':
-                        *(t++) = '\t';
-                        break;
-                case 'v':
-                        *(t++) = '\v';
-                        break;
-                case '\\':
-                        *(t++) = '\\';
-                        break;
-                case '"':
-                        *(t++) = '"';
-                        break;
-                case '\'':
-                        *(t++) = '\'';
-                        break;
-
-                case 'x': {
-                        /* hexadecimal encoding */
-                        int a, b;
-
-                        if ((a = unhexchar(f[1])) < 0 ||
-                            (b = unhexchar(f[2])) < 0) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                *(t++) = 'x';
-                        } else {
-                                *(t++) = (char) ((a << 4) | b);
-                                f += 2;
-                        }
-
-                        break;
-                }
-
-                case '0':
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7': {
-                        /* octal encoding */
-                        int a, b, c;
-
-                        if ((a = unoctchar(f[0])) < 0 ||
-                            (b = unoctchar(f[1])) < 0 ||
-                            (c = unoctchar(f[2])) < 0) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                *(t++) = f[0];
-                        } else {
-                                *(t++) = (char) ((a << 6) | (b << 3) | c);
-                                f += 2;
-                        }
-
-                        break;
-                }
-
-                case 0:
-                        /* premature end of string.*/
-                        *(t++) = '\\';
-                        goto finish;
-
-                default:
-                        /* Invalid escape code, let's take it literal then */
-                        *(t++) = '\\';
-                        *(t++) = 'f';
-                        break;
-                }
-        }
-
-finish:
-        *t = 0;
-        return r;
-}
-
-
-char *xescape(const char *s, const char *bad) {
-        char *r, *t;
-        const char *f;
-
-        /* Escapes all chars in bad, in addition to \ and all special
-         * chars, in \xFF style escaping. May be reversed with
-         * cunescape. */
-
-        if (!(r = new(char, strlen(s)*4+1)))
-                return NULL;
-
-        for (f = s, t = r; *f; f++) {
-
-                if ((*f < ' ') || (*f >= 127) ||
-                    (*f == '\\') || strchr(bad, *f)) {
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-char *bus_path_escape(const char *s) {
-        char *r, *t;
-        const char *f;
-
-        assert(s);
-
-        /* Escapes all chars that D-Bus' object path cannot deal
-         * with. Can be reverse with bus_path_unescape() */
-
-        if (!(r = new(char, strlen(s)*3+1)))
-                return NULL;
-
-        for (f = s, t = r; *f; f++) {
-
-                if (!(*f >= 'A' && *f <= 'Z') &&
-                    !(*f >= 'a' && *f <= 'z') &&
-                    !(*f >= '0' && *f <= '9')) {
-                        *(t++) = '_';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-char *bus_path_unescape(const char *f) {
-        char *r, *t;
-
-        assert(f);
-
-        if (!(r = strdup(f)))
-                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;
-}
-
-char *path_kill_slashes(char *path) {
-        char *f, *t;
-        bool slash = false;
-
-        /* Removes redundant inner and trailing slashes. Modifies the
-         * passed string in-place.
-         *
-         * ///foo///bar/ becomes /foo/bar
-         */
-
-        for (f = path, t = path; *f; f++) {
-
-                if (*f == '/') {
-                        slash = true;
-                        continue;
-                }
-
-                if (slash) {
-                        slash = false;
-                        *(t++) = '/';
-                }
-
-                *(t++) = *f;
-        }
-
-        /* Special rule, if we are talking of the root directory, a
-        trailing slash is good */
-
-        if (t == path && slash)
-                *(t++) = '/';
-
-        *t = 0;
-        return path;
-}
-
-bool path_startswith(const char *path, const char *prefix) {
-        assert(path);
-        assert(prefix);
-
-        if ((path[0] == '/') != (prefix[0] == '/'))
-                return false;
-
-        for (;;) {
-                size_t a, b;
-
-                path += strspn(path, "/");
-                prefix += strspn(prefix, "/");
-
-                if (*prefix == 0)
-                        return true;
-
-                if (*path == 0)
-                        return false;
-
-                a = strcspn(path, "/");
-                b = strcspn(prefix, "/");
-
-                if (a != b)
-                        return false;
-
-                if (memcmp(path, prefix, a) != 0)
-                        return false;
-
-                path += a;
-                prefix += b;
-        }
-}
-
-bool path_equal(const char *a, const char *b) {
-        assert(a);
-        assert(b);
-
-        if ((a[0] == '/') != (b[0] == '/'))
-                return false;
-
-        for (;;) {
-                size_t j, k;
-
-                a += strspn(a, "/");
-                b += strspn(b, "/");
-
-                if (*a == 0 && *b == 0)
-                        return true;
-
-                if (*a == 0 || *b == 0)
-                        return false;
-
-                j = strcspn(a, "/");
-                k = strcspn(b, "/");
-
-                if (j != k)
-                        return false;
-
-                if (memcmp(a, b, j) != 0)
-                        return false;
-
-                a += j;
-                b += k;
-        }
-}
-
-char *ascii_strlower(char *t) {
-        char *p;
-
-        assert(t);
-
-        for (p = t; *p; p++)
-                if (*p >= 'A' && *p <= 'Z')
-                        *p = *p - 'A' + 'a';
-
-        return t;
-}
-
-bool ignore_file(const char *filename) {
-        assert(filename);
-
-        return
-                filename[0] == '.' ||
-                streq(filename, "lost+found") ||
-                endswith(filename, "~") ||
-                endswith(filename, ".rpmnew") ||
-                endswith(filename, ".rpmsave") ||
-                endswith(filename, ".rpmorig") ||
-                endswith(filename, ".dpkg-old") ||
-                endswith(filename, ".dpkg-new") ||
-                endswith(filename, ".swp");
-}
-
-int fd_nonblock(int fd, bool nonblock) {
-        int flags;
-
-        assert(fd >= 0);
-
-        if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
-                return -errno;
-
-        if (nonblock)
-                flags |= O_NONBLOCK;
-        else
-                flags &= ~O_NONBLOCK;
-
-        if (fcntl(fd, F_SETFL, flags) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int fd_cloexec(int fd, bool cloexec) {
-        int flags;
-
-        assert(fd >= 0);
-
-        if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
-                return -errno;
-
-        if (cloexec)
-                flags |= FD_CLOEXEC;
-        else
-                flags &= ~FD_CLOEXEC;
-
-        if (fcntl(fd, F_SETFD, flags) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int close_all_fds(const int except[], unsigned n_except) {
-        DIR *d;
-        struct dirent *de;
-        int r = 0;
-
-        if (!(d = opendir("/proc/self/fd")))
-                return -errno;
-
-        while ((de = readdir(d))) {
-                int fd = -1;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                if ((r = safe_atoi(de->d_name, &fd)) < 0)
-                        goto finish;
-
-                if (fd < 3)
-                        continue;
-
-                if (fd == dirfd(d))
-                        continue;
-
-                if (except) {
-                        bool found;
-                        unsigned i;
-
-                        found = false;
-                        for (i = 0; i < n_except; i++)
-                                if (except[i] == fd) {
-                                        found = true;
-                                        break;
-                                }
-
-                        if (found)
-                                continue;
-                }
-
-                if ((r = close_nointr(fd)) < 0) {
-                        /* Valgrind has its own FD and doesn't want to have it closed */
-                        if (errno != EBADF)
-                                goto finish;
-                }
-        }
-
-        r = 0;
-
-finish:
-        closedir(d);
-        return r;
-}
-
-bool chars_intersect(const char *a, const char *b) {
-        const char *p;
-
-        /* Returns true if any of the chars in a are in b. */
-        for (p = a; *p; p++)
-                if (strchr(b, *p))
-                        return true;
-
-        return false;
-}
-
-char *format_timestamp(char *buf, size_t l, usec_t t) {
-        struct tm tm;
-        time_t sec;
-
-        assert(buf);
-        assert(l > 0);
-
-        if (t <= 0)
-                return NULL;
-
-        sec = (time_t) t / USEC_PER_SEC;
-
-        if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0)
-                return NULL;
-
-        return buf;
-}
-
-bool fstype_is_network(const char *fstype) {
-        static const char * const table[] = {
-                "cifs",
-                "smbfs",
-                "ncpfs",
-                "nfs",
-                "nfs4",
-                "gfs",
-                "gfs2"
-        };
-
-        unsigned i;
-
-        for (i = 0; i < ELEMENTSOF(table); i++)
-                if (streq(table[i], fstype))
-                        return true;
-
-        return false;
-}
-
-int chvt(int vt) {
-        int fd, r = 0;
-
-        if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
-                return -errno;
-
-        if (vt < 0) {
-                int tiocl[2] = {
-                        TIOCL_GETKMSGREDIRECT,
-                        0
-                };
-
-                if (ioctl(fd, TIOCLINUX, tiocl) < 0)
-                        return -errno;
-
-                vt = tiocl[0] <= 0 ? 1 : tiocl[0];
-        }
-
-        if (ioctl(fd, VT_ACTIVATE, vt) < 0)
-                r = -errno;
-
-        close_nointr_nofail(r);
-        return r;
-}
-
-int read_one_char(FILE *f, char *ret, bool *need_nl) {
-        struct termios old_termios, new_termios;
-        char c;
-        char line[1024];
-
-        assert(f);
-        assert(ret);
-
-        if (tcgetattr(fileno(f), &old_termios) >= 0) {
-                new_termios = old_termios;
-
-                new_termios.c_lflag &= ~ICANON;
-                new_termios.c_cc[VMIN] = 1;
-                new_termios.c_cc[VTIME] = 0;
-
-                if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
-                        size_t k;
-
-                        k = fread(&c, 1, 1, f);
-
-                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
-
-                        if (k <= 0)
-                                return -EIO;
-
-                        if (need_nl)
-                                *need_nl = c != '\n';
-
-                        *ret = c;
-                        return 0;
-                }
-        }
-
-        if (!(fgets(line, sizeof(line), f)))
-                return -EIO;
-
-        truncate_nl(line);
-
-        if (strlen(line) != 1)
-                return -EBADMSG;
-
-        if (need_nl)
-                *need_nl = false;
-
-        *ret = line[0];
-        return 0;
-}
-
-int ask(char *ret, const char *replies, const char *text, ...) {
-        assert(ret);
-        assert(replies);
-        assert(text);
-
-        for (;;) {
-                va_list ap;
-                char c;
-                int r;
-                bool need_nl = true;
-
-                fputs("\x1B[1m", stdout);
-
-                va_start(ap, text);
-                vprintf(text, ap);
-                va_end(ap);
-
-                fputs("\x1B[0m", stdout);
-
-                fflush(stdout);
-
-                if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
-
-                        if (r == -EBADMSG) {
-                                puts("Bad input, please try again.");
-                                continue;
-                        }
-
-                        putchar('\n');
-                        return r;
-                }
-
-                if (need_nl)
-                        putchar('\n');
-
-                if (strchr(replies, c)) {
-                        *ret = c;
-                        return 0;
-                }
-
-                puts("Read unexpected character, please try again.");
-        }
-}
-
-int reset_terminal(int fd) {
-        struct termios termios;
-        int r = 0;
-
-        assert(fd >= 0);
-
-        /* Set terminal to some sane defaults */
-
-        if (tcgetattr(fd, &termios) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        /* We only reset the stuff that matters to the software. How
-         * hardware is set up we don't touch assuming that somebody
-         * else will do that for us */
-
-        termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
-        termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
-        termios.c_oflag |= ONLCR;
-        termios.c_cflag |= CREAD;
-        termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
-
-        termios.c_cc[VINTR]    =   03;  /* ^C */
-        termios.c_cc[VQUIT]    =  034;  /* ^\ */
-        termios.c_cc[VERASE]   = 0177;
-        termios.c_cc[VKILL]    =  025;  /* ^X */
-        termios.c_cc[VEOF]     =   04;  /* ^D */
-        termios.c_cc[VSTART]   =  021;  /* ^Q */
-        termios.c_cc[VSTOP]    =  023;  /* ^S */
-        termios.c_cc[VSUSP]    =  032;  /* ^Z */
-        termios.c_cc[VLNEXT]   =  026;  /* ^V */
-        termios.c_cc[VWERASE]  =  027;  /* ^W */
-        termios.c_cc[VREPRINT] =  022;  /* ^R */
-        termios.c_cc[VEOL]     =    0;
-        termios.c_cc[VEOL2]    =    0;
-
-        termios.c_cc[VTIME]  = 0;
-        termios.c_cc[VMIN]   = 1;
-
-        if (tcsetattr(fd, TCSANOW, &termios) < 0)
-                r = -errno;
-
-finish:
-        /* Just in case, flush all crap out */
-        tcflush(fd, TCIOFLUSH);
-
-        return r;
-}
-
-int open_terminal(const char *name, int mode) {
-        int fd, r;
-
-        if ((fd = open(name, mode)) < 0)
-                return -errno;
-
-        if ((r = isatty(fd)) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        if (!r) {
-                close_nointr_nofail(fd);
-                return -ENOTTY;
-        }
-
-        return fd;
-}
-
-int flush_fd(int fd) {
-        struct pollfd pollfd;
-
-        zero(pollfd);
-        pollfd.fd = fd;
-        pollfd.events = POLLIN;
-
-        for (;;) {
-                char buf[1024];
-                ssize_t l;
-                int r;
-
-                if ((r = poll(&pollfd, 1, 0)) < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-                }
-
-                if (r == 0)
-                        return 0;
-
-                if ((l = read(fd, buf, sizeof(buf))) < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN)
-                                return 0;
-
-                        return -errno;
-                }
-
-                if (l <= 0)
-                        return 0;
-        }
-}
-
-int acquire_terminal(const char *name, bool fail, bool force) {
-        int fd = -1, notify = -1, r, wd = -1;
-
-        assert(name);
-
-        /* We use inotify to be notified when the tty is closed. We
-         * create the watch before checking if we can actually acquire
-         * it, so that we don't lose any event.
-         *
-         * Note: strictly speaking this actually watches for the
-         * device being closed, it does *not* really watch whether a
-         * tty loses its controlling process. However, unless some
-         * rogue process uses TIOCNOTTY on /dev/tty *after* closing
-         * its tty otherwise this will not become a problem. As long
-         * as the administrator makes sure not configure any service
-         * on the same tty as an untrusted user this should not be a
-         * problem. (Which he probably should not do anyway.) */
-
-        if (!fail && !force) {
-                if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-
-                if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-        }
-
-        for (;;) {
-                if (notify >= 0)
-                        if ((r = flush_fd(notify)) < 0)
-                                goto fail;
-
-                /* We pass here O_NOCTTY only so that we can check the return
-                 * value TIOCSCTTY and have a reliable way to figure out if we
-                 * successfully became the controlling process of the tty */
-                if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
-                        return -errno;
-
-                /* First, try to get the tty */
-                if ((r = ioctl(fd, TIOCSCTTY, force)) < 0 &&
-                    (force || fail || errno != EPERM)) {
-                        r = -errno;
-                        goto fail;
-                }
-
-                if (r >= 0)
-                        break;
-
-                assert(!fail);
-                assert(!force);
-                assert(notify >= 0);
-
-                for (;;) {
-                        struct inotify_event e;
-                        ssize_t l;
-
-                        if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
-
-                                if (l < 0) {
-
-                                        if (errno == EINTR)
-                                                continue;
-
-                                        r = -errno;
-                                } else
-                                        r = -EIO;
-
-                                goto fail;
-                        }
-
-                        if (e.wd != wd || !(e.mask & IN_CLOSE)) {
-                                r = -errno;
-                                goto fail;
-                        }
-
-                        break;
-                }
-
-                /* We close the tty fd here since if the old session
-                 * ended our handle will be dead. It's important that
-                 * we do this after sleeping, so that we don't enter
-                 * an endless loop. */
-                close_nointr_nofail(fd);
-        }
-
-        if (notify >= 0)
-                close_nointr_nofail(notify);
-
-        if ((r = reset_terminal(fd)) < 0)
-                log_warning("Failed to reset terminal: %s", strerror(-r));
-
-        return fd;
-
-fail:
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        if (notify >= 0)
-                close_nointr_nofail(notify);
-
-        return r;
-}
-
-int release_terminal(void) {
-        int r = 0, fd;
-        struct sigaction sa_old, sa_new;
-
-        if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
-                return -errno;
-
-        /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
-         * by our own TIOCNOTTY */
-
-        zero(sa_new);
-        sa_new.sa_handler = SIG_IGN;
-        sa_new.sa_flags = SA_RESTART;
-        assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
-        if (ioctl(fd, TIOCNOTTY) < 0)
-                r = -errno;
-
-        assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
-        close_nointr_nofail(fd);
-        return r;
-}
-
-int ignore_signal(int sig) {
-        struct sigaction sa;
-
-        zero(sa);
-        sa.sa_handler = SIG_IGN;
-        sa.sa_flags = SA_RESTART;
-
-        return sigaction(sig, &sa, NULL);
-}
-
-int close_pipe(int p[]) {
-        int a = 0, b = 0;
-
-        assert(p);
-
-        if (p[0] >= 0) {
-                a = close_nointr(p[0]);
-                p[0] = -1;
-        }
-
-        if (p[1] >= 0) {
-                b = close_nointr(p[1]);
-                p[1] = -1;
-        }
-
-        return a < 0 ? a : b;
-}
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes) {
-        uint8_t *p;
-        ssize_t n = 0;
-
-        assert(fd >= 0);
-        assert(buf);
-
-        p = buf;
-
-        while (nbytes > 0) {
-                ssize_t k;
-
-                if ((k = read(fd, p, nbytes)) <= 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN) {
-                                struct pollfd pollfd;
-
-                                zero(pollfd);
-                                pollfd.fd = fd;
-                                pollfd.events = POLLIN;
-
-                                if (poll(&pollfd, 1, -1) < 0) {
-                                        if (errno == EINTR)
-                                                continue;
-
-                                        return n > 0 ? n : -errno;
-                                }
-
-                                if (pollfd.revents != POLLIN)
-                                        return n > 0 ? n : -EIO;
-
-                                continue;
-                        }
-
-                        return n > 0 ? n : (k < 0 ? -errno : 0);
-                }
-
-                p += k;
-                nbytes -= k;
-                n += k;
-        }
-
-        return n;
-}
-
-int path_is_mount_point(const char *t) {
-        struct stat a, b;
-        char *copy;
-
-        if (lstat(t, &a) < 0) {
-
-                if (errno == ENOENT)
-                        return 0;
-
-                return -errno;
-        }
-
-        if (!(copy = strdup(t)))
-                return -ENOMEM;
-
-        if (lstat(dirname(copy), &b) < 0) {
-                free(copy);
-                return -errno;
-        }
-
-        free(copy);
-
-        return a.st_dev != b.st_dev;
-}
-
-int parse_usec(const char *t, usec_t *usec) {
-        static const struct {
-                const char *suffix;
-                usec_t usec;
-        } table[] = {
-                { "sec", USEC_PER_SEC },
-                { "s", USEC_PER_SEC },
-                { "min", USEC_PER_MINUTE },
-                { "hr", USEC_PER_HOUR },
-                { "h", USEC_PER_HOUR },
-                { "d", USEC_PER_DAY },
-                { "w", USEC_PER_WEEK },
-                { "msec", USEC_PER_MSEC },
-                { "ms", USEC_PER_MSEC },
-                { "m", USEC_PER_MINUTE },
-                { "usec", 1ULL },
-                { "us", 1ULL },
-                { "", USEC_PER_SEC },
-        };
-
-        const char *p;
-        usec_t r = 0;
-
-        assert(t);
-        assert(usec);
-
-        p = t;
-        do {
-                long long l;
-                char *e;
-                unsigned i;
-
-                errno = 0;
-                l = strtoll(p, &e, 10);
-
-                if (errno != 0)
-                        return -errno;
-
-                if (l < 0)
-                        return -ERANGE;
-
-                if (e == p)
-                        return -EINVAL;
-
-                e += strspn(e, WHITESPACE);
-
-                for (i = 0; i < ELEMENTSOF(table); i++)
-                        if (startswith(e, table[i].suffix)) {
-                                r += (usec_t) l * table[i].usec;
-                                p = e + strlen(table[i].suffix);
-                                break;
-                        }
-
-                if (i >= ELEMENTSOF(table))
-                        return -EINVAL;
-
-        } while (*p != 0);
-
-        *usec = r;
-
-        return 0;
-}
-
-int make_stdio(int fd) {
-        int r, s, t;
-
-        assert(fd >= 0);
-
-        r = dup2(fd, STDIN_FILENO);
-        s = dup2(fd, STDOUT_FILENO);
-        t = dup2(fd, STDERR_FILENO);
-
-        if (fd >= 3)
-                close_nointr_nofail(fd);
-
-        if (r < 0 || s < 0 || t < 0)
-                return -errno;
-
-        return 0;
-}
-
-bool is_clean_exit(int code, int status) {
-
-        if (code == CLD_EXITED)
-                return status == 0;
-
-        /* If a daemon does not implement handlers for some of the
-         * signals that's not considered an unclean shutdown */
-        if (code == CLD_KILLED)
-                return
-                        status == SIGHUP ||
-                        status == SIGINT ||
-                        status == SIGTERM ||
-                        status == SIGPIPE;
-
-        return false;
-}
-
-bool is_device_path(const char *path) {
-
-        /* Returns true on paths that refer to a device, either in
-         * sysfs or in /dev */
-
-        return
-                path_startswith(path, "/dev/") ||
-                path_startswith(path, "/sys/");
-}
-
-static const char *const ioprio_class_table[] = {
-        [IOPRIO_CLASS_NONE] = "none",
-        [IOPRIO_CLASS_RT] = "realtime",
-        [IOPRIO_CLASS_BE] = "best-effort",
-        [IOPRIO_CLASS_IDLE] = "idle"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
-
-static const char *const sigchld_code_table[] = {
-        [CLD_EXITED] = "exited",
-        [CLD_KILLED] = "killed",
-        [CLD_DUMPED] = "dumped",
-        [CLD_TRAPPED] = "trapped",
-        [CLD_STOPPED] = "stopped",
-        [CLD_CONTINUED] = "continued",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
-
-static const char *const log_facility_table[LOG_NFACILITIES] = {
-        [LOG_FAC(LOG_KERN)] = "kern",
-        [LOG_FAC(LOG_USER)] = "user",
-        [LOG_FAC(LOG_MAIL)] = "mail",
-        [LOG_FAC(LOG_DAEMON)] = "daemon",
-        [LOG_FAC(LOG_AUTH)] = "auth",
-        [LOG_FAC(LOG_SYSLOG)] = "syslog",
-        [LOG_FAC(LOG_LPR)] = "lpr",
-        [LOG_FAC(LOG_NEWS)] = "news",
-        [LOG_FAC(LOG_UUCP)] = "uucp",
-        [LOG_FAC(LOG_CRON)] = "cron",
-        [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
-        [LOG_FAC(LOG_FTP)] = "ftp",
-        [LOG_FAC(LOG_LOCAL0)] = "local0",
-        [LOG_FAC(LOG_LOCAL1)] = "local1",
-        [LOG_FAC(LOG_LOCAL2)] = "local2",
-        [LOG_FAC(LOG_LOCAL3)] = "local3",
-        [LOG_FAC(LOG_LOCAL4)] = "local4",
-        [LOG_FAC(LOG_LOCAL5)] = "local5",
-        [LOG_FAC(LOG_LOCAL6)] = "local6",
-        [LOG_FAC(LOG_LOCAL7)] = "local7"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
-
-static const char *const log_level_table[] = {
-        [LOG_EMERG] = "emerg",
-        [LOG_ALERT] = "alert",
-        [LOG_CRIT] = "crit",
-        [LOG_ERR] = "err",
-        [LOG_WARNING] = "warning",
-        [LOG_NOTICE] = "notice",
-        [LOG_INFO] = "info",
-        [LOG_DEBUG] = "debug"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(log_level, int);
-
-static const char* const sched_policy_table[] = {
-        [SCHED_OTHER] = "other",
-        [SCHED_BATCH] = "batch",
-        [SCHED_IDLE] = "idle",
-        [SCHED_FIFO] = "fifo",
-        [SCHED_RR] = "rr"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
-
-static const char* const rlimit_table[] = {
-        [RLIMIT_CPU] = "LimitCPU",
-        [RLIMIT_FSIZE] = "LimitFSIZE",
-        [RLIMIT_DATA] = "LimitDATA",
-        [RLIMIT_STACK] = "LimitSTACK",
-        [RLIMIT_CORE] = "LimitCORE",
-        [RLIMIT_RSS] = "LimitRSS",
-        [RLIMIT_NOFILE] = "LimitNOFILE",
-        [RLIMIT_AS] = "LimitAS",
-        [RLIMIT_NPROC] = "LimitNPROC",
-        [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
-        [RLIMIT_LOCKS] = "LimitLOCKS",
-        [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
-        [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
-        [RLIMIT_NICE] = "LimitNICE",
-        [RLIMIT_RTPRIO] = "LimitRTPRIO",
-        [RLIMIT_RTTIME] = "LimitRTTIME"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
diff --git a/util.h b/util.h
deleted file mode 100644
index a77a952..0000000
--- a/util.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooutilhfoo
-#define fooutilhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <inttypes.h>
-#include <time.h>
-#include <sys/time.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-typedef uint64_t usec_t;
-
-#define MSEC_PER_SEC  1000ULL
-#define USEC_PER_SEC  1000000ULL
-#define USEC_PER_MSEC 1000ULL
-#define NSEC_PER_SEC  1000000000ULL
-#define NSEC_PER_MSEC 1000000ULL
-#define NSEC_PER_USEC 1000ULL
-
-#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC)
-#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE)
-#define USEC_PER_DAY (24ULL*USEC_PER_HOUR)
-#define USEC_PER_WEEK (7ULL*USEC_PER_DAY)
-
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n\r"
-#define NEWLINE "\n\r"
-
-#define FORMAT_TIMESTAMP_MAX 64
-
-usec_t now(clockid_t clock);
-
-usec_t timespec_load(const struct timespec *ts);
-struct timespec *timespec_store(struct timespec *ts, usec_t u);
-
-usec_t timeval_load(const struct timeval *tv);
-struct timeval *timeval_store(struct timeval *tv, usec_t u);
-
-#define streq(a,b) (strcmp((a),(b)) == 0)
-
-bool streq_ptr(const char *a, const char *b);
-
-#define new(t, n) ((t*) malloc(sizeof(t)*(n)))
-
-#define new0(t, n) ((t*) calloc((n), sizeof(t)))
-
-#define malloc0(n) (calloc((n), 1))
-
-static inline const char* yes_no(bool b) {
-        return b ? "yes" : "no";
-}
-
-static inline const char* strempty(const char *s) {
-        return s ? s : "";
-}
-
-static inline const char* strnull(const char *s) {
-        return s ? s : "(null)";
-}
-
-static inline const char *strna(const char *s) {
-        return s ? s : "n/a";
-}
-
-static inline bool is_path_absolute(const char *p) {
-        return *p == '/';
-}
-
-bool endswith(const char *s, const char *postfix);
-bool startswith(const char *s, const char *prefix);
-bool startswith_no_case(const char *s, const char *prefix);
-
-bool first_word(const char *s, const char *word);
-
-int close_nointr(int fd);
-void close_nointr_nofail(int fd);
-
-int parse_boolean(const char *v);
-int parse_usec(const char *t, usec_t *usec);
-
-int safe_atou(const char *s, unsigned *ret_u);
-int safe_atoi(const char *s, int *ret_i);
-
-int safe_atolu(const char *s, unsigned long *ret_u);
-int safe_atoli(const char *s, long int *ret_i);
-
-int safe_atollu(const char *s, unsigned long long *ret_u);
-int safe_atolli(const char *s, long long int *ret_i);
-
-char *split(const char *c, size_t *l, const char *separator, char **state);
-char *split_quoted(const char *c, size_t *l, char **state);
-
-#define FOREACH_WORD(word, length, s, state)                            \
-        for ((state) = NULL, (word) = split((s), &(length), WHITESPACE, &(state)); (word); (word) = split((s), &(length), WHITESPACE, &(state)))
-
-#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
-        for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state)))
-
-#define FOREACH_WORD_QUOTED(word, length, s, state)                     \
-        for ((state) = NULL, (word) = split_quoted((s), &(length), &(state)); (word); (word) = split_quoted((s), &(length), &(state)))
-
-char **split_path_and_make_absolute(const char *p);
-
-pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
-
-int write_one_line_file(const char *fn, const char *line);
-int read_one_line_file(const char *fn, char **line);
-
-char *strappend(const char *s, const char *suffix);
-
-int readlink_malloc(const char *p, char **r);
-
-char *file_name_from_path(const char *p);
-bool is_path(const char *p);
-
-bool path_is_absolute(const char *p);
-char *path_make_absolute(const char *p, const char *prefix);
-char *path_make_absolute_cwd(const char *p);
-char **strv_path_make_absolute_cwd(char **l);
-
-int reset_all_signal_handlers(void);
-
-char *strstrip(char *s);
-char *delete_chars(char *s, const char *bad);
-char *truncate_nl(char *s);
-
-char *file_in_same_dir(const char *path, const char *filename);
-int mkdir_parents(const char *path, mode_t mode);
-int mkdir_p(const char *path, mode_t mode);
-
-int get_process_name(pid_t pid, char **name);
-
-char hexchar(int x);
-int unhexchar(char c);
-char octchar(int x);
-int unoctchar(char c);
-char decchar(int x);
-int undecchar(char c);
-
-char *cescape(const char *s);
-char *cunescape(const char *s);
-
-char *path_kill_slashes(char *path);
-
-bool path_startswith(const char *path, const char *prefix);
-bool path_equal(const char *a, const char *b);
-
-char *ascii_strlower(char *path);
-
-char *xescape(const char *s, const char *bad);
-
-char *bus_path_escape(const char *s);
-char *bus_path_unescape(const char *s);
-
-bool ignore_file(const char *filename);
-
-bool chars_intersect(const char *a, const char *b);
-
-char *format_timestamp(char *buf, size_t l, usec_t t);
-
-int make_stdio(int fd);
-
-bool is_clean_exit(int code, int status);
-
-#define DEFINE_STRING_TABLE_LOOKUP(name,type)                           \
-        const char *name##_to_string(type i) {                          \
-                if (i < 0 || i >= (type) ELEMENTSOF(name##_table))      \
-                        return NULL;                                    \
-                return name##_table[i];                                 \
-        }                                                               \
-        type name##_from_string(const char *s) {                        \
-                type i;                                                 \
-                unsigned u = 0;                                         \
-                assert(s);                                              \
-                for (i = 0; i < (type)ELEMENTSOF(name##_table); i++)    \
-                        if (streq(name##_table[i], s))                  \
-                                return i;                               \
-                if (safe_atou(s, &u) >= 0 &&                            \
-                    u < ELEMENTSOF(name##_table))                       \
-                        return (type) u;                                \
-                return (type) -1;                                       \
-        }                                                               \
-        struct __useless_struct_to_allow_trailing_semicolon__
-
-
-int fd_nonblock(int fd, bool nonblock);
-int fd_cloexec(int fd, bool cloexec);
-
-int close_all_fds(const int except[], unsigned n_except);
-
-bool fstype_is_network(const char *fstype);
-
-int chvt(int vt);
-
-int read_one_char(FILE *f, char *ret, bool *need_nl);
-int ask(char *ret, const char *replies, const char *text, ...);
-
-int reset_terminal(int fd);
-int open_terminal(const char *name, int mode);
-int acquire_terminal(const char *name, bool fail, bool force);
-int release_terminal(void);
-
-int flush_fd(int fd);
-
-int ignore_signal(int sig);
-
-int close_pipe(int p[]);
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes);
-
-int path_is_mount_point(const char *path);
-
-bool is_device_path(const char *path);
-
-extern char * __progname;
-
-const char *ioprio_class_to_string(int i);
-int ioprio_class_from_string(const char *s);
-
-const char *sigchld_code_to_string(int i);
-int sigchld_code_from_string(const char *s);
-
-const char *log_facility_to_string(int i);
-int log_facility_from_string(const char *s);
-
-const char *log_level_to_string(int i);
-int log_level_from_string(const char *s);
-
-const char *sched_policy_to_string(int i);
-int sched_policy_from_string(const char *s);
-
-const char *rlimit_to_string(int i);
-int rlimit_from_string(const char *s);
-
-#endif
diff --git a/utmp-wtmp.c b/utmp-wtmp.c
deleted file mode 100644
index cb3f201..0000000
--- a/utmp-wtmp.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <utmpx.h>
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <sys/utsname.h>
-
-#include "macro.h"
-#include "utmp-wtmp.h"
-
-int utmp_get_runlevel(int *runlevel, int *previous) {
-        struct utmpx lookup, *found;
-        int r;
-        const char *e;
-
-        assert(runlevel);
-
-        /* If these values are set in the environment this takes
-         * precedence. Presumably, sysvinit does this to work around a
-         * race condition that would otherwise exist where we'd always
-         * go to disk and hence might read runlevel data that might be
-         * very new and does not apply to the current script being
-         * executed. */
-
-        if ((e = getenv("RUNLEVEL")) && e[0] > 0) {
-                *runlevel = e[0];
-
-                if (previous) {
-                        /* $PREVLEVEL seems to be an Upstart thing */
-
-                        if ((e = getenv("PREVLEVEL")) && e[0] > 0)
-                                *previous = e[0];
-                        else
-                                *previous = 0;
-                }
-
-                return 0;
-        }
-
-        if (utmpxname(_PATH_UTMPX) < 0)
-                return -errno;
-
-        setutxent();
-
-        zero(lookup);
-        lookup.ut_type = RUN_LVL;
-
-        if (!(found = getutxid(&lookup)))
-                r = -errno;
-        else {
-                int a, b;
-
-                a = found->ut_pid & 0xFF;
-                b = (found->ut_pid >> 8) & 0xFF;
-
-                if (a < 0 || b < 0)
-                        r = -EIO;
-                else {
-                        *runlevel = a;
-
-                        if (previous)
-                                *previous = b;
-                        r = 0;
-                }
-        }
-
-        endutxent();
-
-        return r;
-}
-
-static void init_entry(struct utmpx *store, usec_t timestamp) {
-        struct utsname uts;
-
-        assert(store);
-
-        zero(*store);
-        zero(uts);
-
-        if (timestamp <= 0)
-                timestamp = now(CLOCK_REALTIME);
-
-        store->ut_tv.tv_sec = timestamp / USEC_PER_SEC;
-        store->ut_tv.tv_usec = timestamp % USEC_PER_SEC;
-
-        if (uname(&uts) >= 0)
-                strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
-
-        strncpy(store->ut_line, "~", sizeof(store->ut_line));  /* or ~~ ? */
-        strncpy(store->ut_id, "~~", sizeof(store->ut_id));
-}
-
-static int write_entry_utmp(const struct utmpx *store) {
-        int r;
-
-        assert(store);
-
-        /* utmp is similar to wtmp, but there is only one entry for
-         * each entry type resp. user; i.e. basically a key/value
-         * table. */
-
-        if (utmpxname(_PATH_UTMPX) < 0)
-                return -errno;
-
-        setutxent();
-
-        if (!pututxline(store))
-                r = -errno;
-        else
-                r = 0;
-
-        endutxent();
-
-        return r;
-}
-
-static int write_entry_wtmp(const struct utmpx *store) {
-        assert(store);
-
-        /* wtmp is a simple append-only file where each entry is
-        simply appended to * the end; i.e. basically a log. */
-
-        errno = 0;
-        updwtmpx(_PATH_WTMPX, store);
-        return -errno;
-}
-
-static int write_entry_both(const struct utmpx *store) {
-        int r, s;
-
-        r = write_entry_utmp(store);
-        s = write_entry_wtmp(store);
-
-        if (r >= 0)
-                r = s;
-
-        /* If utmp/wtmp have been disabled, that's a good thing, hence
-         * ignore the errors */
-        if (r == -ENOENT)
-                r = 0;
-
-        return r;
-}
-
-int utmp_put_shutdown(usec_t timestamp) {
-        struct utmpx store;
-
-        init_entry(&store, timestamp);
-
-        store.ut_type = RUN_LVL;
-        strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
-
-int utmp_put_reboot(usec_t timestamp) {
-        struct utmpx store;
-
-        init_entry(&store, timestamp);
-
-        store.ut_type = BOOT_TIME;
-        strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
-
-int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous) {
-        struct utmpx store;
-        int r;
-
-        assert(runlevel > 0);
-
-        if (previous <= 0) {
-                /* Find the old runlevel automatically */
-
-                if ((r = utmp_get_runlevel(&previous, NULL)) < 0) {
-                        if (r != -ESRCH)
-                                return r;
-
-                        previous = 0;
-                }
-
-                if (previous == runlevel)
-                        return 0;
-        }
-
-        init_entry(&store, timestamp);
-
-        store.ut_type = RUN_LVL;
-        store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
-        strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
diff --git a/utmp-wtmp.h b/utmp-wtmp.h
deleted file mode 100644
index 34c3222..0000000
--- a/utmp-wtmp.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooutmpwtmphfoo
-#define fooutmpwtmphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 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
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-
-int utmp_get_runlevel(int *runlevel, int *previous);
-
-int utmp_put_shutdown(usec_t timestamp);
-int utmp_put_reboot(usec_t timestamp);
-int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous);
-
-#endif
commit e9da3678fcfc774b325dc1eaa054d0e00028a1fc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun May 16 18:34:31 2010 +0200

    build-sys: use autoconf'igured mkdir/ln/sed programs

diff --git a/Makefile.am b/Makefile.am
index b8ccc82..c676712 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -251,12 +251,12 @@ systemadm_CPPFLAGS = $(AM_CPPFLAGS) $(DBUSGLIB_CFLAGS) $(GTK_CFLAGS) $(VALA_CFLA
 systemadm_LDADD = $(DBUSGLIB_LIBS) $(GTK_LIBS)
 
 systemd-initctl.service: units/systemd-initctl.service.in Makefile
-	sed -e 's, at libexecdir\@,$(libexecdir),g' \
+	$(SED) -e 's, at libexecdir\@,$(libexecdir),g' \
 		-e 's, at pkglibexecdir\@,$(pkglibexecdir),g' \
 		< $< > $@
 
 systemd-logger.service: units/systemd-logger.service.in Makefile
-	sed -e 's, at libexecdir\@,$(libexecdir),g' \
+	$(SED) -e 's, at libexecdir\@,$(libexecdir),g' \
 		-e 's, at pkglibexecdir\@,$(pkglibexecdir),g' \
 		< $< > $@
 
@@ -287,8 +287,9 @@ install-data-hook:
 		$(DESTDIR)$(pkgsysconfdir)/session \
 		$(DESTDIR)$(sysconfdir)/xdg/systemd \
 		$(DESTDIR)/cgroup/debug
-	rm -f $(DESTDIR)$(sysconfdir)/xdg/systemd/session
-	ln -sf $(DESTDIR)$(pkgsysconfdir)/session $(DESTDIR)$(sysconfdir)/xdg/systemd/session
+	( cd $(DESTDIR)$(sysconfdir)/xdg/systemd/ && \
+		rm -f session && \
+		$(LN_S) $(DESTDIR)$(pkgsysconfdir)/session session )
 
 DISTCHECK_CONFIGURE_FLAGS = \
 	--with-udevrulesdir=$$dc_install_base/$(udevrulesdir)
diff --git a/configure.ac b/configure.ac
index ea77db3..1d2efc3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,6 +37,10 @@ AS_IF([test "x$STOW" = "xyes" && test -d /usr/local/stow], [
         ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
 ])
 
+AC_PROG_MKDIR_P
+AC_PROG_LN_S
+AC_PROG_SED
+
 AC_PROG_CC
 AC_PROG_CC_C99
 AM_PROG_CC_C_O


More information about the systemd-commits mailing list