[systemd-commits] Makefile.am po/POTFILES.skip src/ask-password-api.h src/automount.c src/automount.h src/build.h src/bus-errors.h src/cgroup-attr.c src/cgroup-attr.h src/cgroup.c src/cgroup.h src/condition.c src/condition.h src/core 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-loop.h src/dbus-manager.c src/dbus-manager.h src/dbus-mount.c src/dbus-mount.h src/dbus-path.c src/dbus-path.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-timer.c src/dbus-timer.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/ima-setup.c src/ima-setup.h src/initreq.h src/job.c src/job.h src/kmod-setup.c src/kmod-setup.h src/load-dropin.c src/load-dropin.h src/load-fragme nt.c src/load-fragment.h src/locale-setup.c src/locale-setup.h src/manager.c src/manager.h src/mount.c src/mount.h src/namespace.c src/namespace.h src/path.c src/path.h src/polkit.h src/securebits.h src/selinux-setup.c src/selinux-setup.h src/service.c src/service.h src/snapshot.c src/snapshot.h src/socket.c src/socket.h src/spawn-agent.h src/special.h src/swap.c src/swap.h src/sysfs-show.h src/target.c src/target.h src/tcpwrap.c src/tcpwrap.h src/timer.c src/timer.h src/unit.c src/unit.h

Kay Sievers kay at kemper.freedesktop.org
Wed Apr 11 07:10:43 PDT 2012


 Makefile.am                 |  239 +-
 po/POTFILES.skip            |   26 
 src/ask-password-api.h      |   33 
 src/automount.c             |  888 ----------
 src/automount.h             |   76 
 src/build.h                 |   69 
 src/bus-errors.h            |   58 
 src/cgroup-attr.c           |  102 -
 src/cgroup-attr.h           |   49 
 src/cgroup.c                |  556 ------
 src/cgroup.h                |   94 -
 src/condition.c             |  323 ---
 src/condition.h             |   69 
 src/core/ask-password-api.h |   33 
 src/core/automount.c        |  888 ++++++++++
 src/core/automount.h        |   76 
 src/core/build.h            |   69 
 src/core/bus-errors.h       |   58 
 src/core/cgroup-attr.c      |  102 +
 src/core/cgroup-attr.h      |   49 
 src/core/cgroup.c           |  556 ++++++
 src/core/cgroup.h           |   94 +
 src/core/condition.c        |  323 +++
 src/core/condition.h        |   69 
 src/core/dbus-automount.c   |   72 
 src/core/dbus-automount.h   |   34 
 src/core/dbus-device.c      |   65 
 src/core/dbus-device.h      |   34 
 src/core/dbus-execute.c     |  422 ++++
 src/core/dbus-execute.h     |  125 +
 src/core/dbus-job.c         |  354 ++++
 src/core/dbus-job.h         |   36 
 src/core/dbus-loop.h        |   30 
 src/core/dbus-manager.c     | 1544 +++++++++++++++++
 src/core/dbus-manager.h     |   31 
 src/core/dbus-mount.c       |  168 +
 src/core/dbus-mount.h       |   34 
 src/core/dbus-path.c        |  119 +
 src/core/dbus-path.h        |   35 
 src/core/dbus-service.c     |  169 +
 src/core/dbus-service.h     |   34 
 src/core/dbus-snapshot.c    |   93 +
 src/core/dbus-snapshot.h    |   33 
 src/core/dbus-socket.c      |  139 +
 src/core/dbus-socket.h      |   34 
 src/core/dbus-swap.c        |  111 +
 src/core/dbus-swap.h        |   35 
 src/core/dbus-target.c      |   55 
 src/core/dbus-target.h      |   33 
 src/core/dbus-timer.c       |  137 +
 src/core/dbus-timer.h       |   34 
 src/core/dbus-unit.c        |  850 +++++++++
 src/core/dbus-unit.h        |  139 +
 src/core/dbus.c             | 1483 +++++++++++++++++
 src/core/dbus.h             |   53 
 src/core/device.c           |  616 +++++++
 src/core/device.h           |   59 
 src/core/execute.c          | 2113 ++++++++++++++++++++++++
 src/core/execute.h          |  233 ++
 src/core/fdset.c            |  167 +
 src/core/fdset.h            |   40 
 src/core/ima-setup.c        |  115 +
 src/core/ima-setup.h        |   29 
 src/core/initreq.h          |   77 
 src/core/job.c              |  701 ++++++++
 src/core/job.h              |  200 ++
 src/core/kmod-setup.c       |   96 +
 src/core/kmod-setup.h       |   27 
 src/core/load-dropin.c      |  150 +
 src/core/load-dropin.h      |   31 
 src/core/load-fragment.c    | 2445 ++++++++++++++++++++++++++++
 src/core/load-fragment.h    |   91 +
 src/core/locale-setup.c     |  251 ++
 src/core/locale-setup.h     |   27 
 src/core/manager.c          | 3235 +++++++++++++++++++++++++++++++++++++
 src/core/manager.h          |  304 +++
 src/core/mount.c            | 1930 ++++++++++++++++++++++
 src/core/mount.h            |  124 +
 src/core/namespace.c        |  346 ++++
 src/core/namespace.h        |   34 
 src/core/path.c             |  771 ++++++++
 src/core/path.h             |  113 +
 src/core/polkit.h           |   36 
 src/core/securebits.h       |   45 
 src/core/selinux-setup.c    |  112 +
 src/core/selinux-setup.h    |   29 
 src/core/service.c          | 3797 ++++++++++++++++++++++++++++++++++++++++++++
 src/core/service.h          |  220 ++
 src/core/snapshot.c         |  309 +++
 src/core/snapshot.h         |   53 
 src/core/socket.c           | 2218 +++++++++++++++++++++++++
 src/core/socket.h           |  173 ++
 src/core/spawn-agent.h      |   28 
 src/core/special.h          |   88 +
 src/core/swap.c             | 1415 ++++++++++++++++
 src/core/swap.h             |  128 +
 src/core/sysfs-show.h       |   27 
 src/core/target.c           |  224 ++
 src/core/target.h           |   47 
 src/core/tcpwrap.c          |   68 
 src/core/tcpwrap.h          |   29 
 src/core/timer.c            |  520 ++++++
 src/core/timer.h            |   93 +
 src/core/unit.c             | 2676 +++++++++++++++++++++++++++++++
 src/core/unit.h             |  562 ++++++
 src/dbus-automount.c        |   72 
 src/dbus-automount.h        |   34 
 src/dbus-device.c           |   65 
 src/dbus-device.h           |   34 
 src/dbus-execute.c          |  422 ----
 src/dbus-execute.h          |  125 -
 src/dbus-job.c              |  354 ----
 src/dbus-job.h              |   36 
 src/dbus-loop.h             |   30 
 src/dbus-manager.c          | 1544 -----------------
 src/dbus-manager.h          |   31 
 src/dbus-mount.c            |  168 -
 src/dbus-mount.h            |   34 
 src/dbus-path.c             |  119 -
 src/dbus-path.h             |   35 
 src/dbus-service.c          |  169 -
 src/dbus-service.h          |   34 
 src/dbus-snapshot.c         |   93 -
 src/dbus-snapshot.h         |   33 
 src/dbus-socket.c           |  139 -
 src/dbus-socket.h           |   34 
 src/dbus-swap.c             |  111 -
 src/dbus-swap.h             |   35 
 src/dbus-target.c           |   55 
 src/dbus-target.h           |   33 
 src/dbus-timer.c            |  137 -
 src/dbus-timer.h            |   34 
 src/dbus-unit.c             |  850 ---------
 src/dbus-unit.h             |  139 -
 src/dbus.c                  | 1483 -----------------
 src/dbus.h                  |   53 
 src/device.c                |  616 -------
 src/device.h                |   59 
 src/execute.c               | 2113 ------------------------
 src/execute.h               |  233 --
 src/fdset.c                 |  167 -
 src/fdset.h                 |   40 
 src/ima-setup.c             |  115 -
 src/ima-setup.h             |   29 
 src/initreq.h               |   77 
 src/job.c                   |  701 --------
 src/job.h                   |  200 --
 src/kmod-setup.c            |   96 -
 src/kmod-setup.h            |   27 
 src/load-dropin.c           |  150 -
 src/load-dropin.h           |   31 
 src/load-fragment.c         | 2445 ----------------------------
 src/load-fragment.h         |   91 -
 src/locale-setup.c          |  251 --
 src/locale-setup.h          |   27 
 src/manager.c               | 3235 -------------------------------------
 src/manager.h               |  304 ---
 src/mount.c                 | 1930 ----------------------
 src/mount.h                 |  124 -
 src/namespace.c             |  346 ----
 src/namespace.h             |   34 
 src/path.c                  |  771 --------
 src/path.h                  |  113 -
 src/polkit.h                |   36 
 src/securebits.h            |   45 
 src/selinux-setup.c         |  112 -
 src/selinux-setup.h         |   29 
 src/service.c               | 3797 --------------------------------------------
 src/service.h               |  220 --
 src/snapshot.c              |  309 ---
 src/snapshot.h              |   53 
 src/socket.c                | 2218 -------------------------
 src/socket.h                |  173 --
 src/spawn-agent.h           |   28 
 src/special.h               |   88 -
 src/swap.c                  | 1415 ----------------
 src/swap.h                  |  128 -
 src/sysfs-show.h            |   27 
 src/target.c                |  224 --
 src/target.h                |   47 
 src/tcpwrap.c               |   68 
 src/tcpwrap.h               |   29 
 src/timer.c                 |  520 ------
 src/timer.h                 |   93 -
 src/unit.c                  | 2676 -------------------------------
 src/unit.h                  |  562 ------
 186 files changed, 36208 insertions(+), 36205 deletions(-)

New commits:
commit b30e2f4c18ad81b04e4314fd191a5d458553773c
Author: Kay Sievers <kay at vrfy.org>
Date:   Wed Apr 11 12:59:52 2012 +0200

    move libsystemd_core.la sources into core/

diff --git a/Makefile.am b/Makefile.am
index 07b30eb..4ed1f12 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,6 +126,7 @@ AM_CPPFLAGS = \
 	-I $(top_srcdir)/src/login \
 	-I $(top_srcdir)/src/journal \
 	-I $(top_srcdir)/src/systemd \
+	-I $(top_srcdir)/src/core \
 	-I $(top_srcdir)/src/udev
 
 AM_CFLAGS = $(WARNINGFLAGS)
@@ -647,128 +648,124 @@ noinst_LTLIBRARIES += \
 	libsystemd-core.la
 
 libsystemd_core_la_SOURCES = \
-	src/unit.c \
-	src/unit.h \
-	src/job.c \
-	src/job.h \
-	src/manager.c \
-	src/manager.h \
-	src/path-lookup.c \
-	src/path-lookup.h \
-	src/load-fragment.c \
-	src/load-fragment.h \
-	src/service.c \
-	src/service.h \
-	src/automount.c \
-	src/automount.h \
-	src/mount.c \
-	src/mount.h \
-	src/swap.c \
-	src/swap.h \
-	src/device.c \
-	src/device.h \
-	src/target.c \
-	src/target.h \
-	src/snapshot.c \
-	src/snapshot.h \
-	src/socket.c \
-	src/socket.h \
-	src/timer.c \
-	src/timer.h \
-	src/path.c \
-	src/path.h \
-	src/load-dropin.c \
-	src/load-dropin.h \
-	src/execute.c \
-	src/execute.h \
-	src/utmp-wtmp.c \
-	src/utmp-wtmp.h \
-	src/dbus.c \
-	src/dbus.h \
-	src/dbus-manager.c \
-	src/dbus-manager.h \
-	src/dbus-unit.c \
-	src/dbus-unit.h \
-	src/dbus-job.c \
-	src/dbus-job.h \
-	src/dbus-service.c \
-	src/dbus-service.h \
-	src/dbus-socket.c \
-	src/dbus-socket.h \
-	src/dbus-timer.c \
-	src/dbus-timer.h \
-	src/dbus-target.c \
-	src/dbus-target.h \
-	src/dbus-mount.c \
-	src/dbus-mount.h \
-	src/dbus-automount.c \
-	src/dbus-automount.h \
-	src/dbus-swap.c \
-	src/dbus-swap.h \
-	src/dbus-snapshot.c \
-	src/dbus-snapshot.h \
-	src/dbus-device.c \
-	src/dbus-device.h \
-	src/dbus-execute.c \
-	src/dbus-execute.h \
-	src/dbus-path.c \
-	src/dbus-path.h \
-	src/cgroup.c \
-	src/cgroup.h \
-	src/mount-setup.c \
-	src/mount-setup.h \
-	src/hostname-setup.c \
-	src/hostname-setup.h \
-	src/selinux-setup.c \
-	src/selinux-setup.h \
-	src/ima-setup.c \
-	src/ima-setup.h \
-	src/loopback-setup.h \
-	src/loopback-setup.c \
-	src/kmod-setup.c \
-	src/kmod-setup.h \
-	src/locale-setup.h \
-	src/locale-setup.c \
-	src/machine-id-setup.c \
-	src/machine-id-setup.h \
-	src/fdset.c \
-	src/fdset.h \
-	src/condition.c \
-	src/condition.h \
+	src/def.h \
+	src/missing.h \
 	src/dbus-common.c \
 	src/dbus-common.h \
-	src/install.c \
-	src/install.h \
+	src/watchdog.c \
+	src/watchdog.h \
+	src/loopback-setup.h \
+	src/loopback-setup.c \
+	src/hostname-setup.c \
+	src/hostname-setup.h \
 	src/specifier.c \
 	src/specifier.h \
-	src/namespace.c \
-	src/namespace.h \
+	src/install.c \
+	src/install.h \
+	src/path-lookup.c \
+	src/path-lookup.h \
 	src/unit-name.c \
 	src/unit-name.h \
-	src/tcpwrap.c \
-	src/tcpwrap.h \
-	src/cgroup-attr.c \
-	src/cgroup-attr.h \
-	src/watchdog.c \
-	src/watchdog.h \
-	src/def.h \
-	src/missing.h \
-	src/securebits.h \
+	src/utmp-wtmp.c \
+	src/utmp-wtmp.h \
+	src/machine-id-setup.c \
+	src/machine-id-setup.h \
+	src/mount-setup.c \
+	src/mount-setup.h \
 	src/linux/auto_dev-ioctl.h \
 	src/linux/fanotify.h \
-	src/initreq.h \
-	src/special.h \
-	src/dbus-common.h \
-	src/bus-errors.h \
-	src/cgroup-show.h \
-	src/build.h \
-	src/umount.h \
-	src/ask-password-api.h \
-	src/sysfs-show.h \
-	src/polkit.h \
-	src/dbus-loop.h \
-	src/spawn-agent.h \
-	src/logs-show.h
+	src/core/unit.c \
+	src/core/unit.h \
+	src/core/job.c \
+	src/core/job.h \
+	src/core/manager.c \
+	src/core/manager.h \
+	src/core/load-fragment.c \
+	src/core/load-fragment.h \
+	src/core/service.c \
+	src/core/service.h \
+	src/core/automount.c \
+	src/core/automount.h \
+	src/core/mount.c \
+	src/core/mount.h \
+	src/core/swap.c \
+	src/core/swap.h \
+	src/core/device.c \
+	src/core/device.h \
+	src/core/target.c \
+	src/core/target.h \
+	src/core/snapshot.c \
+	src/core/snapshot.h \
+	src/core/socket.c \
+	src/core/socket.h \
+	src/core/timer.c \
+	src/core/timer.h \
+	src/core/path.c \
+	src/core/path.h \
+	src/core/load-dropin.c \
+	src/core/load-dropin.h \
+	src/core/execute.c \
+	src/core/execute.h \
+	src/core/dbus.c \
+	src/core/dbus.h \
+	src/core/dbus-manager.c \
+	src/core/dbus-manager.h \
+	src/core/dbus-unit.c \
+	src/core/dbus-unit.h \
+	src/core/dbus-job.c \
+	src/core/dbus-job.h \
+	src/core/dbus-service.c \
+	src/core/dbus-service.h \
+	src/core/dbus-socket.c \
+	src/core/dbus-socket.h \
+	src/core/dbus-timer.c \
+	src/core/dbus-timer.h \
+	src/core/dbus-target.c \
+	src/core/dbus-target.h \
+	src/core/dbus-mount.c \
+	src/core/dbus-mount.h \
+	src/core/dbus-automount.c \
+	src/core/dbus-automount.h \
+	src/core/dbus-swap.c \
+	src/core/dbus-swap.h \
+	src/core/dbus-snapshot.c \
+	src/core/dbus-snapshot.h \
+	src/core/dbus-device.c \
+	src/core/dbus-device.h \
+	src/core/dbus-execute.c \
+	src/core/dbus-execute.h \
+	src/core/dbus-path.c \
+	src/core/dbus-path.h \
+	src/core/cgroup.c \
+	src/core/cgroup.h \
+	src/core/selinux-setup.c \
+	src/core/selinux-setup.h \
+	src/core/ima-setup.c \
+	src/core/ima-setup.h \
+	src/core/kmod-setup.c \
+	src/core/kmod-setup.h \
+	src/core/locale-setup.h \
+	src/core/locale-setup.c \
+	src/core/fdset.c \
+	src/core/fdset.h \
+	src/core/condition.c \
+	src/core/condition.h \
+	src/core/namespace.c \
+	src/core/namespace.h \
+	src/core/tcpwrap.c \
+	src/core/tcpwrap.h \
+	src/core/cgroup-attr.c \
+	src/core/cgroup-attr.h \
+	src/core/securebits.h \
+	src/core/initreq.h \
+	src/core/special.h \
+	src/core/bus-errors.h \
+	src/core/build.h \
+	src/core/ask-password-api.h \
+	src/core/sysfs-show.h \
+	src/core/polkit.h \
+	src/core/dbus-loop.h \
+	src/core/spawn-agent.h
 
 nodist_libsystemd_core_la_SOURCES = \
 	src/load-fragment-gperf.c \
@@ -948,6 +945,7 @@ pkginclude_HEADERS += \
 systemd_shutdown_SOURCES = \
 	src/mount-setup.c \
 	src/umount.c \
+	src/umount.h \
 	src/shutdown.c \
 	src/watchdog.c \
 	src/watchdog.h
@@ -1075,10 +1073,12 @@ systemctl_SOURCES = \
 	src/dbus-common.c \
 	src/path-lookup.c \
 	src/cgroup-show.c \
+	src/cgroup-show.h \
 	src/unit-name.c \
 	src/install.c \
 	src/spawn-agent.c \
-	src/logs-show.c
+	src/logs-show.c \
+	src/logs-show.h
 
 systemctl_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -1120,7 +1120,8 @@ systemd_reply_password_LDADD = \
 # ------------------------------------------------------------------------------
 systemd_cgls_SOURCES = \
 	src/cgls.c \
-	src/cgroup-show.c
+	src/cgroup-show.c \
+	src/cgroup-show.h
 
 systemd_cgls_LDADD = \
 	libsystemd-shared.la
@@ -1971,7 +1972,8 @@ systemd_cat_LDADD = \
 
 journalctl_SOURCES = \
 	src/journal/journalctl.c \
-	src/logs-show.c
+	src/logs-show.c \
+	src/logs-show.h
 
 journalctl_LDADD = \
 	libsystemd-shared.la \
@@ -2585,7 +2587,8 @@ loginctl_SOURCES = \
 	src/login/loginctl.c \
 	src/login/sysfs-show.c \
 	src/dbus-common.c \
-	src/cgroup-show.c
+	src/cgroup-show.c \
+	src/cgroup-show.h
 
 loginctl_CFLAGS = \
 	$(AM_CFLAGS) \
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 5a5d027..2acacbb 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,16 +1,16 @@
-src/dbus-automount.c
-src/dbus-device.c
-src/dbus-job.c
-src/dbus-manager.c
-src/dbus-mount.c
-src/dbus-path.c
-src/dbus-service.c
-src/dbus-snapshot.c
-src/dbus-socket.c
-src/dbus-swap.c
-src/dbus-target.c
-src/dbus-timer.c
-src/dbus-unit.c
+src/core/dbus-automount.c
+src/core/dbus-device.c
+src/core/dbus-job.c
+src/core/dbus-manager.c
+src/core/dbus-mount.c
+src/core/dbus-path.c
+src/core/dbus-service.c
+src/core/dbus-snapshot.c
+src/core/dbus-socket.c
+src/core/dbus-swap.c
+src/core/dbus-target.c
+src/core/dbus-timer.c
+src/core/dbus-unit.c
 src/hostname/hostnamed.c
 src/locale/localed.c
 src/org.freedesktop.systemd1.policy.in.in
diff --git a/src/ask-password-api.h b/src/ask-password-api.h
deleted file mode 100644
index fec8625..0000000
--- a/src/ask-password-api.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooaskpasswordapihfoo
-#define fooaskpasswordapihfoo
-
-/***
-  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 ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
-
-int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
-
-int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
-
-#endif
diff --git a/src/automount.c b/src/automount.c
deleted file mode 100644
index 6857a6f..0000000
--- a/src/automount.c
+++ /dev/null
@@ -1,888 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "bus-errors.h"
-#include "special.h"
-#include "label.h"
-#include "mkdir.h"
-
-static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
-        [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
-        [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
-        [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
-        [AUTOMOUNT_FAILED] = UNIT_FAILED
-};
-
-static int open_dev_autofs(Manager *m);
-
-static void automount_init(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        a->pipe_watch.fd = a->pipe_fd = -1;
-        a->pipe_watch.type = WATCH_INVALID;
-
-        a->directory_mode = 0755;
-
-        UNIT(a)->ignore_on_isolate = true;
-}
-
-static void repeat_unmout(const char *path) {
-        assert(path);
-
-        for (;;) {
-                /* If there are multiple mounts on a mount point, this
-                 * removes them all */
-
-                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)->manager->exit_code != MANAGER_RELOAD &&
-             UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
-                repeat_unmout(a->where);
-}
-
-static void automount_done(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        unmount_autofs(a);
-        unit_ref_unset(&a->mount);
-
-        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 (UNIT(a)->load_state != UNIT_LOADED ||
-            UNIT(m)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!path_startswith(a->where, m->where))
-                return 0;
-
-        if (path_equal(a->where, m->where))
-                return 0;
-
-        if ((r = unit_add_two_dependencies(UNIT(a), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
-                return r;
-
-        return 0;
-}
-
-static int automount_add_mount_links(Automount *a) {
-        Unit *other;
-        int r;
-
-        assert(a);
-
-        LIST_FOREACH(units_by_type, other, UNIT(a)->manager->units_by_type[UNIT_MOUNT])
-                if ((r = automount_add_one_mount_link(a, MOUNT(other))) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int automount_add_default_dependencies(Automount *a) {
-        int r;
-
-        assert(a);
-
-        if (UNIT(a)->manager->running_as == MANAGER_SYSTEM) {
-
-                if ((r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
-                        return r;
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int automount_verify(Automount *a) {
-        bool b;
-        char *e;
-        assert(a);
-
-        if (UNIT(a)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (path_equal(a->where, "/")) {
-                log_error("Cannot have an automount unit for the root directory. Refusing.");
-                return -EINVAL;
-        }
-
-        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)->id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int automount_load(Unit *u) {
-        int r;
-        Automount *a = AUTOMOUNT(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        /* Load a .automount file */
-        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
-                return r;
-
-        if (u->load_state == UNIT_LOADED) {
-                Unit *x;
-
-                if (!a->where)
-                        if (!(a->where = unit_name_to_path(u->id)))
-                                return -ENOMEM;
-
-                path_kill_slashes(a->where);
-
-                if ((r = automount_add_mount_links(a)) < 0)
-                        return r;
-
-                r = unit_load_related_unit(u, ".mount", &x);
-                if (r < 0)
-                        return r;
-
-                unit_ref_set(&a->mount, x);
-
-                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(a->mount), true);
-                if (r < 0)
-                        return r;
-
-                if (UNIT(a)->default_dependencies)
-                        if ((r = automount_add_default_dependencies(a)) < 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)->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], true);
-}
-
-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->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"
-                "%sResult: %s\n"
-                "%sWhere: %s\n"
-                "%sDirectoryMode: %04o\n",
-                prefix, automount_state_to_string(a->state),
-                prefix, automount_result_to_string(a->result),
-                prefix, a->where,
-                prefix, a->directory_mode);
-}
-
-static void automount_enter_dead(Automount *a, AutomountResult f) {
-        assert(a);
-
-        if (f != AUTOMOUNT_SUCCESS)
-                a->result = f;
-
-        automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : 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;
-
-        label_fix("/dev/autofs", false);
-
-        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)->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.");
-
-        r = 0;
-
-        /* 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)->manager->dev_autofs_fd,
-                                           ioctl_fd,
-                                           token,
-                                           status)) < 0)
-                        r = k;
-        }
-
-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)->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, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static void automount_enter_runnning(Automount *a) {
-        int r;
-        struct stat st;
-        DBusError error;
-
-        assert(a);
-        assert(UNIT_DEREF(a->mount));
-
-        dbus_error_init(&error);
-
-        /* We don't take mount requests anymore if we are supposed to
-         * shut down anyway */
-        if (unit_pending_inactive(UNIT(a))) {
-                log_debug("Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
-                automount_send_ready(a, -EHOSTDOWN);
-                return;
-        }
-
-        mkdir_p(a->where, a->directory_mode);
-
-        /* Before we do anything, let's see if somebody is playing games with us? */
-        if (lstat(a->where, &st) < 0) {
-                log_warning("%s failed to stat automount point: %m", UNIT(a)->id);
-                goto fail;
-        }
-
-        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
-                log_info("%s's automount point already active?", UNIT(a)->id);
-        else if ((r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_DEREF(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) {
-                log_warning("%s failed to queue mount startup job: %s", UNIT(a)->id, bus_error(&error, r));
-                goto fail;
-        }
-
-        automount_set_state(a, AUTOMOUNT_RUNNING);
-        return;
-
-fail:
-        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
-        dbus_error_free(&error);
-}
-
-static int automount_start(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
-
-        if (path_is_mount_point(a->where, false)) {
-                log_error("Path %s is already a mount point, refusing start for %s", a->where, u->id);
-                return -EEXIST;
-        }
-
-        if (UNIT_DEREF(a->mount)->load_state != UNIT_LOADED)
-                return -ENOENT;
-
-        a->result = AUTOMOUNT_SUCCESS;
-        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, AUTOMOUNT_SUCCESS);
-        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, "result", automount_result_to_string(a->result));
-        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, "result")) {
-                AutomountResult f;
-
-                f = automount_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != AUTOMOUNT_SUCCESS)
-                        a->result = f;
-
-        } 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);
-
-        if (!UNIT_DEREF(a->mount))
-                return false;
-
-        return UNIT_VTABLE(UNIT_DEREF(a->mount))->check_gc(UNIT_DEREF(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), true)) != 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:
-
-                if (packet.v5_packet.pid > 0) {
-                        char *p = NULL;
-
-                        get_process_comm(packet.v5_packet.pid, &p);
-                        log_debug("Got direct mount request for %s, triggered by %lu (%s)", packet.v5_packet.name, (unsigned long) packet.v5_packet.pid, strna(p));
-                        free(p);
-
-                } else
-                        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, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static void automount_shutdown(Manager *m) {
-        assert(m);
-
-        if (m->dev_autofs_fd >= 0)
-                close_nointr_nofail(m->dev_autofs_fd);
-}
-
-static void automount_reset_failed(Unit *u) {
-        Automount *a = AUTOMOUNT(u);
-
-        assert(a);
-
-        if (a->state == AUTOMOUNT_FAILED)
-                automount_set_state(a, AUTOMOUNT_DEAD);
-
-        a->result = AUTOMOUNT_SUCCESS;
-}
-
-static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
-        [AUTOMOUNT_DEAD] = "dead",
-        [AUTOMOUNT_WAITING] = "waiting",
-        [AUTOMOUNT_RUNNING] = "running",
-        [AUTOMOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-
-static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
-        [AUTOMOUNT_SUCCESS] = "success",
-        [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
-
-const UnitVTable automount_vtable = {
-        .suffix = ".automount",
-        .object_size = sizeof(Automount),
-        .sections =
-                "Unit\0"
-                "Automount\0"
-                "Install\0",
-
-        .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,
-
-        .reset_failed = automount_reset_failed,
-
-        .bus_interface = "org.freedesktop.systemd1.Automount",
-        .bus_message_handler = bus_automount_message_handler,
-        .bus_invalidating_properties = bus_automount_invalidating_properties,
-
-        .shutdown = automount_shutdown
-};
diff --git a/src/automount.h b/src/automount.h
deleted file mode 100644
index 19baee2..0000000
--- a/src/automount.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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_FAILED,
-        _AUTOMOUNT_STATE_MAX,
-        _AUTOMOUNT_STATE_INVALID = -1
-} AutomountState;
-
-typedef enum AutomountResult {
-        AUTOMOUNT_SUCCESS,
-        AUTOMOUNT_FAILURE_RESOURCES,
-        _AUTOMOUNT_RESULT_MAX,
-        _AUTOMOUNT_RESULT_INVALID = -1
-} AutomountResult;
-
-struct Automount {
-        Unit meta;
-
-        AutomountState state, deserialized_state;
-
-        char *where;
-
-        UnitRef mount;
-
-        int pipe_fd;
-        mode_t directory_mode;
-        Watch pipe_watch;
-        dev_t dev_id;
-
-        Set *tokens;
-
-        AutomountResult result;
-};
-
-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);
-
-const char* automount_result_to_string(AutomountResult i);
-AutomountResult automount_result_from_string(const char *s);
-
-#endif
diff --git a/src/build.h b/src/build.h
deleted file mode 100644
index 0619013..0000000
--- a/src/build.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foobuildhfoo
-#define foobuildhfoo
-
-/***
-  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/>.
-***/
-
-#ifdef HAVE_PAM
-#define _PAM_FEATURE_ "+PAM"
-#else
-#define _PAM_FEATURE_ "-PAM"
-#endif
-
-#ifdef HAVE_LIBWRAP
-#define _LIBWRAP_FEATURE_ "+LIBWRAP"
-#else
-#define _LIBWRAP_FEATURE_ "-LIBWRAP"
-#endif
-
-#ifdef HAVE_AUDIT
-#define _AUDIT_FEATURE_ "+AUDIT"
-#else
-#define _AUDIT_FEATURE_ "-AUDIT"
-#endif
-
-#ifdef HAVE_SELINUX
-#define _SELINUX_FEATURE_ "+SELINUX"
-#else
-#define _SELINUX_FEATURE_ "-SELINUX"
-#endif
-
-#ifdef HAVE_IMA
-#define _IMA_FEATURE_ "+IMA"
-#else
-#define _IMA_FEATURE_ "-IMA"
-#endif
-
-#ifdef HAVE_SYSV_COMPAT
-#define _SYSVINIT_FEATURE_ "+SYSVINIT"
-#else
-#define _SYSVINIT_FEATURE_ "-SYSVINIT"
-#endif
-
-#ifdef HAVE_LIBCRYPTSETUP
-#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP"
-#else
-#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP"
-#endif
-
-#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_
-
-#endif
diff --git a/src/bus-errors.h b/src/bus-errors.h
deleted file mode 100644
index 82d4e99..0000000
--- a/src/bus-errors.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foobuserrorshfoo
-#define foobuserrorshfoo
-
-/***
-  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 <dbus/dbus.h>
-
-#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
-#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob"
-#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed"
-#define BUS_ERROR_INVALID_PATH "org.freedesktop.systemd1.InvalidPath"
-#define BUS_ERROR_INVALID_NAME "org.freedesktop.systemd1.InvalidName"
-#define BUS_ERROR_UNIT_TYPE_MISMATCH "org.freedesktop.systemd1.UnitTypeMismatch"
-#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists"
-#define BUS_ERROR_NOT_SUPPORTED "org.freedesktop.systemd1.NotSupported"
-#define BUS_ERROR_INVALID_JOB_MODE "org.freedesktop.systemd1.InvalidJobMode"
-#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency"
-#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation"
-#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed"
-#define BUS_ERROR_MASKED "org.freedesktop.systemd1.Masked"
-#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable"
-#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive"
-#define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting"
-#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
-#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
-#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess"
-
-static inline const char *bus_error(const DBusError *e, int r) {
-        if (e && e->message)
-                return e->message;
-
-        if (r >= 0)
-                return strerror(r);
-
-        return strerror(-r);
-}
-
-#endif
diff --git a/src/cgroup-attr.c b/src/cgroup-attr.c
deleted file mode 100644
index 474a686..0000000
--- a/src/cgroup-attr.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2011 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 "cgroup-attr.h"
-#include "cgroup-util.h"
-#include "list.h"
-
-int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) {
-        int r;
-        char *path = NULL;
-        char *v = NULL;
-
-        assert(a);
-
-        b = cgroup_bonding_find_list(b, a->controller);
-        if (!b)
-                return 0;
-
-        if (a->map_callback) {
-                r = a->map_callback(a->controller, a->name, a->value, &v);
-                if (r < 0)
-                        return r;
-        }
-
-        r = cg_get_path(a->controller, b->path, a->name, &path);
-        if (r < 0) {
-                free(v);
-                return r;
-        }
-
-        r = write_one_line_file(path, v ? v : a->value);
-        if (r < 0)
-                log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r));
-
-        free(path);
-        free(v);
-
-        return r;
-}
-
-int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b) {
-        CGroupAttribute *a;
-        int r = 0;
-
-        LIST_FOREACH(by_unit, a, first) {
-                int k;
-
-                k = cgroup_attribute_apply(a, b);
-                if (r == 0)
-                        r = k;
-        }
-
-        return r;
-}
-
-CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name) {
-        CGroupAttribute *a;
-
-        assert(controller);
-        assert(name);
-
-        LIST_FOREACH(by_unit, a, first)
-                if (streq(a->controller, controller) &&
-                    streq(a->name, name))
-                        return a;
-
-        return NULL;
-}
-
-static void cgroup_attribute_free(CGroupAttribute *a) {
-        assert(a);
-
-        free(a->controller);
-        free(a->name);
-        free(a->value);
-        free(a);
-}
-
-void cgroup_attribute_free_list(CGroupAttribute *first) {
-        CGroupAttribute *a, *n;
-
-        LIST_FOREACH_SAFE(by_unit, a, n, first)
-                cgroup_attribute_free(a);
-}
diff --git a/src/cgroup-attr.h b/src/cgroup-attr.h
deleted file mode 100644
index 63a73b8..0000000
--- a/src/cgroup-attr.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foocgroupattrhfoo
-#define foocgroupattrhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2011 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 CGroupAttribute CGroupAttribute;
-
-typedef int (*CGroupAttributeMapCallback)(const char *controller, const char*name, const char *value, char **ret);
-
-#include "unit.h"
-#include "cgroup.h"
-
-struct CGroupAttribute {
-        char *controller;
-        char *name;
-        char *value;
-
-        CGroupAttributeMapCallback map_callback;
-
-        LIST_FIELDS(CGroupAttribute, by_unit);
-};
-
-int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b);
-int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b);
-
-CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name);
-
-void cgroup_attribute_free_list(CGroupAttribute *first);
-
-#endif
diff --git a/src/cgroup.c b/src/cgroup.c
deleted file mode 100644
index 1f6139e..0000000
--- a/src/cgroup.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <fcntl.h>
-
-#include "cgroup.h"
-#include "cgroup-util.h"
-#include "log.h"
-
-int cgroup_bonding_realize(CGroupBonding *b) {
-        int r;
-
-        assert(b);
-        assert(b->path);
-        assert(b->controller);
-
-        r = cg_create(b->controller, b->path);
-        if (r < 0) {
-                log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
-                return r;
-        }
-
-        b->realized = true;
-
-        return 0;
-}
-
-int cgroup_bonding_realize_list(CGroupBonding *first) {
-        CGroupBonding *b;
-        int r;
-
-        LIST_FOREACH(by_unit, b, first)
-                if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
-                        return r;
-
-        return 0;
-}
-
-void cgroup_bonding_free(CGroupBonding *b, bool trim) {
-        assert(b);
-
-        if (b->unit) {
-                CGroupBonding *f;
-
-                LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
-
-                if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                        assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
-                        LIST_REMOVE(CGroupBonding, by_path, f, b);
-
-                        if (f)
-                                hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
-                        else
-                                hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
-                }
-        }
-
-        if (b->realized && b->ours && trim)
-                cg_trim(b->controller, b->path, false);
-
-        free(b->controller);
-        free(b->path);
-        free(b);
-}
-
-void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
-        CGroupBonding *b, *n;
-
-        LIST_FOREACH_SAFE(by_unit, b, n, first)
-                cgroup_bonding_free(b, remove_or_trim);
-}
-
-void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
-        assert(b);
-
-        if (b->realized && b->ours)
-                cg_trim(b->controller, b->path, delete_root);
-}
-
-void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
-        CGroupBonding *b;
-
-        LIST_FOREACH(by_unit, b, first)
-                cgroup_bonding_trim(b, delete_root);
-}
-
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
-        int r;
-
-        assert(b);
-        assert(pid >= 0);
-
-        if ((r = cg_create_and_attach(b->controller, b->path, pid)) < 0)
-                return r;
-
-        b->realized = true;
-        return 0;
-}
-
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
-        CGroupBonding *b;
-        int r;
-
-        LIST_FOREACH(by_unit, b, first)
-                if ((r = cgroup_bonding_install(b, pid)) < 0 && b->essential)
-                        return r;
-
-        return 0;
-}
-
-int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
-        assert(b);
-
-        if (!b->realized)
-                return -EINVAL;
-
-        return cg_set_group_access(b->controller, b->path, mode, uid, gid);
-}
-
-int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
-        CGroupBonding *b;
-        int r;
-
-        LIST_FOREACH(by_unit, b, first) {
-                r = cgroup_bonding_set_group_access(b, mode, uid, gid);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
-        assert(b);
-
-        if (!b->realized)
-                return -EINVAL;
-
-        return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
-}
-
-int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
-        CGroupBonding *b;
-        int r;
-
-        LIST_FOREACH(by_unit, b, first) {
-                r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s) {
-        assert(b);
-        assert(sig >= 0);
-
-        /* Don't kill cgroups that aren't ours */
-        if (!b->ours)
-                return 0;
-
-        return cg_kill_recursive(b->controller, b->path, sig, sigcont, true, false, s);
-}
-
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s) {
-        CGroupBonding *b;
-        Set *allocated_set = NULL;
-        int ret = -EAGAIN, r;
-
-        if (!first)
-                return 0;
-
-        if (!s)
-                if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
-                        return -ENOMEM;
-
-        LIST_FOREACH(by_unit, b, first) {
-                if ((r = cgroup_bonding_kill(b, sig, sigcont, s)) < 0) {
-                        if (r == -EAGAIN || r == -ESRCH)
-                                continue;
-
-                        ret = r;
-                        goto finish;
-                }
-
-                if (ret < 0 || r > 0)
-                        ret = r;
-        }
-
-finish:
-        if (allocated_set)
-                set_free(allocated_set);
-
-        return ret;
-}
-
-/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
- * cannot know */
-int cgroup_bonding_is_empty(CGroupBonding *b) {
-        int r;
-
-        assert(b);
-
-        if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
-                return r;
-
-        /* If it is empty it is empty */
-        if (r > 0)
-                return 1;
-
-        /* It's not only us using this cgroup, so we just don't know */
-        return b->ours ? 0 : -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;
-}
-
-int manager_setup_cgroup(Manager *m) {
-        char *current = NULL, *path = NULL;
-        int r;
-        char suffix[32];
-
-        assert(m);
-
-        /* 0. Be nice to Ingo Molnar #628004 */
-        if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
-                log_warning("No control group support available, not creating root group.");
-                return 0;
-        }
-
-        /* 1. Determine hierarchy */
-        if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current)) < 0) {
-                log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
-                goto finish;
-        }
-
-        if (m->running_as == MANAGER_SYSTEM)
-                strcpy(suffix, "/system");
-        else {
-                snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
-                char_array_0(suffix);
-        }
-
-        free(m->cgroup_hierarchy);
-        if (endswith(current, suffix)) {
-                /* We probably got reexecuted and can continue to use our root cgroup */
-                m->cgroup_hierarchy = current;
-                current = NULL;
-
-        } else {
-                /* We need a new root cgroup */
-                m->cgroup_hierarchy = NULL;
-                if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
-                        log_error("Out of memory");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-        }
-
-        /* 2. Show data */
-        if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
-                log_error("Cannot find cgroup mount point: %s", strerror(-r));
-                goto finish;
-        }
-
-        log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
-
-        /* 3. Install agent */
-        if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
-                log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
-        else if (r > 0)
-                log_debug("Installed release agent.");
-        else
-                log_debug("Release agent already installed.");
-
-        /* 4. Realize the group */
-        if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
-                log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
-                goto finish;
-        }
-
-        /* 5. And pin it, so that it cannot be unmounted */
-        if (m->pin_cgroupfs_fd >= 0)
-                close_nointr_nofail(m->pin_cgroupfs_fd);
-
-        if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
-                log_error("Failed to open pin file: %m");
-                r = -errno;
-                goto finish;
-        }
-
-        log_debug("Created root group.");
-
-finish:
-        free(current);
-        free(path);
-
-        return r;
-}
-
-void manager_shutdown_cgroup(Manager *m, bool delete) {
-        assert(m);
-
-        if (delete && m->cgroup_hierarchy)
-                cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
-
-        if (m->pin_cgroupfs_fd >= 0) {
-                close_nointr_nofail(m->pin_cgroupfs_fd);
-                m->pin_cgroupfs_fd = -1;
-        }
-
-        free(m->cgroup_hierarchy);
-        m->cgroup_hierarchy = NULL;
-}
-
-int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
-        CGroupBonding *b;
-        char *p;
-
-        assert(m);
-        assert(cgroup);
-        assert(bonding);
-
-        b = hashmap_get(m->cgroup_bondings, cgroup);
-        if (b) {
-                *bonding = b;
-                return 1;
-        }
-
-        p = strdup(cgroup);
-        if (!p)
-                return -ENOMEM;
-
-        for (;;) {
-                char *e;
-
-                e = strrchr(p, '/');
-                if (!e || e == p) {
-                        free(p);
-                        *bonding = NULL;
-                        return 0;
-                }
-
-                *e = 0;
-
-                b = hashmap_get(m->cgroup_bondings, p);
-                if (b) {
-                        free(p);
-                        *bonding = b;
-                        return 1;
-                }
-        }
-}
-
-int cgroup_notify_empty(Manager *m, const char *group) {
-        CGroupBonding *l, *b;
-        int r;
-
-        assert(m);
-        assert(group);
-
-        r = cgroup_bonding_get(m, group, &l);
-        if (r <= 0)
-                return r;
-
-        LIST_FOREACH(by_path, b, l) {
-                int t;
-
-                if (!b->unit)
-                        continue;
-
-                t = cgroup_bonding_is_empty_list(b);
-                if (t < 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 it is empty, let's delete it */
-                        cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
-
-                        if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
-                                UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
-                }
-        }
-
-        return 0;
-}
-
-Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
-        CGroupBonding *l, *b;
-        char *group = NULL;
-
-        assert(m);
-
-        if (pid <= 1)
-                return NULL;
-
-        if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
-                return NULL;
-
-        l = hashmap_get(m->cgroup_bondings, group);
-
-        if (!l) {
-                char *slash;
-
-                while ((slash = strrchr(group, '/'))) {
-                        if (slash == group)
-                                break;
-
-                        *slash = 0;
-
-                        if ((l = hashmap_get(m->cgroup_bondings, group)))
-                                break;
-                }
-        }
-
-        free(group);
-
-        LIST_FOREACH(by_path, b, l) {
-
-                if (!b->unit)
-                        continue;
-
-                if (b->ours)
-                        return b->unit;
-        }
-
-        return NULL;
-}
-
-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;
-}
-
-pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
-        FILE *f;
-        pid_t pid = 0, npid, mypid;
-
-        assert(b);
-
-        if (!b->ours)
-                return 0;
-
-        if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
-                return 0;
-
-        mypid = getpid();
-
-        while (cg_read_pid(f, &npid) > 0)  {
-                pid_t ppid;
-
-                if (npid == pid)
-                        continue;
-
-                /* Ignore processes that aren't our kids */
-                if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
-                        continue;
-
-                if (pid != 0) {
-                        /* Dang, there's more than one daemonized PID
-                        in this group, so we don't know what process
-                        is the main process. */
-                        pid = 0;
-                        break;
-                }
-
-                pid = npid;
-        }
-
-        fclose(f);
-
-        return pid;
-}
-
-pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
-        CGroupBonding *b;
-        pid_t pid;
-
-        /* Try to find a main pid from this cgroup, but checking if
-         * there's only one PID in the cgroup and returning it. Later
-         * on we might want to add additional, smarter heuristics
-         * here. */
-
-        LIST_FOREACH(by_unit, b, first)
-                if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
-                        return pid;
-
-        return 0;
-
-}
diff --git a/src/cgroup.h b/src/cgroup.h
deleted file mode 100644
index 5faa7dc..0000000
--- a/src/cgroup.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-typedef struct CGroupBonding CGroupBonding;
-
-#include "unit.h"
-
-/* Binds a cgroup to a name */
-struct CGroupBonding {
-        char *controller;
-        char *path;
-
-        Unit *unit;
-
-        /* 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? Are our own tasks the
-         * only ones in this group?*/
-        bool ours:1;
-
-        /* If we cannot create this group, or add a process to it, is this fatal? */
-        bool essential:1;
-
-        /* This cgroup is realized */
-        bool realized:1;
-};
-
-int cgroup_bonding_realize(CGroupBonding *b);
-int cgroup_bonding_realize_list(CGroupBonding *first);
-
-void cgroup_bonding_free(CGroupBonding *b, bool trim);
-void cgroup_bonding_free_list(CGroupBonding *first, bool trim);
-
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid);
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid);
-
-int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
-int cgroup_bonding_set_group_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
-
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
-int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
-
-int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s);
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s);
-
-void cgroup_bonding_trim(CGroupBonding *first, bool delete_root);
-void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root);
-
-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);
-
-pid_t cgroup_bonding_search_main_pid(CGroupBonding *b);
-pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b);
-
-#include "manager.h"
-
-int manager_setup_cgroup(Manager *m);
-void manager_shutdown_cgroup(Manager *m, bool delete);
-
-int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding);
-int cgroup_notify_empty(Manager *m, const char *group);
-
-Unit* cgroup_unit_by_pid(Manager *m, pid_t pid);
-
-#endif
diff --git a/src/condition.c b/src/condition.c
deleted file mode 100644
index 2b51a16..0000000
--- a/src/condition.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/capability.h>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#include "util.h"
-#include "condition.h"
-#include "virt.h"
-
-Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
-        Condition *c;
-
-        assert(type < _CONDITION_TYPE_MAX);
-
-        c = new0(Condition, 1);
-        if (!c)
-                return NULL;
-
-        c->type = type;
-        c->trigger = trigger;
-        c->negate = negate;
-
-        if (parameter) {
-                c->parameter = strdup(parameter);
-                if (!c->parameter) {
-                        free(c);
-                        return NULL;
-                }
-        }
-
-        return c;
-}
-
-void condition_free(Condition *c) {
-        assert(c);
-
-        free(c->parameter);
-        free(c);
-}
-
-void condition_free_list(Condition *first) {
-        Condition *c, *n;
-
-        LIST_FOREACH_SAFE(conditions, c, n, first)
-                condition_free(c);
-}
-
-static bool test_kernel_command_line(const char *parameter) {
-        char *line, *w, *state, *word = NULL;
-        bool equal;
-        int r;
-        size_t l, pl;
-        bool found = false;
-
-        assert(parameter);
-
-        if (detect_container(NULL) > 0)
-                return false;
-
-        r = read_one_line_file("/proc/cmdline", &line);
-        if (r < 0) {
-                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
-                return false;
-        }
-
-        equal = !!strchr(parameter, '=');
-        pl = strlen(parameter);
-
-        FOREACH_WORD_QUOTED(w, l, line, state) {
-
-                free(word);
-                word = strndup(w, l);
-                if (!word)
-                        break;
-
-                if (equal) {
-                        if (streq(word, parameter)) {
-                                found = true;
-                                break;
-                        }
-                } else {
-                        if (startswith(word, parameter) && (word[pl] == '=' || word[pl] == 0)) {
-                                found = true;
-                                break;
-                        }
-                }
-
-        }
-
-        free(word);
-        free(line);
-
-        return found;
-}
-
-static bool test_virtualization(const char *parameter) {
-        int b;
-        Virtualization v;
-        const char *id;
-
-        assert(parameter);
-
-        v = detect_virtualization(&id);
-        if (v < 0) {
-                log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
-                return false;
-        }
-
-        /* First, compare with yes/no */
-        b = parse_boolean(parameter);
-
-        if (v > 0 && b > 0)
-                return true;
-
-        if (v == 0 && b == 0)
-                return true;
-
-        /* Then, compare categorization */
-        if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
-                return true;
-
-        if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
-                return true;
-
-        /* Finally compare id */
-        return v > 0 && streq(parameter, id);
-}
-
-static bool test_security(const char *parameter) {
-#ifdef HAVE_SELINUX
-        if (streq(parameter, "selinux"))
-                return is_selinux_enabled() > 0;
-#endif
-        return false;
-}
-
-static bool test_capability(const char *parameter) {
-        cap_value_t value;
-        FILE *f;
-        char line[LINE_MAX];
-        unsigned long long capabilities = (unsigned long long) -1;
-
-        /* If it's an invalid capability, we don't have it */
-
-        if (cap_from_name(parameter, &value) < 0)
-                return false;
-
-        /* If it's a valid capability we default to assume
-         * that we have it */
-
-        f = fopen("/proc/self/status", "re");
-        if (!f)
-                return true;
-
-        while (fgets(line, sizeof(line), f)) {
-                truncate_nl(line);
-
-                if (startswith(line, "CapBnd:")) {
-                        (void) sscanf(line+7, "%llx", &capabilities);
-                        break;
-                }
-        }
-
-        fclose(f);
-
-        return !!(capabilities & (1ULL << value));
-}
-
-bool condition_test(Condition *c) {
-        assert(c);
-
-        switch(c->type) {
-
-        case CONDITION_PATH_EXISTS:
-                return (access(c->parameter, F_OK) >= 0) == !c->negate;
-
-        case CONDITION_PATH_EXISTS_GLOB:
-                return (glob_exists(c->parameter) > 0) == !c->negate;
-
-        case CONDITION_PATH_IS_DIRECTORY: {
-                struct stat st;
-
-                if (stat(c->parameter, &st) < 0)
-                        return c->negate;
-                return S_ISDIR(st.st_mode) == !c->negate;
-        }
-
-        case CONDITION_PATH_IS_SYMBOLIC_LINK: {
-                struct stat st;
-
-                if (lstat(c->parameter, &st) < 0)
-                        return c->negate;
-                return S_ISLNK(st.st_mode) == !c->negate;
-        }
-
-        case CONDITION_PATH_IS_MOUNT_POINT:
-                return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
-
-        case CONDITION_DIRECTORY_NOT_EMPTY: {
-                int k;
-
-                k = dir_is_empty(c->parameter);
-                return !(k == -ENOENT || k > 0) == !c->negate;
-        }
-
-        case CONDITION_FILE_IS_EXECUTABLE: {
-                struct stat st;
-
-                if (stat(c->parameter, &st) < 0)
-                        return c->negate;
-
-                return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
-        }
-
-        case CONDITION_KERNEL_COMMAND_LINE:
-                return test_kernel_command_line(c->parameter) == !c->negate;
-
-        case CONDITION_VIRTUALIZATION:
-                return test_virtualization(c->parameter) == !c->negate;
-
-        case CONDITION_SECURITY:
-                return test_security(c->parameter) == !c->negate;
-
-        case CONDITION_CAPABILITY:
-                return test_capability(c->parameter) == !c->negate;
-
-        case CONDITION_NULL:
-                return !c->negate;
-
-        default:
-                assert_not_reached("Invalid condition type.");
-        }
-}
-
-bool condition_test_list(Condition *first) {
-        Condition *c;
-        int triggered = -1;
-
-        /* If the condition list is empty, then it is true */
-        if (!first)
-                return true;
-
-        /* Otherwise, if all of the non-trigger conditions apply and
-         * if any of the trigger conditions apply (unless there are
-         * none) we return true */
-        LIST_FOREACH(conditions, c, first) {
-                bool b;
-
-                b = condition_test(c);
-
-                if (!c->trigger && !b)
-                        return false;
-
-                if (c->trigger && triggered <= 0)
-                        triggered = b;
-        }
-
-        return triggered != 0;
-}
-
-void condition_dump(Condition *c, FILE *f, const char *prefix) {
-        assert(c);
-        assert(f);
-
-        if (!prefix)
-                prefix = "";
-
-        fprintf(f,
-                "%s\t%s: %s%s%s\n",
-                prefix,
-                condition_type_to_string(c->type),
-                c->trigger ? "|" : "",
-                c->negate ? "!" : "",
-                c->parameter);
-}
-
-void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
-        Condition *c;
-
-        LIST_FOREACH(conditions, c, first)
-                condition_dump(c, f, prefix);
-}
-
-static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
-        [CONDITION_PATH_EXISTS] = "ConditionPathExists",
-        [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
-        [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
-        [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
-        [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
-        [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
-        [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
-        [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
-        [CONDITION_SECURITY] = "ConditionSecurity",
-        [CONDITION_NULL] = "ConditionNull"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
diff --git a/src/condition.h b/src/condition.h
deleted file mode 100644
index 71b1c67..0000000
--- a/src/condition.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooconditionhfoo
-#define fooconditionhfoo
-
-/***
-  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 "list.h"
-
-typedef enum ConditionType {
-        CONDITION_PATH_EXISTS,
-        CONDITION_PATH_EXISTS_GLOB,
-        CONDITION_PATH_IS_DIRECTORY,
-        CONDITION_PATH_IS_SYMBOLIC_LINK,
-        CONDITION_PATH_IS_MOUNT_POINT,
-        CONDITION_DIRECTORY_NOT_EMPTY,
-        CONDITION_FILE_IS_EXECUTABLE,
-        CONDITION_KERNEL_COMMAND_LINE,
-        CONDITION_VIRTUALIZATION,
-        CONDITION_SECURITY,
-        CONDITION_CAPABILITY,
-        CONDITION_NULL,
-        _CONDITION_TYPE_MAX,
-        _CONDITION_TYPE_INVALID = -1
-} ConditionType;
-
-typedef struct Condition {
-        ConditionType type;
-        char *parameter;
-
-        bool trigger:1;
-        bool negate:1;
-
-        LIST_FIELDS(struct Condition, conditions);
-} Condition;
-
-Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate);
-void condition_free(Condition *c);
-void condition_free_list(Condition *c);
-
-bool condition_test(Condition *c);
-bool condition_test_list(Condition *c);
-
-void condition_dump(Condition *c, FILE *f, const char *prefix);
-void condition_dump_list(Condition *c, FILE *f, const char *prefix);
-
-const char* condition_type_to_string(ConditionType t);
-int condition_type_from_string(const char *s);
-
-#endif
diff --git a/src/core/ask-password-api.h b/src/core/ask-password-api.h
new file mode 100644
index 0000000..fec8625
--- /dev/null
+++ b/src/core/ask-password-api.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooaskpasswordapihfoo
+#define fooaskpasswordapihfoo
+
+/***
+  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 ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
+
+int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
+
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
+
+#endif
diff --git a/src/core/automount.c b/src/core/automount.c
new file mode 100644
index 0000000..6857a6f
--- /dev/null
+++ b/src/core/automount.c
@@ -0,0 +1,888 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "bus-errors.h"
+#include "special.h"
+#include "label.h"
+#include "mkdir.h"
+
+static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
+        [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
+        [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
+        [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
+        [AUTOMOUNT_FAILED] = UNIT_FAILED
+};
+
+static int open_dev_autofs(Manager *m);
+
+static void automount_init(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        a->pipe_watch.fd = a->pipe_fd = -1;
+        a->pipe_watch.type = WATCH_INVALID;
+
+        a->directory_mode = 0755;
+
+        UNIT(a)->ignore_on_isolate = true;
+}
+
+static void repeat_unmout(const char *path) {
+        assert(path);
+
+        for (;;) {
+                /* If there are multiple mounts on a mount point, this
+                 * removes them all */
+
+                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)->manager->exit_code != MANAGER_RELOAD &&
+             UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
+                repeat_unmout(a->where);
+}
+
+static void automount_done(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        unmount_autofs(a);
+        unit_ref_unset(&a->mount);
+
+        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 (UNIT(a)->load_state != UNIT_LOADED ||
+            UNIT(m)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!path_startswith(a->where, m->where))
+                return 0;
+
+        if (path_equal(a->where, m->where))
+                return 0;
+
+        if ((r = unit_add_two_dependencies(UNIT(a), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
+                return r;
+
+        return 0;
+}
+
+static int automount_add_mount_links(Automount *a) {
+        Unit *other;
+        int r;
+
+        assert(a);
+
+        LIST_FOREACH(units_by_type, other, UNIT(a)->manager->units_by_type[UNIT_MOUNT])
+                if ((r = automount_add_one_mount_link(a, MOUNT(other))) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int automount_add_default_dependencies(Automount *a) {
+        int r;
+
+        assert(a);
+
+        if (UNIT(a)->manager->running_as == MANAGER_SYSTEM) {
+
+                if ((r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
+                        return r;
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int automount_verify(Automount *a) {
+        bool b;
+        char *e;
+        assert(a);
+
+        if (UNIT(a)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (path_equal(a->where, "/")) {
+                log_error("Cannot have an automount unit for the root directory. Refusing.");
+                return -EINVAL;
+        }
+
+        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)->id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int automount_load(Unit *u) {
+        int r;
+        Automount *a = AUTOMOUNT(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        /* Load a .automount file */
+        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
+                return r;
+
+        if (u->load_state == UNIT_LOADED) {
+                Unit *x;
+
+                if (!a->where)
+                        if (!(a->where = unit_name_to_path(u->id)))
+                                return -ENOMEM;
+
+                path_kill_slashes(a->where);
+
+                if ((r = automount_add_mount_links(a)) < 0)
+                        return r;
+
+                r = unit_load_related_unit(u, ".mount", &x);
+                if (r < 0)
+                        return r;
+
+                unit_ref_set(&a->mount, x);
+
+                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(a->mount), true);
+                if (r < 0)
+                        return r;
+
+                if (UNIT(a)->default_dependencies)
+                        if ((r = automount_add_default_dependencies(a)) < 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)->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], true);
+}
+
+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->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"
+                "%sResult: %s\n"
+                "%sWhere: %s\n"
+                "%sDirectoryMode: %04o\n",
+                prefix, automount_state_to_string(a->state),
+                prefix, automount_result_to_string(a->result),
+                prefix, a->where,
+                prefix, a->directory_mode);
+}
+
+static void automount_enter_dead(Automount *a, AutomountResult f) {
+        assert(a);
+
+        if (f != AUTOMOUNT_SUCCESS)
+                a->result = f;
+
+        automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : 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;
+
+        label_fix("/dev/autofs", false);
+
+        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)->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.");
+
+        r = 0;
+
+        /* 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)->manager->dev_autofs_fd,
+                                           ioctl_fd,
+                                           token,
+                                           status)) < 0)
+                        r = k;
+        }
+
+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)->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, AUTOMOUNT_FAILURE_RESOURCES);
+}
+
+static void automount_enter_runnning(Automount *a) {
+        int r;
+        struct stat st;
+        DBusError error;
+
+        assert(a);
+        assert(UNIT_DEREF(a->mount));
+
+        dbus_error_init(&error);
+
+        /* We don't take mount requests anymore if we are supposed to
+         * shut down anyway */
+        if (unit_pending_inactive(UNIT(a))) {
+                log_debug("Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
+                automount_send_ready(a, -EHOSTDOWN);
+                return;
+        }
+
+        mkdir_p(a->where, a->directory_mode);
+
+        /* Before we do anything, let's see if somebody is playing games with us? */
+        if (lstat(a->where, &st) < 0) {
+                log_warning("%s failed to stat automount point: %m", UNIT(a)->id);
+                goto fail;
+        }
+
+        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
+                log_info("%s's automount point already active?", UNIT(a)->id);
+        else if ((r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_DEREF(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) {
+                log_warning("%s failed to queue mount startup job: %s", UNIT(a)->id, bus_error(&error, r));
+                goto fail;
+        }
+
+        automount_set_state(a, AUTOMOUNT_RUNNING);
+        return;
+
+fail:
+        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
+        dbus_error_free(&error);
+}
+
+static int automount_start(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
+
+        if (path_is_mount_point(a->where, false)) {
+                log_error("Path %s is already a mount point, refusing start for %s", a->where, u->id);
+                return -EEXIST;
+        }
+
+        if (UNIT_DEREF(a->mount)->load_state != UNIT_LOADED)
+                return -ENOENT;
+
+        a->result = AUTOMOUNT_SUCCESS;
+        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, AUTOMOUNT_SUCCESS);
+        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, "result", automount_result_to_string(a->result));
+        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, "result")) {
+                AutomountResult f;
+
+                f = automount_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != AUTOMOUNT_SUCCESS)
+                        a->result = f;
+
+        } 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);
+
+        if (!UNIT_DEREF(a->mount))
+                return false;
+
+        return UNIT_VTABLE(UNIT_DEREF(a->mount))->check_gc(UNIT_DEREF(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), true)) != 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:
+
+                if (packet.v5_packet.pid > 0) {
+                        char *p = NULL;
+
+                        get_process_comm(packet.v5_packet.pid, &p);
+                        log_debug("Got direct mount request for %s, triggered by %lu (%s)", packet.v5_packet.name, (unsigned long) packet.v5_packet.pid, strna(p));
+                        free(p);
+
+                } else
+                        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, AUTOMOUNT_FAILURE_RESOURCES);
+}
+
+static void automount_shutdown(Manager *m) {
+        assert(m);
+
+        if (m->dev_autofs_fd >= 0)
+                close_nointr_nofail(m->dev_autofs_fd);
+}
+
+static void automount_reset_failed(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        if (a->state == AUTOMOUNT_FAILED)
+                automount_set_state(a, AUTOMOUNT_DEAD);
+
+        a->result = AUTOMOUNT_SUCCESS;
+}
+
+static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
+        [AUTOMOUNT_DEAD] = "dead",
+        [AUTOMOUNT_WAITING] = "waiting",
+        [AUTOMOUNT_RUNNING] = "running",
+        [AUTOMOUNT_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
+
+static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
+        [AUTOMOUNT_SUCCESS] = "success",
+        [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
+
+const UnitVTable automount_vtable = {
+        .suffix = ".automount",
+        .object_size = sizeof(Automount),
+        .sections =
+                "Unit\0"
+                "Automount\0"
+                "Install\0",
+
+        .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,
+
+        .reset_failed = automount_reset_failed,
+
+        .bus_interface = "org.freedesktop.systemd1.Automount",
+        .bus_message_handler = bus_automount_message_handler,
+        .bus_invalidating_properties = bus_automount_invalidating_properties,
+
+        .shutdown = automount_shutdown
+};
diff --git a/src/core/automount.h b/src/core/automount.h
new file mode 100644
index 0000000..19baee2
--- /dev/null
+++ b/src/core/automount.h
@@ -0,0 +1,76 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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_FAILED,
+        _AUTOMOUNT_STATE_MAX,
+        _AUTOMOUNT_STATE_INVALID = -1
+} AutomountState;
+
+typedef enum AutomountResult {
+        AUTOMOUNT_SUCCESS,
+        AUTOMOUNT_FAILURE_RESOURCES,
+        _AUTOMOUNT_RESULT_MAX,
+        _AUTOMOUNT_RESULT_INVALID = -1
+} AutomountResult;
+
+struct Automount {
+        Unit meta;
+
+        AutomountState state, deserialized_state;
+
+        char *where;
+
+        UnitRef mount;
+
+        int pipe_fd;
+        mode_t directory_mode;
+        Watch pipe_watch;
+        dev_t dev_id;
+
+        Set *tokens;
+
+        AutomountResult result;
+};
+
+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);
+
+const char* automount_result_to_string(AutomountResult i);
+AutomountResult automount_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/build.h b/src/core/build.h
new file mode 100644
index 0000000..0619013
--- /dev/null
+++ b/src/core/build.h
@@ -0,0 +1,69 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foobuildhfoo
+#define foobuildhfoo
+
+/***
+  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/>.
+***/
+
+#ifdef HAVE_PAM
+#define _PAM_FEATURE_ "+PAM"
+#else
+#define _PAM_FEATURE_ "-PAM"
+#endif
+
+#ifdef HAVE_LIBWRAP
+#define _LIBWRAP_FEATURE_ "+LIBWRAP"
+#else
+#define _LIBWRAP_FEATURE_ "-LIBWRAP"
+#endif
+
+#ifdef HAVE_AUDIT
+#define _AUDIT_FEATURE_ "+AUDIT"
+#else
+#define _AUDIT_FEATURE_ "-AUDIT"
+#endif
+
+#ifdef HAVE_SELINUX
+#define _SELINUX_FEATURE_ "+SELINUX"
+#else
+#define _SELINUX_FEATURE_ "-SELINUX"
+#endif
+
+#ifdef HAVE_IMA
+#define _IMA_FEATURE_ "+IMA"
+#else
+#define _IMA_FEATURE_ "-IMA"
+#endif
+
+#ifdef HAVE_SYSV_COMPAT
+#define _SYSVINIT_FEATURE_ "+SYSVINIT"
+#else
+#define _SYSVINIT_FEATURE_ "-SYSVINIT"
+#endif
+
+#ifdef HAVE_LIBCRYPTSETUP
+#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP"
+#else
+#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP"
+#endif
+
+#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_
+
+#endif
diff --git a/src/core/bus-errors.h b/src/core/bus-errors.h
new file mode 100644
index 0000000..82d4e99
--- /dev/null
+++ b/src/core/bus-errors.h
@@ -0,0 +1,58 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foobuserrorshfoo
+#define foobuserrorshfoo
+
+/***
+  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 <dbus/dbus.h>
+
+#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
+#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob"
+#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed"
+#define BUS_ERROR_INVALID_PATH "org.freedesktop.systemd1.InvalidPath"
+#define BUS_ERROR_INVALID_NAME "org.freedesktop.systemd1.InvalidName"
+#define BUS_ERROR_UNIT_TYPE_MISMATCH "org.freedesktop.systemd1.UnitTypeMismatch"
+#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists"
+#define BUS_ERROR_NOT_SUPPORTED "org.freedesktop.systemd1.NotSupported"
+#define BUS_ERROR_INVALID_JOB_MODE "org.freedesktop.systemd1.InvalidJobMode"
+#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency"
+#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation"
+#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed"
+#define BUS_ERROR_MASKED "org.freedesktop.systemd1.Masked"
+#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable"
+#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive"
+#define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting"
+#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
+#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
+#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess"
+
+static inline const char *bus_error(const DBusError *e, int r) {
+        if (e && e->message)
+                return e->message;
+
+        if (r >= 0)
+                return strerror(r);
+
+        return strerror(-r);
+}
+
+#endif
diff --git a/src/core/cgroup-attr.c b/src/core/cgroup-attr.c
new file mode 100644
index 0000000..474a686
--- /dev/null
+++ b/src/core/cgroup-attr.c
@@ -0,0 +1,102 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 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 "cgroup-attr.h"
+#include "cgroup-util.h"
+#include "list.h"
+
+int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) {
+        int r;
+        char *path = NULL;
+        char *v = NULL;
+
+        assert(a);
+
+        b = cgroup_bonding_find_list(b, a->controller);
+        if (!b)
+                return 0;
+
+        if (a->map_callback) {
+                r = a->map_callback(a->controller, a->name, a->value, &v);
+                if (r < 0)
+                        return r;
+        }
+
+        r = cg_get_path(a->controller, b->path, a->name, &path);
+        if (r < 0) {
+                free(v);
+                return r;
+        }
+
+        r = write_one_line_file(path, v ? v : a->value);
+        if (r < 0)
+                log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r));
+
+        free(path);
+        free(v);
+
+        return r;
+}
+
+int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b) {
+        CGroupAttribute *a;
+        int r = 0;
+
+        LIST_FOREACH(by_unit, a, first) {
+                int k;
+
+                k = cgroup_attribute_apply(a, b);
+                if (r == 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name) {
+        CGroupAttribute *a;
+
+        assert(controller);
+        assert(name);
+
+        LIST_FOREACH(by_unit, a, first)
+                if (streq(a->controller, controller) &&
+                    streq(a->name, name))
+                        return a;
+
+        return NULL;
+}
+
+static void cgroup_attribute_free(CGroupAttribute *a) {
+        assert(a);
+
+        free(a->controller);
+        free(a->name);
+        free(a->value);
+        free(a);
+}
+
+void cgroup_attribute_free_list(CGroupAttribute *first) {
+        CGroupAttribute *a, *n;
+
+        LIST_FOREACH_SAFE(by_unit, a, n, first)
+                cgroup_attribute_free(a);
+}
diff --git a/src/core/cgroup-attr.h b/src/core/cgroup-attr.h
new file mode 100644
index 0000000..63a73b8
--- /dev/null
+++ b/src/core/cgroup-attr.h
@@ -0,0 +1,49 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foocgroupattrhfoo
+#define foocgroupattrhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 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 CGroupAttribute CGroupAttribute;
+
+typedef int (*CGroupAttributeMapCallback)(const char *controller, const char*name, const char *value, char **ret);
+
+#include "unit.h"
+#include "cgroup.h"
+
+struct CGroupAttribute {
+        char *controller;
+        char *name;
+        char *value;
+
+        CGroupAttributeMapCallback map_callback;
+
+        LIST_FIELDS(CGroupAttribute, by_unit);
+};
+
+int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b);
+int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b);
+
+CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name);
+
+void cgroup_attribute_free_list(CGroupAttribute *first);
+
+#endif
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
new file mode 100644
index 0000000..1f6139e
--- /dev/null
+++ b/src/core/cgroup.c
@@ -0,0 +1,556 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <fcntl.h>
+
+#include "cgroup.h"
+#include "cgroup-util.h"
+#include "log.h"
+
+int cgroup_bonding_realize(CGroupBonding *b) {
+        int r;
+
+        assert(b);
+        assert(b->path);
+        assert(b->controller);
+
+        r = cg_create(b->controller, b->path);
+        if (r < 0) {
+                log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
+                return r;
+        }
+
+        b->realized = true;
+
+        return 0;
+}
+
+int cgroup_bonding_realize_list(CGroupBonding *first) {
+        CGroupBonding *b;
+        int r;
+
+        LIST_FOREACH(by_unit, b, first)
+                if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
+                        return r;
+
+        return 0;
+}
+
+void cgroup_bonding_free(CGroupBonding *b, bool trim) {
+        assert(b);
+
+        if (b->unit) {
+                CGroupBonding *f;
+
+                LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
+
+                if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                        assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
+                        LIST_REMOVE(CGroupBonding, by_path, f, b);
+
+                        if (f)
+                                hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
+                        else
+                                hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
+                }
+        }
+
+        if (b->realized && b->ours && trim)
+                cg_trim(b->controller, b->path, false);
+
+        free(b->controller);
+        free(b->path);
+        free(b);
+}
+
+void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
+        CGroupBonding *b, *n;
+
+        LIST_FOREACH_SAFE(by_unit, b, n, first)
+                cgroup_bonding_free(b, remove_or_trim);
+}
+
+void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
+        assert(b);
+
+        if (b->realized && b->ours)
+                cg_trim(b->controller, b->path, delete_root);
+}
+
+void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
+        CGroupBonding *b;
+
+        LIST_FOREACH(by_unit, b, first)
+                cgroup_bonding_trim(b, delete_root);
+}
+
+int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
+        int r;
+
+        assert(b);
+        assert(pid >= 0);
+
+        if ((r = cg_create_and_attach(b->controller, b->path, pid)) < 0)
+                return r;
+
+        b->realized = true;
+        return 0;
+}
+
+int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
+        CGroupBonding *b;
+        int r;
+
+        LIST_FOREACH(by_unit, b, first)
+                if ((r = cgroup_bonding_install(b, pid)) < 0 && b->essential)
+                        return r;
+
+        return 0;
+}
+
+int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
+        assert(b);
+
+        if (!b->realized)
+                return -EINVAL;
+
+        return cg_set_group_access(b->controller, b->path, mode, uid, gid);
+}
+
+int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
+        CGroupBonding *b;
+        int r;
+
+        LIST_FOREACH(by_unit, b, first) {
+                r = cgroup_bonding_set_group_access(b, mode, uid, gid);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
+        assert(b);
+
+        if (!b->realized)
+                return -EINVAL;
+
+        return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
+}
+
+int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
+        CGroupBonding *b;
+        int r;
+
+        LIST_FOREACH(by_unit, b, first) {
+                r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s) {
+        assert(b);
+        assert(sig >= 0);
+
+        /* Don't kill cgroups that aren't ours */
+        if (!b->ours)
+                return 0;
+
+        return cg_kill_recursive(b->controller, b->path, sig, sigcont, true, false, s);
+}
+
+int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s) {
+        CGroupBonding *b;
+        Set *allocated_set = NULL;
+        int ret = -EAGAIN, r;
+
+        if (!first)
+                return 0;
+
+        if (!s)
+                if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+        LIST_FOREACH(by_unit, b, first) {
+                if ((r = cgroup_bonding_kill(b, sig, sigcont, s)) < 0) {
+                        if (r == -EAGAIN || r == -ESRCH)
+                                continue;
+
+                        ret = r;
+                        goto finish;
+                }
+
+                if (ret < 0 || r > 0)
+                        ret = r;
+        }
+
+finish:
+        if (allocated_set)
+                set_free(allocated_set);
+
+        return ret;
+}
+
+/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
+ * cannot know */
+int cgroup_bonding_is_empty(CGroupBonding *b) {
+        int r;
+
+        assert(b);
+
+        if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
+                return r;
+
+        /* If it is empty it is empty */
+        if (r > 0)
+                return 1;
+
+        /* It's not only us using this cgroup, so we just don't know */
+        return b->ours ? 0 : -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;
+}
+
+int manager_setup_cgroup(Manager *m) {
+        char *current = NULL, *path = NULL;
+        int r;
+        char suffix[32];
+
+        assert(m);
+
+        /* 0. Be nice to Ingo Molnar #628004 */
+        if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
+                log_warning("No control group support available, not creating root group.");
+                return 0;
+        }
+
+        /* 1. Determine hierarchy */
+        if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current)) < 0) {
+                log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
+                goto finish;
+        }
+
+        if (m->running_as == MANAGER_SYSTEM)
+                strcpy(suffix, "/system");
+        else {
+                snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
+                char_array_0(suffix);
+        }
+
+        free(m->cgroup_hierarchy);
+        if (endswith(current, suffix)) {
+                /* We probably got reexecuted and can continue to use our root cgroup */
+                m->cgroup_hierarchy = current;
+                current = NULL;
+
+        } else {
+                /* We need a new root cgroup */
+                m->cgroup_hierarchy = NULL;
+                if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
+                        log_error("Out of memory");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+        }
+
+        /* 2. Show data */
+        if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
+                log_error("Cannot find cgroup mount point: %s", strerror(-r));
+                goto finish;
+        }
+
+        log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
+
+        /* 3. Install agent */
+        if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
+                log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
+        else if (r > 0)
+                log_debug("Installed release agent.");
+        else
+                log_debug("Release agent already installed.");
+
+        /* 4. Realize the group */
+        if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
+                log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
+                goto finish;
+        }
+
+        /* 5. And pin it, so that it cannot be unmounted */
+        if (m->pin_cgroupfs_fd >= 0)
+                close_nointr_nofail(m->pin_cgroupfs_fd);
+
+        if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
+                log_error("Failed to open pin file: %m");
+                r = -errno;
+                goto finish;
+        }
+
+        log_debug("Created root group.");
+
+finish:
+        free(current);
+        free(path);
+
+        return r;
+}
+
+void manager_shutdown_cgroup(Manager *m, bool delete) {
+        assert(m);
+
+        if (delete && m->cgroup_hierarchy)
+                cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
+
+        if (m->pin_cgroupfs_fd >= 0) {
+                close_nointr_nofail(m->pin_cgroupfs_fd);
+                m->pin_cgroupfs_fd = -1;
+        }
+
+        free(m->cgroup_hierarchy);
+        m->cgroup_hierarchy = NULL;
+}
+
+int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
+        CGroupBonding *b;
+        char *p;
+
+        assert(m);
+        assert(cgroup);
+        assert(bonding);
+
+        b = hashmap_get(m->cgroup_bondings, cgroup);
+        if (b) {
+                *bonding = b;
+                return 1;
+        }
+
+        p = strdup(cgroup);
+        if (!p)
+                return -ENOMEM;
+
+        for (;;) {
+                char *e;
+
+                e = strrchr(p, '/');
+                if (!e || e == p) {
+                        free(p);
+                        *bonding = NULL;
+                        return 0;
+                }
+
+                *e = 0;
+
+                b = hashmap_get(m->cgroup_bondings, p);
+                if (b) {
+                        free(p);
+                        *bonding = b;
+                        return 1;
+                }
+        }
+}
+
+int cgroup_notify_empty(Manager *m, const char *group) {
+        CGroupBonding *l, *b;
+        int r;
+
+        assert(m);
+        assert(group);
+
+        r = cgroup_bonding_get(m, group, &l);
+        if (r <= 0)
+                return r;
+
+        LIST_FOREACH(by_path, b, l) {
+                int t;
+
+                if (!b->unit)
+                        continue;
+
+                t = cgroup_bonding_is_empty_list(b);
+                if (t < 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 it is empty, let's delete it */
+                        cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
+
+                        if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
+                                UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
+                }
+        }
+
+        return 0;
+}
+
+Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
+        CGroupBonding *l, *b;
+        char *group = NULL;
+
+        assert(m);
+
+        if (pid <= 1)
+                return NULL;
+
+        if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
+                return NULL;
+
+        l = hashmap_get(m->cgroup_bondings, group);
+
+        if (!l) {
+                char *slash;
+
+                while ((slash = strrchr(group, '/'))) {
+                        if (slash == group)
+                                break;
+
+                        *slash = 0;
+
+                        if ((l = hashmap_get(m->cgroup_bondings, group)))
+                                break;
+                }
+        }
+
+        free(group);
+
+        LIST_FOREACH(by_path, b, l) {
+
+                if (!b->unit)
+                        continue;
+
+                if (b->ours)
+                        return b->unit;
+        }
+
+        return NULL;
+}
+
+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;
+}
+
+pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
+        FILE *f;
+        pid_t pid = 0, npid, mypid;
+
+        assert(b);
+
+        if (!b->ours)
+                return 0;
+
+        if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
+                return 0;
+
+        mypid = getpid();
+
+        while (cg_read_pid(f, &npid) > 0)  {
+                pid_t ppid;
+
+                if (npid == pid)
+                        continue;
+
+                /* Ignore processes that aren't our kids */
+                if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+                        continue;
+
+                if (pid != 0) {
+                        /* Dang, there's more than one daemonized PID
+                        in this group, so we don't know what process
+                        is the main process. */
+                        pid = 0;
+                        break;
+                }
+
+                pid = npid;
+        }
+
+        fclose(f);
+
+        return pid;
+}
+
+pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
+        CGroupBonding *b;
+        pid_t pid;
+
+        /* Try to find a main pid from this cgroup, but checking if
+         * there's only one PID in the cgroup and returning it. Later
+         * on we might want to add additional, smarter heuristics
+         * here. */
+
+        LIST_FOREACH(by_unit, b, first)
+                if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
+                        return pid;
+
+        return 0;
+
+}
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
new file mode 100644
index 0000000..5faa7dc
--- /dev/null
+++ b/src/core/cgroup.h
@@ -0,0 +1,94 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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/>.
+***/
+
+typedef struct CGroupBonding CGroupBonding;
+
+#include "unit.h"
+
+/* Binds a cgroup to a name */
+struct CGroupBonding {
+        char *controller;
+        char *path;
+
+        Unit *unit;
+
+        /* 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? Are our own tasks the
+         * only ones in this group?*/
+        bool ours:1;
+
+        /* If we cannot create this group, or add a process to it, is this fatal? */
+        bool essential:1;
+
+        /* This cgroup is realized */
+        bool realized:1;
+};
+
+int cgroup_bonding_realize(CGroupBonding *b);
+int cgroup_bonding_realize_list(CGroupBonding *first);
+
+void cgroup_bonding_free(CGroupBonding *b, bool trim);
+void cgroup_bonding_free_list(CGroupBonding *first, bool trim);
+
+int cgroup_bonding_install(CGroupBonding *b, pid_t pid);
+int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid);
+
+int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
+int cgroup_bonding_set_group_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
+
+int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
+int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
+
+int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s);
+int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s);
+
+void cgroup_bonding_trim(CGroupBonding *first, bool delete_root);
+void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root);
+
+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);
+
+pid_t cgroup_bonding_search_main_pid(CGroupBonding *b);
+pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b);
+
+#include "manager.h"
+
+int manager_setup_cgroup(Manager *m);
+void manager_shutdown_cgroup(Manager *m, bool delete);
+
+int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding);
+int cgroup_notify_empty(Manager *m, const char *group);
+
+Unit* cgroup_unit_by_pid(Manager *m, pid_t pid);
+
+#endif
diff --git a/src/core/condition.c b/src/core/condition.c
new file mode 100644
index 0000000..2b51a16
--- /dev/null
+++ b/src/core/condition.c
@@ -0,0 +1,323 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/capability.h>
+
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include "util.h"
+#include "condition.h"
+#include "virt.h"
+
+Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
+        Condition *c;
+
+        assert(type < _CONDITION_TYPE_MAX);
+
+        c = new0(Condition, 1);
+        if (!c)
+                return NULL;
+
+        c->type = type;
+        c->trigger = trigger;
+        c->negate = negate;
+
+        if (parameter) {
+                c->parameter = strdup(parameter);
+                if (!c->parameter) {
+                        free(c);
+                        return NULL;
+                }
+        }
+
+        return c;
+}
+
+void condition_free(Condition *c) {
+        assert(c);
+
+        free(c->parameter);
+        free(c);
+}
+
+void condition_free_list(Condition *first) {
+        Condition *c, *n;
+
+        LIST_FOREACH_SAFE(conditions, c, n, first)
+                condition_free(c);
+}
+
+static bool test_kernel_command_line(const char *parameter) {
+        char *line, *w, *state, *word = NULL;
+        bool equal;
+        int r;
+        size_t l, pl;
+        bool found = false;
+
+        assert(parameter);
+
+        if (detect_container(NULL) > 0)
+                return false;
+
+        r = read_one_line_file("/proc/cmdline", &line);
+        if (r < 0) {
+                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
+                return false;
+        }
+
+        equal = !!strchr(parameter, '=');
+        pl = strlen(parameter);
+
+        FOREACH_WORD_QUOTED(w, l, line, state) {
+
+                free(word);
+                word = strndup(w, l);
+                if (!word)
+                        break;
+
+                if (equal) {
+                        if (streq(word, parameter)) {
+                                found = true;
+                                break;
+                        }
+                } else {
+                        if (startswith(word, parameter) && (word[pl] == '=' || word[pl] == 0)) {
+                                found = true;
+                                break;
+                        }
+                }
+
+        }
+
+        free(word);
+        free(line);
+
+        return found;
+}
+
+static bool test_virtualization(const char *parameter) {
+        int b;
+        Virtualization v;
+        const char *id;
+
+        assert(parameter);
+
+        v = detect_virtualization(&id);
+        if (v < 0) {
+                log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
+                return false;
+        }
+
+        /* First, compare with yes/no */
+        b = parse_boolean(parameter);
+
+        if (v > 0 && b > 0)
+                return true;
+
+        if (v == 0 && b == 0)
+                return true;
+
+        /* Then, compare categorization */
+        if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
+                return true;
+
+        if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
+                return true;
+
+        /* Finally compare id */
+        return v > 0 && streq(parameter, id);
+}
+
+static bool test_security(const char *parameter) {
+#ifdef HAVE_SELINUX
+        if (streq(parameter, "selinux"))
+                return is_selinux_enabled() > 0;
+#endif
+        return false;
+}
+
+static bool test_capability(const char *parameter) {
+        cap_value_t value;
+        FILE *f;
+        char line[LINE_MAX];
+        unsigned long long capabilities = (unsigned long long) -1;
+
+        /* If it's an invalid capability, we don't have it */
+
+        if (cap_from_name(parameter, &value) < 0)
+                return false;
+
+        /* If it's a valid capability we default to assume
+         * that we have it */
+
+        f = fopen("/proc/self/status", "re");
+        if (!f)
+                return true;
+
+        while (fgets(line, sizeof(line), f)) {
+                truncate_nl(line);
+
+                if (startswith(line, "CapBnd:")) {
+                        (void) sscanf(line+7, "%llx", &capabilities);
+                        break;
+                }
+        }
+
+        fclose(f);
+
+        return !!(capabilities & (1ULL << value));
+}
+
+bool condition_test(Condition *c) {
+        assert(c);
+
+        switch(c->type) {
+
+        case CONDITION_PATH_EXISTS:
+                return (access(c->parameter, F_OK) >= 0) == !c->negate;
+
+        case CONDITION_PATH_EXISTS_GLOB:
+                return (glob_exists(c->parameter) > 0) == !c->negate;
+
+        case CONDITION_PATH_IS_DIRECTORY: {
+                struct stat st;
+
+                if (stat(c->parameter, &st) < 0)
+                        return c->negate;
+                return S_ISDIR(st.st_mode) == !c->negate;
+        }
+
+        case CONDITION_PATH_IS_SYMBOLIC_LINK: {
+                struct stat st;
+
+                if (lstat(c->parameter, &st) < 0)
+                        return c->negate;
+                return S_ISLNK(st.st_mode) == !c->negate;
+        }
+
+        case CONDITION_PATH_IS_MOUNT_POINT:
+                return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
+
+        case CONDITION_DIRECTORY_NOT_EMPTY: {
+                int k;
+
+                k = dir_is_empty(c->parameter);
+                return !(k == -ENOENT || k > 0) == !c->negate;
+        }
+
+        case CONDITION_FILE_IS_EXECUTABLE: {
+                struct stat st;
+
+                if (stat(c->parameter, &st) < 0)
+                        return c->negate;
+
+                return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
+        }
+
+        case CONDITION_KERNEL_COMMAND_LINE:
+                return test_kernel_command_line(c->parameter) == !c->negate;
+
+        case CONDITION_VIRTUALIZATION:
+                return test_virtualization(c->parameter) == !c->negate;
+
+        case CONDITION_SECURITY:
+                return test_security(c->parameter) == !c->negate;
+
+        case CONDITION_CAPABILITY:
+                return test_capability(c->parameter) == !c->negate;
+
+        case CONDITION_NULL:
+                return !c->negate;
+
+        default:
+                assert_not_reached("Invalid condition type.");
+        }
+}
+
+bool condition_test_list(Condition *first) {
+        Condition *c;
+        int triggered = -1;
+
+        /* If the condition list is empty, then it is true */
+        if (!first)
+                return true;
+
+        /* Otherwise, if all of the non-trigger conditions apply and
+         * if any of the trigger conditions apply (unless there are
+         * none) we return true */
+        LIST_FOREACH(conditions, c, first) {
+                bool b;
+
+                b = condition_test(c);
+
+                if (!c->trigger && !b)
+                        return false;
+
+                if (c->trigger && triggered <= 0)
+                        triggered = b;
+        }
+
+        return triggered != 0;
+}
+
+void condition_dump(Condition *c, FILE *f, const char *prefix) {
+        assert(c);
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        fprintf(f,
+                "%s\t%s: %s%s%s\n",
+                prefix,
+                condition_type_to_string(c->type),
+                c->trigger ? "|" : "",
+                c->negate ? "!" : "",
+                c->parameter);
+}
+
+void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
+        Condition *c;
+
+        LIST_FOREACH(conditions, c, first)
+                condition_dump(c, f, prefix);
+}
+
+static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
+        [CONDITION_PATH_EXISTS] = "ConditionPathExists",
+        [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
+        [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
+        [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
+        [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
+        [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
+        [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
+        [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
+        [CONDITION_SECURITY] = "ConditionSecurity",
+        [CONDITION_NULL] = "ConditionNull"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
diff --git a/src/core/condition.h b/src/core/condition.h
new file mode 100644
index 0000000..71b1c67
--- /dev/null
+++ b/src/core/condition.h
@@ -0,0 +1,69 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooconditionhfoo
+#define fooconditionhfoo
+
+/***
+  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 "list.h"
+
+typedef enum ConditionType {
+        CONDITION_PATH_EXISTS,
+        CONDITION_PATH_EXISTS_GLOB,
+        CONDITION_PATH_IS_DIRECTORY,
+        CONDITION_PATH_IS_SYMBOLIC_LINK,
+        CONDITION_PATH_IS_MOUNT_POINT,
+        CONDITION_DIRECTORY_NOT_EMPTY,
+        CONDITION_FILE_IS_EXECUTABLE,
+        CONDITION_KERNEL_COMMAND_LINE,
+        CONDITION_VIRTUALIZATION,
+        CONDITION_SECURITY,
+        CONDITION_CAPABILITY,
+        CONDITION_NULL,
+        _CONDITION_TYPE_MAX,
+        _CONDITION_TYPE_INVALID = -1
+} ConditionType;
+
+typedef struct Condition {
+        ConditionType type;
+        char *parameter;
+
+        bool trigger:1;
+        bool negate:1;
+
+        LIST_FIELDS(struct Condition, conditions);
+} Condition;
+
+Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate);
+void condition_free(Condition *c);
+void condition_free_list(Condition *c);
+
+bool condition_test(Condition *c);
+bool condition_test_list(Condition *c);
+
+void condition_dump(Condition *c, FILE *f, const char *prefix);
+void condition_dump_list(Condition *c, FILE *f, const char *prefix);
+
+const char* condition_type_to_string(ConditionType t);
+int condition_type_from_string(const char *s);
+
+#endif
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
new file mode 100644
index 0000000..8e45f81
--- /dev/null
+++ b/src/core/dbus-automount.c
@@ -0,0 +1,72 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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-automount.h"
+#include "dbus-common.h"
+
+#define BUS_AUTOMOUNT_INTERFACE                                      \
+        " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \
+        "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"  \
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        " </interface>\n"
+
+#define INTROSPECTION                                                \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                    \
+        "<node>\n"                                                   \
+        BUS_UNIT_INTERFACE                                           \
+        BUS_AUTOMOUNT_INTERFACE                                      \
+        BUS_PROPERTIES_INTERFACE                                     \
+        BUS_PEER_INTERFACE                                           \
+        BUS_INTROSPECTABLE_INTERFACE                                 \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Automount\0"
+
+const char bus_automount_interface[] _introspect_("Automount") = BUS_AUTOMOUNT_INTERFACE;
+
+const char bus_automount_invalidating_properties[] =
+        "Result\0";
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_automount_append_automount_result, automount_result, AutomountResult);
+
+static const BusProperty bus_automount_properties[] = {
+        { "Where",         bus_property_append_string, "s", offsetof(Automount, where),    true },
+        { "DirectoryMode", bus_property_append_mode,   "u", offsetof(Automount, directory_mode) },
+        { "Result",        bus_automount_append_automount_result, "s", offsetof(Automount, result) },
+        { NULL, }
+};
+
+DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Automount *am = AUTOMOUNT(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",      bus_unit_properties,      u  },
+                { "org.freedesktop.systemd1.Automount", bus_automount_properties, am },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
new file mode 100644
index 0000000..2fc8345
--- /dev/null
+++ b/src/core/dbus-automount.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_automount_interface[];
+extern const char bus_automount_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
new file mode 100644
index 0000000..b39fb9d
--- /dev/null
+++ b/src/core/dbus-device.c
@@ -0,0 +1,65 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "dbus-common.h"
+
+#define BUS_DEVICE_INTERFACE                                            \
+        " <interface name=\"org.freedesktop.systemd1.Device\">\n"       \
+        "  <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>\n" \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_DEVICE_INTERFACE                                            \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Device\0"
+
+const char bus_device_interface[] _introspect_("Device") = BUS_DEVICE_INTERFACE;
+
+const char bus_device_invalidating_properties[] =
+        "SysFSPath\0";
+
+static const BusProperty bus_device_properties[] = {
+        { "SysFSPath", bus_property_append_string, "s", offsetof(Device, sysfs), true },
+        { NULL, }
+};
+
+
+DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Device *d = DEVICE(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",   bus_unit_properties,   u },
+                { "org.freedesktop.systemd1.Device", bus_device_properties, d },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h
new file mode 100644
index 0000000..fba270b
--- /dev/null
+++ b/src/core/dbus-device.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_device_interface[];
+extern const char bus_device_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
new file mode 100644
index 0000000..1fd2b21
--- /dev/null
+++ b/src/core/dbus-execute.c
@@ -0,0 +1,422 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <sys/prctl.h>
+
+#include "dbus-execute.h"
+#include "missing.h"
+#include "ioprio.h"
+#include "strv.h"
+#include "dbus-common.h"
+
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode);
+
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
+DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
+
+int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
+        char **env_files = data, **j;
+        DBusMessageIter sub, sub2;
+
+        assert(i);
+        assert(property);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
+                return -ENOMEM;
+
+        STRV_FOREACH(j, env_files) {
+                dbus_bool_t b = false;
+                char *fn = *j;
+
+                if (fn[0] == '-') {
+                        b = true;
+                        fn++;
+                }
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->oom_score_adjust_set)
+                n = c->oom_score_adjust;
+        else {
+                char *t;
+
+                n = 0;
+                if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
+                        safe_atoi(t, &n);
+                        free(t);
+                } else if (read_one_line_file("/proc/self/oom_adj", &t) >= 0) {
+                        safe_atoi(t, &n);
+                        free(t);
+
+                        if (n == OOM_ADJUST_MAX)
+                                n = OOM_SCORE_ADJ_MAX;
+                        else
+                                n = (n * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
+                }
+        }
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->nice_set)
+                n = c->nice;
+        else
+                n = getpriority(PRIO_PROCESS, 0);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->ioprio_set)
+                n = c->ioprio;
+        else
+                n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->cpu_sched_set)
+                n = c->cpu_sched_policy;
+        else
+                n = sched_getscheduler(0);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->cpu_sched_set)
+                n = c->cpu_sched_priority;
+        else {
+                struct sched_param p;
+                n = 0;
+
+                zero(p);
+                if (sched_getparam(0, &p) >= 0)
+                        n = p.sched_priority;
+        }
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        dbus_bool_t b;
+        DBusMessageIter sub;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
+                return -ENOMEM;
+
+        if (c->cpuset)
+                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
+        else
+                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
+
+        if (!b)
+                return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        uint64_t u;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->timer_slack_nsec_set)
+                u = (uint64_t) c->timer_slack_nsec;
+        else
+                u = (uint64_t) prctl(PR_GET_TIMERSLACK);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        uint64_t normal, inverted;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        /* We store this negated internally, to match the kernel, but
+         * we expose it normalized. */
+
+        normal = *(uint64_t*) data;
+        inverted = ~normal;
+
+        return bus_property_append_uint64(i, property, &inverted);
+}
+
+int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        char *t = NULL;
+        const char *s;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->capabilities)
+                s = t = cap_to_text(c->capabilities, NULL);
+        else
+                s = "";
+
+        if (!s)
+                return -ENOMEM;
+
+        b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
+
+        if (t)
+                cap_free(t);
+
+        if (!b)
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int r;
+        uint64_t u;
+
+        assert(i);
+        assert(property);
+        assert(c);
+
+        assert_se((r = rlimit_from_string(property)) >= 0);
+
+        if (c->rlimit[r])
+                u = (uint64_t) c->rlimit[r]->rlim_max;
+        else {
+                struct rlimit rl;
+
+                zero(rl);
+                getrlimit(r, &rl);
+
+                u = (uint64_t) rl.rlim_max;
+        }
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
+        ExecCommand *c = data;
+        DBusMessageIter sub, sub2, sub3;
+
+        assert(i);
+        assert(property);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(command, c, c) {
+                char **l;
+                uint32_t pid;
+                int32_t code, status;
+                dbus_bool_t b;
+
+                if (!c->path)
+                        continue;
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
+                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
+                        return -ENOMEM;
+
+                STRV_FOREACH(l, c->argv)
+                        if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
+                                return -ENOMEM;
+
+                pid = (uint32_t) c->exec_status.pid;
+                code = (int32_t) c->exec_status.code;
+                status = (int32_t) c->exec_status.status;
+
+                b = !!c->ignore;
+
+                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+const BusProperty bus_exec_context_properties[] = {
+        { "Environment",              bus_property_append_strv,             "as", offsetof(ExecContext, environment),            true },
+        { "EnvironmentFiles",         bus_execute_append_env_files,      "a(sb)", offsetof(ExecContext, environment_files),      true },
+        { "UMask",                    bus_property_append_mode,              "u", offsetof(ExecContext, umask)                        },
+        { "LimitCPU",                 bus_execute_append_rlimits,            "t", 0 },
+        { "LimitFSIZE",               bus_execute_append_rlimits,            "t", 0 },
+        { "LimitDATA",                bus_execute_append_rlimits,            "t", 0 },
+        { "LimitSTACK",               bus_execute_append_rlimits,            "t", 0 },
+        { "LimitCORE",                bus_execute_append_rlimits,            "t", 0 },
+        { "LimitRSS",                 bus_execute_append_rlimits,            "t", 0 },
+        { "LimitNOFILE",              bus_execute_append_rlimits,            "t", 0 },
+        { "LimitAS",                  bus_execute_append_rlimits,            "t", 0 },
+        { "LimitNPROC",               bus_execute_append_rlimits,            "t", 0 },
+        { "LimitMEMLOCK",             bus_execute_append_rlimits,            "t", 0 },
+        { "LimitLOCKS",               bus_execute_append_rlimits,            "t", 0 },
+        { "LimitSIGPENDING",          bus_execute_append_rlimits,            "t", 0 },
+        { "LimitMSGQUEUE",            bus_execute_append_rlimits,            "t", 0 },
+        { "LimitNICE",                bus_execute_append_rlimits,            "t", 0 },
+        { "LimitRTPRIO",              bus_execute_append_rlimits,            "t", 0 },
+        { "LimitRTTIME",              bus_execute_append_rlimits,            "t", 0 },
+        { "WorkingDirectory",         bus_property_append_string,            "s", offsetof(ExecContext, working_directory),      true },
+        { "RootDirectory",            bus_property_append_string,            "s", offsetof(ExecContext, root_directory),         true },
+        { "OOMScoreAdjust",           bus_execute_append_oom_score_adjust,   "i", 0 },
+        { "Nice",                     bus_execute_append_nice,               "i", 0 },
+        { "IOScheduling",             bus_execute_append_ioprio,             "i", 0 },
+        { "CPUSchedulingPolicy",      bus_execute_append_cpu_sched_policy,   "i", 0 },
+        { "CPUSchedulingPriority",    bus_execute_append_cpu_sched_priority, "i", 0 },
+        { "CPUAffinity",              bus_execute_append_affinity,          "ay", 0 },
+        { "TimerSlackNSec",           bus_execute_append_timer_slack_nsec,   "t", 0 },
+        { "CPUSchedulingResetOnFork", bus_property_append_bool,              "b", offsetof(ExecContext, cpu_sched_reset_on_fork)      },
+        { "NonBlocking",              bus_property_append_bool,              "b", offsetof(ExecContext, non_blocking)                 },
+        { "StandardInput",            bus_execute_append_input,              "s", offsetof(ExecContext, std_input)                    },
+        { "StandardOutput",           bus_execute_append_output,             "s", offsetof(ExecContext, std_output)                   },
+        { "StandardError",            bus_execute_append_output,             "s", offsetof(ExecContext, std_error)                    },
+        { "TTYPath",                  bus_property_append_string,            "s", offsetof(ExecContext, tty_path),               true },
+        { "TTYReset",                 bus_property_append_bool,              "b", offsetof(ExecContext, tty_reset)                    },
+        { "TTYVHangup",               bus_property_append_bool,              "b", offsetof(ExecContext, tty_vhangup)                  },
+        { "TTYVTDisallocate",         bus_property_append_bool,              "b", offsetof(ExecContext, tty_vt_disallocate)           },
+        { "SyslogPriority",           bus_property_append_int,               "i", offsetof(ExecContext, syslog_priority)              },
+        { "SyslogIdentifier",         bus_property_append_string,            "s", offsetof(ExecContext, syslog_identifier),      true },
+        { "SyslogLevelPrefix",        bus_property_append_bool,              "b", offsetof(ExecContext, syslog_level_prefix)          },
+        { "Capabilities",             bus_execute_append_capabilities,       "s", 0 },
+        { "SecureBits",               bus_property_append_int,               "i", offsetof(ExecContext, secure_bits)                  },
+        { "CapabilityBoundingSet",    bus_execute_append_capability_bs,      "t", offsetof(ExecContext, capability_bounding_set_drop) },
+        { "User",                     bus_property_append_string,            "s", offsetof(ExecContext, user),                   true },
+        { "Group",                    bus_property_append_string,            "s", offsetof(ExecContext, group),                  true },
+        { "SupplementaryGroups",      bus_property_append_strv,             "as", offsetof(ExecContext, supplementary_groups),   true },
+        { "TCPWrapName",              bus_property_append_string,            "s", offsetof(ExecContext, tcpwrap_name),           true },
+        { "PAMName",                  bus_property_append_string,            "s", offsetof(ExecContext, pam_name),               true },
+        { "ReadWriteDirectories",     bus_property_append_strv,             "as", offsetof(ExecContext, read_write_dirs),        true },
+        { "ReadOnlyDirectories",      bus_property_append_strv,             "as", offsetof(ExecContext, read_only_dirs),         true },
+        { "InaccessibleDirectories",  bus_property_append_strv,             "as", offsetof(ExecContext, inaccessible_dirs),      true },
+        { "MountFlags",               bus_property_append_ul,                "t", offsetof(ExecContext, mount_flags)                  },
+        { "PrivateTmp",               bus_property_append_bool,              "b", offsetof(ExecContext, private_tmp)                  },
+        { "PrivateNetwork",           bus_property_append_bool,              "b", offsetof(ExecContext, private_network)              },
+        { "SameProcessGroup",         bus_property_append_bool,              "b", offsetof(ExecContext, same_pgrp)                    },
+        { "KillMode",                 bus_execute_append_kill_mode,          "s", offsetof(ExecContext, kill_mode)                    },
+        { "KillSignal",               bus_property_append_int,               "i", offsetof(ExecContext, kill_signal)                  },
+        { "UtmpIdentifier",           bus_property_append_string,            "s", offsetof(ExecContext, utmp_id),                true },
+        { "ControlGroupModify",       bus_property_append_bool,              "b", offsetof(ExecContext, control_group_modify)         },
+        { "ControlGroupPersistent",   bus_property_append_tristate_false,    "b", offsetof(ExecContext, control_group_persistent)     },
+        { "IgnoreSIGPIPE",            bus_property_append_bool,              "b", offsetof(ExecContext, ignore_sigpipe          )     },
+        { NULL, }
+};
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
new file mode 100644
index 0000000..03cd69d
--- /dev/null
+++ b/src/core/dbus-execute.h
@@ -0,0 +1,125 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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"
+#include "dbus-common.h"
+
+#define BUS_EXEC_STATUS_INTERFACE(prefix)                               \
+        "  <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "StartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "ExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n"
+
+#define BUS_EXEC_CONTEXT_INTERFACE                                      \
+        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"UMask\" type=\"u\" access=\"read\"/>\n"     \
+        "  <property name=\"LimitCPU\" type=\"t\" access=\"read\"/>\n"  \
+        "  <property name=\"LimitFSIZE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitDATA\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitSTACK\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitCORE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitRSS\" type=\"t\" access=\"read\"/>\n"  \
+        "  <property name=\"LimitNOFILE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitAS\" type=\"t\" access=\"read\"/>\n"   \
+        "  <property name=\"LimitNPROC\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitMEMLOCK\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitLOCKS\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitSIGPENDING\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitMSGQUEUE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitNICE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitRTPRIO\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitRTTIME\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"OOMScoreAdjust\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"Nice\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"IOScheduling\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CPUSchedulingPolicy\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CPUSchedulingPriority\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CPUAffinity\" type=\"ay\" access=\"read\"/>\n" \
+        "  <property name=\"TimerSlackNS\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"StandardInput\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"StandardError\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"TTYReset\" type=\"b\" access=\"read\"/>\n"   \
+        "  <property name=\"TTYVHangup\" type=\"b\" access=\"read\"/>\n"   \
+        "  <property name=\"TTYVTDisallocate\" type=\"b\" access=\"read\"/>\n"   \
+        "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"SyslogLevelPrefix\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CapabilityBoundingSet\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"User\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Group\" type=\"s\" access=\"read\"/>\n"     \
+        "  <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"TCPWrapName\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"ReadWriteDirectories\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ReadOnlyDirectories\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
+        "  <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"ControlGroupModify\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"ControlGroupPersistent\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"PrivateNetwork\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"IgnoreSIGPIPE\" type=\"b\" access=\"read\"/>\n"
+
+#define BUS_EXEC_COMMAND_INTERFACE(name)                             \
+        "  <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
+
+extern const BusProperty bus_exec_context_properties[];
+
+#define BUS_EXEC_COMMAND_PROPERTY(name, command, indirect)             \
+        { name, bus_execute_append_command, "a(sasbttttuii)", (command), (indirect), NULL }
+
+int bus_execute_append_output(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_input(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data);
+int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data);
+
+#endif
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
new file mode 100644
index 0000000..ab6d610
--- /dev/null
+++ b/src/core/dbus-job.c
@@ -0,0 +1,354 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "dbus-common.h"
+
+#define BUS_JOB_INTERFACE                                             \
+        " <interface name=\"org.freedesktop.systemd1.Job\">\n"        \
+        "  <method name=\"Cancel\"/>\n"                               \
+        "  <property name=\"Id\" type=\"u\" access=\"read\"/>\n"      \
+        "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>\n" \
+        "  <property name=\"JobType\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"   \
+        " </interface>\n"
+
+#define INTROSPECTION                                                 \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                     \
+        "<node>\n"                                                    \
+        BUS_JOB_INTERFACE                                             \
+        BUS_PROPERTIES_INTERFACE                                      \
+        BUS_PEER_INTERFACE                                            \
+        BUS_INTROSPECTABLE_INTERFACE                                  \
+        "</node>\n"
+
+const char bus_job_interface[] _introspect_("Job") = BUS_JOB_INTERFACE;
+
+#define INTERFACES_LIST                              \
+        BUS_GENERIC_INTERFACES_LIST                  \
+        "org.freedesktop.systemd1.Job\0"
+
+#define INVALIDATING_PROPERTIES                 \
+        "State\0"
+
+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(DBusMessageIter *i, const char *property, void *data) {
+        Job *j = data;
+        DBusMessageIter sub;
+        char *p;
+
+        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->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 const BusProperty bus_job_properties[] = {
+        { "Id",      bus_property_append_uint32, "u", offsetof(Job, id)    },
+        { "State",   bus_job_append_state,       "s", offsetof(Job, state) },
+        { "JobType", bus_job_append_type,        "s", offsetof(Job, type)  },
+        { "Unit",    bus_job_append_unit,     "(so)", 0 },
+        { NULL, }
+};
+
+static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connection, DBusMessage *message) {
+        DBusMessage *reply = NULL;
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                job_finish_and_invalidate(j, JOB_CANCELED);
+
+        } else {
+                const BusBoundProperties bps[] = {
+                        { "org.freedesktop.systemd1.Job", bus_job_properties, j },
+                        { NULL, }
+                };
+                return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
+        }
+
+        if (reply) {
+                if (!dbus_connection_send(connection, 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;
+        DBusMessage *reply;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) {
+                /* Be nice to gdbus and return introspection data for our mid-level paths */
+
+                if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+                        char *introspection = NULL;
+                        FILE *f;
+                        Iterator i;
+                        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(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+                              "<node>\n", f);
+
+                        fputs(BUS_INTROSPECTABLE_INTERFACE, f);
+                        fputs(BUS_PEER_INTERFACE, f);
+
+                        HASHMAP_FOREACH(j, m->jobs, i)
+                                fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
+
+                        fputs("</node>\n", 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);
+
+                        if (!dbus_connection_send(connection, reply, NULL))
+                                goto oom;
+
+                        dbus_message_unref(reply);
+
+                        return DBUS_HANDLER_RESULT_HANDLED;
+                }
+
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+
+        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) {
+                        DBusError e;
+
+                        dbus_error_init(&e);
+                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job");
+                        return bus_send_error_reply(connection, message, &e, r);
+                }
+
+                return bus_send_error_reply(connection, message, NULL, r);
+        }
+
+        return bus_job_message_dispatch(j, connection, message);
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+const DBusObjectPathVTable bus_job_vtable = {
+        .message_function = bus_job_message_handler
+};
+
+static int job_send_message(Job *j, DBusMessage *m) {
+        int r;
+
+        assert(j);
+        assert(m);
+
+        if (bus_has_subscriber(j->manager)) {
+                if ((r = bus_broadcast(j->manager, m)) < 0)
+                        return r;
+
+        } else  if (j->bus_client) {
+                /* If nobody is subscribed, we just send the message
+                 * to the client which created the job */
+
+                assert(j->bus);
+
+                if (!dbus_message_set_destination(m, j->bus_client))
+                        return -ENOMEM;
+
+                if (!dbus_connection_send(j->bus, m, NULL))
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
+void bus_job_send_change_signal(Job *j) {
+        char *p = NULL;
+        DBusMessage *m = NULL;
+
+        assert(j);
+
+        if (j->in_dbus_queue) {
+                LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
+                j->in_dbus_queue = false;
+        }
+
+        if (!bus_has_subscriber(j->manager) && !j->bus_client) {
+                j->sent_dbus_new_signal = true;
+                return;
+        }
+
+        if (!(p = job_dbus_path(j)))
+                goto oom;
+
+        if (j->sent_dbus_new_signal) {
+                /* Send a properties changed signal */
+
+                if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES)))
+                        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 (job_send_message(j, m) < 0)
+                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;
+        const char *r;
+
+        assert(j);
+
+        if (!bus_has_subscriber(j->manager) && !j->bus_client)
+                return;
+
+        if (!j->sent_dbus_new_signal)
+                bus_job_send_change_signal(j);
+
+        if (!(p = job_dbus_path(j)))
+                goto oom;
+
+        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved")))
+                goto oom;
+
+        r = job_result_to_string(j->result);
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_UINT32, &j->id,
+                                      DBUS_TYPE_OBJECT_PATH, &p,
+                                      DBUS_TYPE_STRING, &r,
+                                      DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (job_send_message(j, m) < 0)
+                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/core/dbus-job.h b/src/core/dbus-job.h
new file mode 100644
index 0000000..103c2ff
--- /dev/null
+++ b/src/core/dbus-job.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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>
+
+#include "job.h"
+
+void bus_job_send_change_signal(Job *j);
+void bus_job_send_removed_signal(Job *j);
+
+extern const DBusObjectPathVTable bus_job_vtable;
+
+extern const char bus_job_interface[];
+
+#endif
diff --git a/src/core/dbus-loop.h b/src/core/dbus-loop.h
new file mode 100644
index 0000000..0bbdfe5
--- /dev/null
+++ b/src/core/dbus-loop.h
@@ -0,0 +1,30 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foodbusloophfoo
+#define foodbusloophfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 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>
+
+int bus_loop_open(DBusConnection *c);
+int bus_loop_dispatch(int fd);
+
+#endif
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
new file mode 100644
index 0000000..3bf0c07
--- /dev/null
+++ b/src/core/dbus-manager.c
@@ -0,0 +1,1544 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <unistd.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "dbus-manager.h"
+#include "strv.h"
+#include "bus-errors.h"
+#include "build.h"
+#include "dbus-common.h"
+#include "install.h"
+
+#define BUS_MANAGER_INTERFACE_BEGIN                                     \
+        " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
+
+#define BUS_MANAGER_INTERFACE_METHODS                                   \
+        "  <method name=\"GetUnit\">\n"                                 \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetUnitByPID\">\n"                            \
+        "   <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n"          \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <method name=\"LoadUnit\">\n"                                \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <method name=\"StartUnit\">\n"                               \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"StartUnitReplace\">\n"                        \
+        "   <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n"     \
+        "   <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n"     \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"StopUnit\">\n"                                \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ReloadUnit\">\n"                              \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"RestartUnit\">\n"                             \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"TryRestartUnit\">\n"                          \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ReloadOrRestartUnit\">\n"                     \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ReloadOrTryRestartUnit\">\n"                  \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"KillUnit\">\n"                                \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"ResetFailedUnit\">\n"                         \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetJob\">\n"                                  \
+        "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ClearJobs\"/>\n"                              \
+        "  <method name=\"ResetFailed\"/>\n"                            \
+        "  <method name=\"ListUnits\">\n"                               \
+        "   <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListJobs\">\n"                                \
+        "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"Subscribe\"/>\n"                              \
+        "  <method name=\"Unsubscribe\"/>\n"                            \
+        "  <method name=\"Dump\"/>\n"                                   \
+        "  <method name=\"CreateSnapshot\">\n"                          \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <method name=\"Reload\"/>\n"                                 \
+        "  <method name=\"Reexecute\"/>\n"                              \
+        "  <method name=\"Exit\"/>\n"                                   \
+        "  <method name=\"Reboot\"/>\n"                                 \
+        "  <method name=\"PowerOff\"/>\n"                               \
+        "  <method name=\"Halt\"/>\n"                                   \
+        "  <method name=\"KExec\"/>\n"                                  \
+        "  <method name=\"SetEnvironment\">\n"                          \
+        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"UnsetEnvironment\">\n"                        \
+        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"UnsetAndSetEnvironment\">\n"                  \
+        "   <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"set\" type=\"as\" direction=\"in\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListUnitFiles\">\n"                            \
+        "   <arg name=\"changes\" type=\"a(ss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetUnitFileState\">\n"                        \
+        "   <arg name=\"file\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"state\" type=\"s\" direction=\"out\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"EnableUnitFiles\">\n"                         \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
+        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"DisableUnitFiles\">\n"                        \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"ReenableUnitFiles\">\n"                       \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
+        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"LinkUnitFiles\">\n"                           \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"PresetUnitFiles\">\n"                         \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
+        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"MaskUnitFiles\">\n"                           \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"UnmaskUnitFiles\">\n"                         \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"
+
+#define BUS_MANAGER_INTERFACE_SIGNALS                                   \
+        "  <signal name=\"UnitNew\">\n"                                 \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "   <arg name=\"unit\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"UnitRemoved\">\n"                             \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "   <arg name=\"unit\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"JobNew\">\n"                                  \
+        "   <arg name=\"id\" type=\"u\"/>\n"                            \
+        "   <arg name=\"job\" type=\"o\"/>\n"                           \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"JobRemoved\">\n"                              \
+        "   <arg name=\"id\" type=\"u\"/>\n"                            \
+        "   <arg name=\"job\" type=\"o\"/>\n"                           \
+        "   <arg name=\"result\" type=\"s\"/>\n"                        \
+        "  </signal>"                                                   \
+        "  <signal name=\"StartupFinished\">\n"                         \
+        "   <arg name=\"kernel\" type=\"t\"/>\n"                        \
+        "   <arg name=\"initrd\" type=\"t\"/>\n"                        \
+        "   <arg name=\"userspace\" type=\"t\"/>\n"                     \
+        "   <arg name=\"total\" type=\"t\"/>\n"                         \
+        "  </signal>"                                                   \
+        "  <signal name=\"UnitFilesChanged\"/>\n"
+
+#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
+        "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Features\" type=\"s\" access=\"read\"/>\n"  \
+        "  <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n"  \
+        "  <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
+        "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
+        "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
+        "  <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"Progress\" type=\"d\" access=\"read\"/>\n"  \
+        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"MountAuto\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"SwapAuto\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"read\"/>\n"
+
+#ifdef HAVE_SYSV_COMPAT
+#define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV                           \
+        "  <property name=\"SysVConsole\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
+#else
+#define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
+#endif
+
+#define BUS_MANAGER_INTERFACE_END                                       \
+        " </interface>\n"
+
+#define BUS_MANAGER_INTERFACE                                           \
+        BUS_MANAGER_INTERFACE_BEGIN                                     \
+        BUS_MANAGER_INTERFACE_METHODS                                   \
+        BUS_MANAGER_INTERFACE_SIGNALS                                   \
+        BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
+        BUS_MANAGER_INTERFACE_PROPERTIES_SYSV                           \
+        BUS_MANAGER_INTERFACE_END
+
+#define INTROSPECTION_BEGIN                                             \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_MANAGER_INTERFACE                                           \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE
+
+#define INTROSPECTION_END                                               \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_GENERIC_INTERFACES_LIST                  \
+        "org.freedesktop.systemd1.Manager\0"
+
+const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
+
+static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+        Manager *m = data;
+        char buf[LINE_MAX] = "", *e = buf, *p = NULL;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        if (m->taint_usr)
+                e = stpcpy(e, "usr-separate-fs ");
+
+        if (readlink_malloc("/etc/mtab", &p) < 0)
+                e = stpcpy(e, "etc-mtab-not-symlink ");
+        else
+                free(p);
+
+        if (access("/proc/cgroups", F_OK) < 0)
+                stpcpy(e, "cgroups-missing ");
+
+        t = strstrip(buf);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+
+        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_set_log_target(DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+
+        assert(i);
+        assert(property);
+
+        dbus_message_iter_get_basic(i, &t);
+
+        return log_set_target_from_string(t);
+}
+
+static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+
+        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_set_log_level(DBusMessageIter *i, const char *property, void *data) {
+        const char *t;
+
+        assert(i);
+        assert(property);
+
+        dbus_message_iter_get_basic(i, &t);
+
+        return log_set_max_level_from_string(t);
+}
+
+static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
+        Manager *m = data;
+        uint32_t u;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        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(DBusMessageIter *i, const char *property, void *data) {
+        Manager *m = data;
+        uint32_t u;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        u = hashmap_size(m->jobs);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
+        double d;
+        Manager *m = data;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        if (dual_timestamp_is_set(&m->finish_timestamp))
+                d = 1.0;
+        else
+                d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static const char *message_get_sender_with_fallback(DBusMessage *m) {
+        const char *s;
+
+        assert(m);
+
+        if ((s = dbus_message_get_sender(m)))
+                return s;
+
+        /* When the message came in from a direct connection the
+         * message will have no sender. We fix that here. */
+
+        return ":no-sender";
+}
+
+static DBusMessage *message_from_file_changes(
+                DBusMessage *m,
+                UnitFileChange *changes,
+                unsigned n_changes,
+                int carries_install_info) {
+
+        DBusMessageIter iter, sub, sub2;
+        DBusMessage *reply;
+        unsigned i;
+
+        reply = dbus_message_new_method_return(m);
+        if (!reply)
+                return NULL;
+
+        dbus_message_iter_init_append(reply, &iter);
+
+        if (carries_install_info >= 0) {
+                dbus_bool_t b;
+
+                b = !!carries_install_info;
+                if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
+                        goto oom;
+        }
+
+        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
+                goto oom;
+
+        for (i = 0; i < n_changes; i++) {
+                const char *type, *path, *source;
+
+                type = unit_file_change_type_to_string(changes[i].type);
+                path = strempty(changes[i].path);
+                source = strempty(changes[i].source);
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        goto oom;
+        }
+
+        if (!dbus_message_iter_close_container(&iter, &sub))
+                goto oom;
+
+        return reply;
+
+oom:
+        dbus_message_unref(reply);
+        return NULL;
+}
+
+static int bus_manager_send_unit_files_changed(Manager *m) {
+        DBusMessage *s;
+        int r;
+
+        s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
+        if (!s)
+                return -ENOMEM;
+
+        r = bus_broadcast(m, s);
+        dbus_message_unref(s);
+
+        return r;
+}
+
+static const char systemd_property_string[] =
+        PACKAGE_STRING "\0"
+        DISTRIBUTION "\0"
+        SYSTEMD_FEATURES;
+
+static const BusProperty bus_systemd_properties[] = {
+        { "Version",       bus_property_append_string,    "s",  0                                             },
+        { "Distribution",  bus_property_append_string,    "s",  sizeof(PACKAGE_STRING)                        },
+        { "Features",      bus_property_append_string,    "s",  sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
+        { NULL, }
+};
+
+static const BusProperty bus_manager_properties[] = {
+        { "RunningAs",     bus_manager_append_running_as,          "s", offsetof(Manager, running_as)                  },
+        { "Tainted",       bus_manager_append_tainted,             "s", 0                                              },
+        { "InitRDTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, initrd_timestamp.realtime)   },
+        { "InitRDTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, initrd_timestamp.monotonic)  },
+        { "StartupTimestamp", bus_property_append_uint64,          "t", offsetof(Manager, startup_timestamp.realtime)  },
+        { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
+        { "FinishTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, finish_timestamp.realtime)   },
+        { "FinishTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, finish_timestamp.monotonic)  },
+        { "LogLevel",      bus_manager_append_log_level,           "s", 0,                                             0, bus_manager_set_log_level },
+        { "LogTarget",     bus_manager_append_log_target,          "s", 0,                                             0, bus_manager_set_log_target },
+        { "NNames",        bus_manager_append_n_names,             "u", 0                                              },
+        { "NJobs",         bus_manager_append_n_jobs,              "u", 0                                              },
+        { "NInstalledJobs",bus_property_append_uint32,             "u", offsetof(Manager, n_installed_jobs)            },
+        { "NFailedJobs",   bus_property_append_uint32,             "u", offsetof(Manager, n_failed_jobs)               },
+        { "Progress",      bus_manager_append_progress,            "d", 0                                              },
+        { "Environment",   bus_property_append_strv,              "as", offsetof(Manager, environment),                true },
+        { "ConfirmSpawn",  bus_property_append_bool,               "b", offsetof(Manager, confirm_spawn)               },
+        { "ShowStatus",    bus_property_append_bool,               "b", offsetof(Manager, show_status)                 },
+        { "UnitPath",      bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.unit_path),     true },
+        { "NotifySocket",  bus_property_append_string,             "s", offsetof(Manager, notify_socket),              true },
+        { "ControlGroupHierarchy", bus_property_append_string,     "s", offsetof(Manager, cgroup_hierarchy),           true },
+        { "MountAuto",     bus_property_append_bool,               "b", offsetof(Manager, mount_auto)                  },
+        { "SwapAuto",      bus_property_append_bool,               "b", offsetof(Manager, swap_auto)                   },
+        { "DefaultControllers", bus_property_append_strv,         "as", offsetof(Manager, default_controllers),        true },
+        { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output)          },
+        { "DefaultStandardError",  bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error)           },
+        { "RuntimeWatchdogUSec", bus_property_append_usec,         "t", offsetof(Manager, runtime_watchdog),           },
+        { "ShutdownWatchdogUSec", bus_property_append_usec,        "t", offsetof(Manager, shutdown_watchdog),          },
+#ifdef HAVE_SYSV_COMPAT
+        { "SysVConsole",   bus_property_append_bool,               "b", offsetof(Manager, sysv_console)                },
+        { "SysVInitPath",  bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.sysvinit_path), true },
+        { "SysVRcndPath",  bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.sysvrcnd_path), true },
+#endif
+        { NULL, }
+};
+
+static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
+        Manager *m = data;
+
+        int r;
+        DBusError error;
+        DBusMessage *reply = NULL;
+        char * path = NULL;
+        JobType job_type = _JOB_TYPE_INVALID;
+        bool reload_if_possible = false;
+        const char *member;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        member = dbus_message_get_member(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(connection, message, &error, -EINVAL);
+
+                if (!(u = manager_get_unit(m, name))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+                        return bus_send_error_reply(connection, message, &error, -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", "GetUnitByPID")) {
+                Unit *u;
+                uint32_t pid;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_UINT32, &pid,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
+                        return bus_send_error_reply(connection, message, &error, -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(connection, message, &error, -EINVAL);
+
+                if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
+                        return bus_send_error_reply(connection, message, &error, 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", "StartUnit"))
+                job_type = JOB_START;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
+                job_type = JOB_START;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
+                job_type = JOB_STOP;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
+                job_type = JOB_RELOAD;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
+                job_type = JOB_RESTART;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
+                job_type = JOB_TRY_RESTART;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
+                reload_if_possible = true;
+                job_type = JOB_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
+                reload_if_possible = true;
+                job_type = JOB_TRY_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
+                const char *name, *swho, *smode;
+                int32_t signo;
+                Unit *u;
+                KillMode mode;
+                KillWho who;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_STRING, &swho,
+                                    DBUS_TYPE_STRING, &smode,
+                                    DBUS_TYPE_INT32, &signo,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (isempty(swho))
+                        who = KILL_ALL;
+                else {
+                        who = kill_who_from_string(swho);
+                        if (who < 0)
+                                return bus_send_error_reply(connection, message, &error, -EINVAL);
+                }
+
+                if (isempty(smode))
+                        mode = KILL_CONTROL_GROUP;
+                else {
+                        mode = kill_mode_from_string(smode);
+                        if (mode < 0)
+                                return bus_send_error_reply(connection, message, &error, -EINVAL);
+                }
+
+                if (signo <= 0 || signo >= _NSIG)
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (!(u = manager_get_unit(m, name))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+                }
+
+                if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        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(connection, message, &error, -EINVAL);
+
+                if (!(j = manager_get_job(m, id))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
+                        return bus_send_error_reply(connection, message, &error, -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", "ResetFailed")) {
+
+                manager_reset_failed(m);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
+                const char *name;
+                Unit *u;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (!(u = manager_get_unit(m, name))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+                }
+
+                unit_reset_failed(u);
+
+                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, "(ssssssouso)", &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, *sjob_type, *following;
+                        DBusMessageIter sub2;
+                        uint32_t job_id;
+                        Unit *f;
+
+                        if (k != u->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->load_state);
+                        active_state = unit_active_state_to_string(unit_active_state(u));
+                        sub_state = unit_sub_state_to_string(u);
+
+                        f = unit_following(u);
+                        following = f ? f->id : "";
+
+                        if (!(u_path = unit_dbus_path(u)))
+                                goto oom;
+
+                        if (u->job) {
+                                job_id = (uint32_t) u->job->id;
+
+                                if (!(j_path = job_dbus_path(u->job))) {
+                                        free(u_path);
+                                        goto oom;
+                                }
+
+                                sjob_type = job_type_to_string(u->job->type);
+                        } else {
+                                job_id = 0;
+                                j_path = u_path;
+                                sjob_type = "";
+                        }
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->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_STRING, &following) ||
+                            !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, &sjob_type) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
+                                free(u_path);
+                                if (u->job)
+                                        free(j_path);
+                                goto oom;
+                        }
+
+                        free(u_path);
+                        if (u->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->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;
+                Set *s;
+
+                if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
+                        if (!(s = set_new(string_hash_func, string_compare_func)))
+                                goto oom;
+
+                        if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
+                                set_free(s);
+                                goto oom;
+                        }
+                }
+
+                if (!(client = strdup(message_get_sender_with_fallback(message))))
+                        goto oom;
+
+                if ((r = set_put(s, client)) < 0) {
+                        free(client);
+                        return bus_send_error_reply(connection, 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(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
+                        return bus_send_error_reply(connection, message, &error, -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(connection, message, &error, -EINVAL);
+
+                if (name && name[0] == 0)
+                        name = NULL;
+
+                if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
+                        return bus_send_error_reply(connection, message, &error, 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->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->queued_message_connection = connection;
+                m->exit_code = MANAGER_RELOAD;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
+
+                /* We don't send a reply back here, the client should
+                 * just wait for us disconnecting. */
+
+                m->exit_code = MANAGER_REEXECUTE;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
+
+                if (m->running_as == MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
+                        return bus_send_error_reply(connection, message, &error, -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", "Reboot")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
+                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_REBOOT;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
+                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_POWEROFF;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
+                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_HALT;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
+                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_KEXEC;
+
+        } 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(connection, message, NULL, r);
+                }
+
+                e = strv_env_merge(2, m->environment, l);
+                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(connection, message, NULL, r);
+                }
+
+                e = strv_env_delete(m->environment, 1, l);
+                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", "UnsetAndSetEnvironment")) {
+                char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
+                DBusMessageIter iter;
+
+                if (!dbus_message_iter_init(message, &iter))
+                        goto oom;
+
+                r = bus_parse_strv_iter(&iter, &l_unset);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                if (!dbus_message_iter_next(&iter)) {
+                        strv_free(l_unset);
+                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+                }
+
+                r = bus_parse_strv_iter(&iter, &l_set);
+                if (r < 0) {
+                        strv_free(l_unset);
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                e = strv_env_delete(m->environment, 1, l_unset);
+                strv_free(l_unset);
+
+                if (!e) {
+                        strv_free(l_set);
+                        goto oom;
+                }
+
+                f = strv_env_merge(2, e, l_set);
+                strv_free(l_set);
+                strv_free(e);
+
+                if (!f)
+                        goto oom;
+
+                if (!(reply = dbus_message_new_method_return(message))) {
+                        strv_free(f);
+                        goto oom;
+                }
+
+                strv_free(m->environment);
+                m->environment = f;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
+                DBusMessageIter iter, sub, sub2;
+                Hashmap *h;
+                Iterator i;
+                UnitFileList *item;
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                h = hashmap_new(string_hash_func, string_compare_func);
+                if (!h)
+                        goto oom;
+
+                r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
+                if (r < 0) {
+                        unit_file_list_free(h);
+                        dbus_message_unref(reply);
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
+                        unit_file_list_free(h);
+                        goto oom;
+                }
+
+                HASHMAP_FOREACH(item, h, i) {
+                        const char *state;
+
+                        state = unit_file_state_to_string(item->state);
+                        assert(state);
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
+                            !dbus_message_iter_close_container(&sub, &sub2)) {
+                                unit_file_list_free(h);
+                                goto oom;
+                        }
+                }
+
+                unit_file_list_free(h);
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
+                const char *name;
+                UnitFileState state;
+                const char *s;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
+                if (state < 0)
+                        return bus_send_error_reply(connection, message, NULL, state);
+
+                s = unit_file_state_to_string(state);
+                assert(s);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_STRING, &s,
+                                    DBUS_TYPE_INVALID))
+                        goto oom;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
+
+                char **l = NULL;
+                DBusMessageIter iter;
+                UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+                UnitFileChange *changes = NULL;
+                unsigned n_changes = 0;
+                dbus_bool_t runtime, force;
+                int carries_install_info = -1;
+
+                if (!dbus_message_iter_init(message, &iter))
+                        goto oom;
+
+                r = bus_parse_strv_iter(&iter, &l);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                if (!dbus_message_iter_next(&iter) ||
+                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
+                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
+                        strv_free(l);
+                        return bus_send_error_reply(connection, message, NULL, -EIO);
+                }
+
+                if (streq(member, "EnableUnitFiles")) {
+                        r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
+                        carries_install_info = r;
+                } else if (streq(member, "ReenableUnitFiles")) {
+                        r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
+                        carries_install_info = r;
+                } else if (streq(member, "LinkUnitFiles"))
+                        r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
+                else if (streq(member, "PresetUnitFiles")) {
+                        r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
+                        carries_install_info = r;
+                } else if (streq(member, "MaskUnitFiles"))
+                        r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
+                else
+                        assert_not_reached("Uh? Wrong method");
+
+                strv_free(l);
+                bus_manager_send_unit_files_changed(m);
+
+                if (r < 0) {
+                        unit_file_changes_free(changes, n_changes);
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
+                unit_file_changes_free(changes, n_changes);
+
+                if (!reply)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
+
+                char **l = NULL;
+                DBusMessageIter iter;
+                UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+                UnitFileChange *changes = NULL;
+                unsigned n_changes = 0;
+                dbus_bool_t runtime;
+
+                if (!dbus_message_iter_init(message, &iter))
+                        goto oom;
+
+                r = bus_parse_strv_iter(&iter, &l);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                if (!dbus_message_iter_next(&iter) ||
+                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
+                        strv_free(l);
+                        return bus_send_error_reply(connection, message, NULL, -EIO);
+                }
+
+                if (streq(member, "DisableUnitFiles"))
+                        r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
+                else if (streq(member, "UnmaskUnitFiles"))
+                        r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
+                else
+                        assert_not_reached("Uh? Wrong method");
+
+                strv_free(l);
+                bus_manager_send_unit_files_changed(m);
+
+                if (r < 0) {
+                        unit_file_changes_free(changes, n_changes);
+                        return bus_send_error_reply(connection, message, NULL, r);
+                }
+
+                reply = message_from_file_changes(message, changes, n_changes, -1);
+                unit_file_changes_free(changes, n_changes);
+
+                if (!reply)
+                        goto oom;
+
+        } else {
+                const BusBoundProperties bps[] = {
+                        { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
+                        { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
+                        { NULL, }
+                };
+                return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
+        }
+
+        if (job_type != _JOB_TYPE_INVALID) {
+                const char *name, *smode, *old_name = NULL;
+                JobMode mode;
+                Job *j;
+                Unit *u;
+                bool b;
+
+                if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
+                        b = dbus_message_get_args(
+                                        message,
+                                        &error,
+                                        DBUS_TYPE_STRING, &old_name,
+                                        DBUS_TYPE_STRING, &name,
+                                        DBUS_TYPE_STRING, &smode,
+                                        DBUS_TYPE_INVALID);
+                else
+                        b = dbus_message_get_args(
+                                        message,
+                                        &error,
+                                        DBUS_TYPE_STRING, &name,
+                                        DBUS_TYPE_STRING, &smode,
+                                        DBUS_TYPE_INVALID);
+
+                if (!b)
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (old_name)
+                        if (!(u = manager_get_unit(m, old_name)) ||
+                            !u->job ||
+                            u->job->type != JOB_START) {
+                                dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
+                                return bus_send_error_reply(connection, message, &error, -ENOENT);
+                        }
+
+
+                if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
+                        dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+                }
+
+                if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                if (reload_if_possible && unit_can_reload(u)) {
+                        if (job_type == JOB_RESTART)
+                                job_type = JOB_RELOAD_OR_START;
+                        else if (job_type == JOB_TRY_RESTART)
+                                job_type = JOB_RELOAD;
+                }
+
+                if ((job_type == JOB_START && u->refuse_manual_start) ||
+                    (job_type == JOB_STOP && u->refuse_manual_stop) ||
+                    ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
+                     (u->refuse_manual_start || u->refuse_manual_stop))) {
+                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
+                        return bus_send_error_reply(connection, message, &error, -EPERM);
+                }
+
+                if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                if (!(j->bus_client = strdup(message_get_sender_with_fallback(message))))
+                        goto oom;
+
+                j->bus = connection;
+
+                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(connection, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        free(path);
+
+        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/core/dbus-manager.h b/src/core/dbus-manager.h
new file mode 100644
index 0000000..2eb2fbb
--- /dev/null
+++ b/src/core/dbus-manager.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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;
+
+extern const char bus_manager_interface[];
+
+#endif
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
new file mode 100644
index 0000000..35d6ea7
--- /dev/null
+++ b/src/core/dbus-mount.c
@@ -0,0 +1,168 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "dbus-common.h"
+
+#define BUS_MOUNT_INTERFACE                                             \
+        " <interface name=\"org.freedesktop.systemd1.Mount\">\n"        \
+        "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"     \
+        "  <property name=\"What\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Options\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecMount")                         \
+        BUS_EXEC_COMMAND_INTERFACE("ExecUnmount")                       \
+        BUS_EXEC_COMMAND_INTERFACE("ExecRemount")                       \
+        BUS_EXEC_CONTEXT_INTERFACE                                      \
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_MOUNT_INTERFACE                                             \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Mount\0"
+
+const char bus_mount_interface[] _introspect_("Mount") = BUS_MOUNT_INTERFACE;
+
+const char bus_mount_invalidating_properties[] =
+        "What\0"
+        "Options\0"
+        "Type\0"
+        "ExecMount\0"
+        "ExecUnmount\0"
+        "ExecRemount\0"
+        "ControlPID\0"
+        "Result\0";
+
+static int bus_mount_append_what(DBusMessageIter *i, const char *property, void *data) {
+        Mount *m = data;
+        const char *d;
+
+        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(DBusMessageIter *i, const char *property, void *data) {
+        Mount *m = data;
+        const char *d;
+
+        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(DBusMessageIter *i, const char *property, void *data) {
+        Mount *m = data;
+        const char *d;
+
+        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;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_mount_append_mount_result, mount_result, MountResult);
+
+static const BusProperty bus_mount_properties[] = {
+        { "Where",         bus_property_append_string, "s", offsetof(Mount, where),    true },
+        { "What",          bus_mount_append_what,      "s", 0 },
+        { "Options",       bus_mount_append_options,   "s", 0 },
+        { "Type",          bus_mount_append_type,      "s", 0 },
+        { "TimeoutUSec",   bus_property_append_usec,   "t", offsetof(Mount, timeout_usec)   },
+        BUS_EXEC_COMMAND_PROPERTY("ExecMount",   offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]),   false),
+        BUS_EXEC_COMMAND_PROPERTY("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), false),
+        BUS_EXEC_COMMAND_PROPERTY("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), false),
+        { "ControlPID",    bus_property_append_pid,    "u", offsetof(Mount, control_pid)    },
+        { "DirectoryMode", bus_property_append_mode,   "u", offsetof(Mount, directory_mode) },
+        { "Result",        bus_mount_append_mount_result, "s", offsetof(Mount, result)      },
+        { NULL, }
+};
+
+DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Mount *m = MOUNT(u);
+
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,         u },
+                { "org.freedesktop.systemd1.Mount", bus_mount_properties,        m },
+                { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps );
+}
diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h
new file mode 100644
index 0000000..b5613fa
--- /dev/null
+++ b/src/core/dbus-mount.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_mount_interface[];
+extern const char bus_mount_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
new file mode 100644
index 0000000..5506784
--- /dev/null
+++ b/src/core/dbus-path.c
@@ -0,0 +1,119 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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-path.h"
+#include "dbus-execute.h"
+#include "dbus-common.h"
+
+#define BUS_PATH_INTERFACE                                              \
+        " <interface name=\"org.freedesktop.systemd1.Path\">\n"         \
+        "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Paths\" type=\"a(ss)\" access=\"read\"/>\n" \
+        "  <property name=\"MakeDirectory\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_PATH_INTERFACE                                              \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Path\0"
+
+const char bus_path_interface[] _introspect_("Path") = BUS_PATH_INTERFACE;
+
+const char bus_path_invalidating_properties[] =
+        "Result\0";
+
+static int bus_path_append_paths(DBusMessageIter *i, const char *property, void *data) {
+        Path *p = data;
+        DBusMessageIter sub, sub2;
+        PathSpec *k;
+
+        assert(i);
+        assert(property);
+        assert(p);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(spec, k, p->specs) {
+                const char *t = path_type_to_string(k->type);
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &k->path) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        Path *p = PATH(u);
+        const char *t;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        t = UNIT_DEREF(p->unit) ? UNIT_DEREF(p->unit)->id : "";
+
+        return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_path_append_path_result, path_result, PathResult);
+
+static const BusProperty bus_path_properties[] = {
+        { "Unit",          bus_path_append_unit,      "s", 0 },
+        { "Paths",         bus_path_append_paths, "a(ss)", 0 },
+        { "MakeDirectory", bus_property_append_bool,  "b", offsetof(Path, make_directory) },
+        { "DirectoryMode", bus_property_append_mode,  "u", offsetof(Path, directory_mode) },
+        { "Result",        bus_path_append_path_result, "s", offsetof(Path, result) },
+        { NULL, }
+};
+
+DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Path *p = PATH(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
+                { "org.freedesktop.systemd1.Path", bus_path_properties, p },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h
new file mode 100644
index 0000000..2888400
--- /dev/null
+++ b/src/core/dbus-path.h
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foodbuspathhfoo
+#define foodbuspathhfoo
+
+/***
+  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_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_path_interface[];
+
+extern const char bus_path_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
new file mode 100644
index 0000000..d840415
--- /dev/null
+++ b/src/core/dbus-service.c
@@ -0,0 +1,169 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "dbus-common.h"
+
+#ifdef HAVE_SYSV_COMPAT
+#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT                            \
+        "  <property name=\"SysVStartPriority\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"SysVRunLevels\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"SysVPath\" type=\"s\" access=\"read\"/>\n"
+#else
+#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT ""
+#endif
+
+#define BUS_SERVICE_INTERFACE                                           \
+        " <interface name=\"org.freedesktop.systemd1.Service\">\n"      \
+        "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Restart\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStart")                         \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
+        BUS_EXEC_COMMAND_INTERFACE("ExecReload")                        \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStop")                          \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
+        BUS_EXEC_CONTEXT_INTERFACE                                      \
+        "  <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
+        BUS_EXEC_STATUS_INTERFACE("ExecMain")                           \
+        "  <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n"   \
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"BusName\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"FsckPassNo\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        BUS_SERVICE_SYSV_INTERFACE_FRAGMENT                             \
+       " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_SERVICE_INTERFACE                                           \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Service\0"
+
+const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
+
+const char bus_service_invalidating_properties[] =
+        "ExecStartPre\0"
+        "ExecStart\0"
+        "ExecStartPost\0"
+        "ExecReload\0"
+        "ExecStop\0"
+        "ExecStopPost\0"
+        "ExecMain\0"
+        "WatchdogTimestamp\0"
+        "WatchdogTimestampMonotonic\0"
+        "MainPID\0"
+        "ControlPID\0"
+        "StatusText\0"
+        "Result\0";
+
+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);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
+static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction);
+
+static const BusProperty bus_exec_main_status_properties[] = {
+        { "ExecMainStartTimestamp",         bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
+        { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
+        { "ExecMainExitTimestamp",          bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
+        { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
+        { "ExecMainPID",                    bus_property_append_pid,  "u", offsetof(ExecStatus, pid)                       },
+        { "ExecMainCode",                   bus_property_append_int,  "i", offsetof(ExecStatus, code)                      },
+        { "ExecMainStatus",                 bus_property_append_int,  "i", offsetof(ExecStatus, status)                    },
+        { NULL, }
+};
+
+static const BusProperty bus_service_properties[] = {
+        { "Type",                   bus_service_append_type,          "s", offsetof(Service, type)                         },
+        { "Restart",                bus_service_append_restart,       "s", offsetof(Service, restart)                      },
+        { "PIDFile",                bus_property_append_string,       "s", offsetof(Service, pid_file),               true },
+        { "NotifyAccess",           bus_service_append_notify_access, "s", offsetof(Service, notify_access)                },
+        { "RestartUSec",            bus_property_append_usec,         "t", offsetof(Service, restart_usec)                 },
+        { "TimeoutUSec",            bus_property_append_usec,         "t", offsetof(Service, timeout_usec)                 },
+        { "WatchdogUSec",           bus_property_append_usec,         "t", offsetof(Service, watchdog_usec)                },
+        { "WatchdogTimestamp",      bus_property_append_usec,         "t", offsetof(Service, watchdog_timestamp.realtime)  },
+        { "WatchdogTimestampMonotonic",bus_property_append_usec,      "t", offsetof(Service, watchdog_timestamp.monotonic) },
+        { "StartLimitInterval",     bus_property_append_usec,         "t", offsetof(Service, start_limit.interval)         },
+        { "StartLimitBurst",        bus_property_append_uint32,       "u", offsetof(Service, start_limit.burst)            },
+        { "StartLimitAction",       bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action), false, bus_service_set_start_limit_action},
+        BUS_EXEC_COMMAND_PROPERTY("ExecStartPre",  offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]),  true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStart",     offsetof(Service, exec_command[SERVICE_EXEC_START]),      true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecReload",    offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]),     true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStop",      offsetof(Service, exec_command[SERVICE_EXEC_STOP]),       true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStopPost",  offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]),  true ),
+        { "PermissionsStartOnly",   bus_property_append_bool,         "b", offsetof(Service, permissions_start_only)       },
+        { "RootDirectoryStartOnly", bus_property_append_bool,         "b", offsetof(Service, root_directory_start_only)    },
+        { "RemainAfterExit",        bus_property_append_bool,         "b", offsetof(Service, remain_after_exit)            },
+        { "GuessMainPID",           bus_property_append_bool,         "b", offsetof(Service, guess_main_pid)               },
+        { "MainPID",                bus_property_append_pid,          "u", offsetof(Service, main_pid)                     },
+        { "ControlPID",             bus_property_append_pid,          "u", offsetof(Service, control_pid)                  },
+        { "BusName",                bus_property_append_string,       "s", offsetof(Service, bus_name),               true },
+        { "StatusText",             bus_property_append_string,       "s", offsetof(Service, status_text),            true },
+#ifdef HAVE_SYSV_COMPAT
+        { "SysVRunLevels",          bus_property_append_string,       "s", offsetof(Service, sysv_runlevels),         true },
+        { "SysVStartPriority",      bus_property_append_int,          "i", offsetof(Service, sysv_start_priority)          },
+        { "SysVPath",               bus_property_append_string,       "s", offsetof(Service, sysv_path),              true },
+#endif
+        { "FsckPassNo",             bus_property_append_int,          "i", offsetof(Service, fsck_passno)                  },
+        { "Result",                 bus_service_append_service_result,"s", offsetof(Service, result)                       },
+        { NULL, }
+};
+
+DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
+        Service *s = SERVICE(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",    bus_unit_properties,             u },
+                { "org.freedesktop.systemd1.Service", bus_service_properties,          s },
+                { "org.freedesktop.systemd1.Service", bus_exec_context_properties,     &s->exec_context },
+                { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
new file mode 100644
index 0000000..d6eab65
--- /dev/null
+++ b/src/core/dbus-service.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_service_interface[];
+extern const char bus_service_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
new file mode 100644
index 0000000..e69388a
--- /dev/null
+++ b/src/core/dbus-snapshot.c
@@ -0,0 +1,93 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "dbus-common.h"
+
+#define BUS_SNAPSHOT_INTERFACE                                          \
+        " <interface name=\"org.freedesktop.systemd1.Snapshot\">\n"     \
+        "  <method name=\"Remove\"/>\n"                                 \
+        "  <property name=\"Cleanup\" type=\"b\" access=\"read\"/>\n"   \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_SNAPSHOT_INTERFACE                                          \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Snapshot\0"
+
+const char bus_snapshot_interface[] _introspect_("Snapshot") = BUS_SNAPSHOT_INTERFACE;
+
+static const BusProperty bus_snapshot_properties[] = {
+        { "Cleanup", bus_property_append_bool, "b", offsetof(Snapshot, cleanup) },
+        { NULL, }
+};
+
+DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Snapshot *s = SNAPSHOT(u);
+
+        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 {
+                const BusBoundProperties bps[] = {
+                        { "org.freedesktop.systemd1.Unit",     bus_unit_properties,     u },
+                        { "org.freedesktop.systemd1.Snapshot", bus_snapshot_properties, s },
+                        { NULL, }
+                };
+                return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+        }
+
+        if (reply) {
+                if (!dbus_connection_send(c, 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/core/dbus-snapshot.h b/src/core/dbus-snapshot.h
new file mode 100644
index 0000000..0b82279
--- /dev/null
+++ b/src/core/dbus-snapshot.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_snapshot_interface[];
+
+#endif
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
new file mode 100644
index 0000000..2e3342c
--- /dev/null
+++ b/src/core/dbus-socket.c
@@ -0,0 +1,139 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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-socket.h"
+#include "dbus-execute.h"
+#include "dbus-common.h"
+
+#define BUS_SOCKET_INTERFACE                                            \
+        " <interface name=\"org.freedesktop.systemd1.Socket\">\n"       \
+        "  <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Backlog\" type=\"u\" access=\"read\"/>\n"   \
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStopPre")                       \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
+        BUS_EXEC_CONTEXT_INTERFACE                                      \
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"SocketMode\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"Accept\" type=\"b\" access=\"read\"/>\n"    \
+        "  <property name=\"KeepAlive\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Priority\" type=\"i\" access=\"read\"/>\n"  \
+        "  <property name=\"ReceiveBuffer\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"SendBuffer\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"IPTOS\" type=\"i\" access=\"read\"/>\n"     \
+        "  <property name=\"IPTTL\" type=\"i\" access=\"read\"/>\n"     \
+        "  <property name=\"PipeSize\" type=\"t\" access=\"read\"/>\n"  \
+        "  <property name=\"FreeBind\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"Transparent\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Broadcast\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"PassCredentials\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"PassSecurity\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Mark\" type=\"i\" access=\"read\"/>\n"      \
+        "  <property name=\"MaxConnections\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"NAccepted\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"NConnections\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"MessageQueueMaxMessages\" type=\"x\" access=\"read\"/>\n" \
+        "  <property name=\"MessageQueueMessageSize\" type=\"x\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        " </interface>\n"                                               \
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_SOCKET_INTERFACE                                            \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Socket\0"
+
+const char bus_socket_interface[] _introspect_("Socket") = BUS_SOCKET_INTERFACE;
+
+const char bus_socket_invalidating_properties[] =
+        "ExecStartPre\0"
+        "ExecStartPost\0"
+        "ExecStopPre\0"
+        "ExecStopPost\0"
+        "ControlPID\0"
+        "NAccepted\0"
+        "NConnections\0"
+        "Result\0";
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_socket_result, socket_result, SocketResult);
+
+static const BusProperty bus_socket_properties[] = {
+        { "BindIPv6Only",   bus_socket_append_bind_ipv6_only,  "s", offsetof(Socket, bind_ipv6_only)  },
+        { "Backlog",        bus_property_append_unsigned,      "u", offsetof(Socket, backlog)         },
+        { "TimeoutUSec",    bus_property_append_usec,          "t", offsetof(Socket, timeout_usec)    },
+        BUS_EXEC_COMMAND_PROPERTY("ExecStartPre",  offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]),  true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStopPre",   offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]),   true ),
+        BUS_EXEC_COMMAND_PROPERTY("ExecStopPost",  offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]),  true ),
+        { "ControlPID",     bus_property_append_pid,           "u", offsetof(Socket, control_pid)     },
+        { "BindToDevice",   bus_property_append_string,        "s", offsetof(Socket, bind_to_device), true },
+        { "DirectoryMode",  bus_property_append_mode,          "u", offsetof(Socket, directory_mode)  },
+        { "SocketMode",     bus_property_append_mode,          "u", offsetof(Socket, socket_mode)     },
+        { "Accept",         bus_property_append_bool,          "b", offsetof(Socket, accept)          },
+        { "KeepAlive",      bus_property_append_bool,          "b", offsetof(Socket, keep_alive)      },
+        { "Priority",       bus_property_append_int,           "i", offsetof(Socket, priority)        },
+        { "ReceiveBuffer",  bus_property_append_size,          "t", offsetof(Socket, receive_buffer)  },
+        { "SendBuffer",     bus_property_append_size,          "t", offsetof(Socket, send_buffer)     },
+        { "IPTOS",          bus_property_append_int,           "i", offsetof(Socket, ip_tos)          },
+        { "IPTTL",          bus_property_append_int,           "i", offsetof(Socket, ip_ttl)          },
+        { "PipeSize",       bus_property_append_size,          "t", offsetof(Socket, pipe_size)       },
+        { "FreeBind",       bus_property_append_bool,          "b", offsetof(Socket, free_bind)       },
+        { "Transparent",    bus_property_append_bool,          "b", offsetof(Socket, transparent)     },
+        { "Broadcast",      bus_property_append_bool,          "b", offsetof(Socket, broadcast)       },
+        { "PassCredentials",bus_property_append_bool,          "b", offsetof(Socket, pass_cred)       },
+        { "PassSecurity",   bus_property_append_bool,          "b", offsetof(Socket, pass_sec)        },
+        { "Mark",           bus_property_append_int,           "i", offsetof(Socket, mark)            },
+        { "MaxConnections", bus_property_append_unsigned,      "u", offsetof(Socket, max_connections) },
+        { "NConnections",   bus_property_append_unsigned,      "u", offsetof(Socket, n_connections)   },
+        { "NAccepted",      bus_property_append_unsigned,      "u", offsetof(Socket, n_accepted)      },
+        { "MessageQueueMaxMessages", bus_property_append_long, "x", offsetof(Socket, mq_maxmsg)       },
+        { "MessageQueueMessageSize", bus_property_append_long, "x", offsetof(Socket, mq_msgsize)      },
+        { "Result",         bus_socket_append_socket_result,   "s", offsetof(Socket, result)          },
+        { NULL, }
+};
+
+DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Socket *s = SOCKET(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",   bus_unit_properties,         u },
+                { "org.freedesktop.systemd1.Socket", bus_socket_properties,       s },
+                { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h
new file mode 100644
index 0000000..069a2f5
--- /dev/null
+++ b/src/core/dbus-socket.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_socket_interface[];
+extern const char bus_socket_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
new file mode 100644
index 0000000..09cd1e8
--- /dev/null
+++ b/src/core/dbus-swap.c
@@ -0,0 +1,111 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "dbus-execute.h"
+#include "dbus-common.h"
+
+#define BUS_SWAP_INTERFACE                                              \
+        " <interface name=\"org.freedesktop.systemd1.Swap\">\n"         \
+        "  <property name=\"What\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Priority\" type=\"i\" access=\"read\"/>\n"  \
+        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecActivate")                      \
+        BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate")                    \
+        BUS_EXEC_CONTEXT_INTERFACE                                      \
+        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_SWAP_INTERFACE                                              \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Swap\0"
+
+const char bus_swap_interface[] _introspect_("Swap") = BUS_SWAP_INTERFACE;
+
+const char bus_swap_invalidating_properties[] =
+        "What\0"
+        "Priority\0"
+        "ExecActivate\0"
+        "ExecDeactivate\0"
+        "ControlPID\0"
+        "Result\0";
+
+static int bus_swap_append_priority(DBusMessageIter *i, const char *property, void *data) {
+        Swap *s = data;
+        dbus_int32_t j;
+
+        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;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_swap_append_swap_result, swap_result, SwapResult);
+
+static const BusProperty bus_swap_properties[] = {
+        { "What",       bus_property_append_string, "s", offsetof(Swap, what),  true },
+        { "Priority",   bus_swap_append_priority,   "i", 0 },
+        BUS_EXEC_COMMAND_PROPERTY("ExecActivate",   offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]),   false),
+        BUS_EXEC_COMMAND_PROPERTY("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), false),
+        { "ControlPID", bus_property_append_pid,    "u", offsetof(Swap, control_pid) },
+        { "Result",     bus_swap_append_swap_result,"s", offsetof(Swap, result)      },
+        { NULL, }
+};
+
+DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Swap *s = SWAP(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit", bus_unit_properties,         u },
+                { "org.freedesktop.systemd1.Swap", bus_swap_properties,         s },
+                { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h
new file mode 100644
index 0000000..15b9147
--- /dev/null
+++ b/src/core/dbus-swap.h
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_swap_interface[];
+extern const char bus_swap_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
new file mode 100644
index 0000000..55cf862
--- /dev/null
+++ b/src/core/dbus-target.c
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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-target.h"
+#include "dbus-common.h"
+
+#define BUS_TARGET_INTERFACE                                            \
+        " <interface name=\"org.freedesktop.systemd1.Target\">\n"       \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_TARGET_INTERFACE                                            \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Target\0"
+
+const char bus_target_interface[] _introspect_("Target") = BUS_TARGET_INTERFACE;
+
+DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
new file mode 100644
index 0000000..13d3876
--- /dev/null
+++ b/src/core/dbus-target.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_target_interface[];
+
+#endif
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
new file mode 100644
index 0000000..b396aed
--- /dev/null
+++ b/src/core/dbus-timer.c
@@ -0,0 +1,137 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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-timer.h"
+#include "dbus-execute.h"
+#include "dbus-common.h"
+
+#define BUS_TIMER_INTERFACE                                             \
+        " <interface name=\"org.freedesktop.systemd1.Timer\">\n"        \
+        "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Timers\" type=\"a(stt)\" access=\"read\"/>\n" \
+        "  <property name=\"NextElapseUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_TIMER_INTERFACE                                             \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Timer\0"
+
+const char bus_timer_interface[] _introspect_("Timer") = BUS_TIMER_INTERFACE;
+
+const char bus_timer_invalidating_properties[] =
+        "Timers\0"
+        "NextElapseUSec\0"
+        "Result\0";
+
+static int bus_timer_append_timers(DBusMessageIter *i, const char *property, void *data) {
+        Timer *p = data;
+        DBusMessageIter sub, sub2;
+        TimerValue *k;
+
+        assert(i);
+        assert(property);
+        assert(p);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(stt)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(value, k, p->values) {
+                char *buf;
+                const char *t;
+                size_t l;
+                bool b;
+
+                t = timer_base_to_string(k->base);
+                assert(endswith(t, "Sec"));
+
+                /* s/Sec/USec/ */
+                l = strlen(t);
+                if (!(buf = new(char, l+2)))
+                        return -ENOMEM;
+
+                memcpy(buf, t, l-3);
+                memcpy(buf+l-3, "USec", 5);
+
+                b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) &&
+                        dbus_message_iter_close_container(&sub, &sub2);
+
+                free(buf);
+                if (!b)
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_timer_append_unit(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        Timer *timer = TIMER(u);
+        const char *t;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        t = UNIT_DEREF(timer->unit) ? UNIT_DEREF(timer->unit)->id : "";
+
+        return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_timer_append_timer_result, timer_result, TimerResult);
+
+static const BusProperty bus_timer_properties[] = {
+        { "Unit",           bus_timer_append_unit,        "s", 0 },
+        { "Timers",         bus_timer_append_timers, "a(stt)", 0 },
+        { "NextElapseUSec", bus_property_append_usec,     "t", offsetof(Timer, next_elapse) },
+        { "Result",         bus_timer_append_timer_result,"s", offsetof(Timer, result)      },
+        { NULL, }
+};
+
+DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        Timer *t = TIMER(u);
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,  u },
+                { "org.freedesktop.systemd1.Timer", bus_timer_properties, t },
+                { NULL, }
+        };
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
new file mode 100644
index 0000000..e692e12
--- /dev/null
+++ b/src/core/dbus-timer.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foodbustimerhfoo
+#define foodbustimerhfoo
+
+/***
+  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_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_timer_interface[];
+extern const char bus_timer_invalidating_properties[];
+
+#endif
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
new file mode 100644
index 0000000..c7532c7
--- /dev/null
+++ b/src/core/dbus-unit.c
@@ -0,0 +1,850 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "bus-errors.h"
+#include "dbus-common.h"
+
+const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE;
+
+#define INVALIDATING_PROPERTIES                 \
+        "LoadState\0"                           \
+        "ActiveState\0"                         \
+        "SubState\0"                            \
+        "InactiveExitTimestamp\0"               \
+        "ActiveEnterTimestamp\0"                \
+        "ActiveExitTimestamp\0"                 \
+        "InactiveEnterTimestamp\0"              \
+        "Job\0"                                 \
+        "NeedDaemonReload\0"
+
+static int bus_unit_append_names(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->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;
+}
+
+static int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data, *f;
+        const char *d;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        f = unit_following(u);
+        d = f ? f->id : "";
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_dependencies(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->id))
+                        return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *d;
+
+        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;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState);
+
+static int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *state;
+
+        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;
+}
+
+static int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *state;
+
+        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;
+}
+
+static int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *state;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        state = strempty(unit_file_state_to_string(unit_get_unit_file_state(u)));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = unit_can_start(u) &&
+                !u->refuse_manual_start;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        /* On the lower levels we assume that every unit we can start
+         * we can also stop */
+
+        b = unit_can_start(u) &&
+                !u->refuse_manual_stop;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        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;
+}
+
+static int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = unit_can_isolate(u) &&
+                !u->refuse_manual_start;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        DBusMessageIter sub;
+        char *p;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        if (u->job) {
+
+                if (!(p = job_dbus_path(u->job)))
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->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;
+}
+
+static int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        char *t;
+        CGroupBonding *cgb;
+        bool success;
+
+        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;
+}
+
+static int bus_unit_append_cgroups(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->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;
+}
+
+static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        CGroupAttribute *a;
+        DBusMessageIter sub, sub2;
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
+                char *v = NULL;
+                bool success;
+
+                if (a->map_callback)
+                        a->map_callback(a->controller, a->name, a->value, &v);
+
+                success =
+                        dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) &&
+                        dbus_message_iter_close_container(&sub, &sub2);
+
+                free(v);
+
+                if (!success)
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = unit_need_daemon_reload(u);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        const char *name, *message;
+        DBusMessageIter sub;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        if (u->load_error != 0) {
+                name = bus_errno_to_dbus(u->load_error);
+                message = strempty(strerror(-u->load_error));
+        } else
+                name = message = "";
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &message) ||
+            !dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) {
+        DBusMessage *reply = NULL;
+        Manager *m = u->manager;
+        DBusError error;
+        JobType job_type = _JOB_TYPE_INVALID;
+        char *path = NULL;
+        bool reload_if_possible = false;
+
+        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 (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "TryRestart"))
+                job_type = JOB_TRY_RESTART;
+        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) {
+                reload_if_possible = true;
+                job_type = JOB_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
+                reload_if_possible = true;
+                job_type = JOB_TRY_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) {
+                const char *swho, *smode;
+                int32_t signo;
+                KillMode mode;
+                KillWho who;
+                int r;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &swho,
+                                    DBUS_TYPE_STRING, &smode,
+                                    DBUS_TYPE_INT32, &signo,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (isempty(swho))
+                        who = KILL_ALL;
+                else {
+                        who = kill_who_from_string(swho);
+                        if (who < 0)
+                                return bus_send_error_reply(connection, message, &error, -EINVAL);
+                }
+
+                if (isempty(smode))
+                        mode = KILL_CONTROL_GROUP;
+                else {
+                        mode = kill_mode_from_string(smode);
+                        if (mode < 0)
+                                return bus_send_error_reply(connection, message, &error, -EINVAL);
+                }
+
+                if (signo <= 0 || signo >= _NSIG)
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) {
+
+                unit_reset_failed(u);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (UNIT_VTABLE(u)->bus_message_handler)
+                return UNIT_VTABLE(u)->bus_message_handler(u, connection, message);
+        else
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+        if (job_type != _JOB_TYPE_INVALID) {
+                const char *smode;
+                JobMode mode;
+                Job *j;
+                int r;
+
+                if ((job_type == JOB_START && u->refuse_manual_start) ||
+                    (job_type == JOB_STOP && u->refuse_manual_stop) ||
+                    ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
+                     (u->refuse_manual_start || u->refuse_manual_stop))) {
+                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
+                        return bus_send_error_reply(connection, message, &error, -EPERM);
+                }
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &smode,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (reload_if_possible && unit_can_reload(u)) {
+                        if (job_type == JOB_RESTART)
+                                job_type = JOB_RELOAD_OR_START;
+                        else if (job_type == JOB_TRY_RESTART)
+                                job_type = JOB_RELOAD;
+                }
+
+                if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
+                        dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+                }
+
+                if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
+                        return bus_send_error_reply(connection, message, &error, 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(connection, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        free(path);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        free(path);
+
+        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;
+        DBusMessage *reply;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) {
+                /* Be nice to gdbus and return introspection data for our mid-level paths */
+
+                if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+                        char *introspection = NULL;
+                        FILE *f;
+                        Iterator i;
+                        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(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+                              "<node>\n", f);
+
+                        fputs(BUS_INTROSPECTABLE_INTERFACE, f);
+                        fputs(BUS_PEER_INTERFACE, f);
+
+                        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+                                char *p;
+
+                                if (k != u->id)
+                                        continue;
+
+                                if (!(p = bus_path_escape(k))) {
+                                        fclose(f);
+                                        free(introspection);
+                                        goto oom;
+                                }
+
+                                fprintf(f, "<node name=\"%s\"/>", p);
+                                free(p);
+                        }
+
+                        fputs("</node>\n", 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);
+
+                        if (!dbus_connection_send(connection, reply, NULL))
+                                goto oom;
+
+                        dbus_message_unref(reply);
+
+                        return DBUS_HANDLER_RESULT_HANDLED;
+                }
+
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+
+        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) {
+                        DBusError e;
+
+                        dbus_error_init(&e);
+                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown unit");
+                        return bus_send_error_reply(connection, message, &e, r);
+                }
+
+                return bus_send_error_reply(connection, message, NULL, r);
+        }
+
+        return bus_unit_message_dispatch(u, connection, message);
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+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);
+
+        if (u->in_dbus_queue) {
+                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
+                u->in_dbus_queue = false;
+        }
+
+        if (!u->id)
+                return;
+
+        if (!bus_has_subscriber(u->manager)) {
+                u->sent_dbus_new_signal = true;
+                return;
+        }
+
+        if (!(p = unit_dbus_path(u)))
+                goto oom;
+
+        if (u->sent_dbus_new_signal) {
+                /* Send a properties changed signal. First for the
+                 * specific type, then for the generic unit. The
+                 * clients may rely on this order to get atomic
+                 * behaviour if needed. */
+
+                if (UNIT_VTABLE(u)->bus_invalidating_properties) {
+
+                        if (!(m = bus_properties_changed_new(p,
+                                                             UNIT_VTABLE(u)->bus_interface,
+                                                             UNIT_VTABLE(u)->bus_invalidating_properties)))
+                                goto oom;
+
+                        if (bus_broadcast(u->manager, m) < 0)
+                                goto oom;
+
+                        dbus_message_unref(m);
+                }
+
+                if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", INVALIDATING_PROPERTIES)))
+                        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->id,
+                                              DBUS_TYPE_OBJECT_PATH, &p,
+                                              DBUS_TYPE_INVALID))
+                        goto oom;
+        }
+
+        if (bus_broadcast(u->manager, m) < 0)
+                goto oom;
+
+        free(p);
+        dbus_message_unref(m);
+
+        u->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 (!bus_has_subscriber(u->manager))
+                return;
+
+        if (!u->sent_dbus_new_signal)
+                bus_unit_send_change_signal(u);
+
+        if (!u->id)
+                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->id,
+                                      DBUS_TYPE_OBJECT_PATH, &p,
+                                      DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (bus_broadcast(u->manager, m) < 0)
+                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.");
+}
+
+const BusProperty bus_unit_properties[] = {
+        { "Id",                   bus_property_append_string,         "s", offsetof(Unit, id),                                         true },
+        { "Names",                bus_unit_append_names,             "as", 0 },
+        { "Following",            bus_unit_append_following,          "s", 0 },
+        { "Requires",             bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRES]),                true },
+        { "RequiresOverridable",  bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]),    true },
+        { "Requisite",            bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUISITE]),               true },
+        { "RequisiteOverridable", bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]),   true },
+        { "Wants",                bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_WANTS]),                   true },
+        { "BindTo",               bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_BIND_TO]),                 true },
+        { "RequiredBy",           bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY]),             true },
+        { "RequiredByOverridable",bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), true },
+        { "WantedBy",             bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_WANTED_BY]),               true },
+        { "BoundBy",              bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_BOUND_BY]),                true },
+        { "Conflicts",            bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_CONFLICTS]),               true },
+        { "ConflictedBy",         bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]),           true },
+        { "Before",               bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_BEFORE]),                  true },
+        { "After",                bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_AFTER]),                   true },
+        { "OnFailure",            bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_ON_FAILURE]),              true },
+        { "Triggers",             bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_TRIGGERS]),                true },
+        { "TriggeredBy",          bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]),            true },
+        { "PropagateReloadTo",    bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_TO]),     true },
+        { "PropagateReloadFrom",  bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_FROM]),   true },
+        { "Description",          bus_unit_append_description,        "s", 0 },
+        { "LoadState",            bus_unit_append_load_state,         "s", offsetof(Unit, load_state)                         },
+        { "ActiveState",          bus_unit_append_active_state,       "s", 0 },
+        { "SubState",             bus_unit_append_sub_state,          "s", 0 },
+        { "FragmentPath",         bus_property_append_string,         "s", offsetof(Unit, fragment_path),                              true },
+        { "UnitFileState",        bus_unit_append_file_state,         "s", 0 },
+        { "InactiveExitTimestamp",bus_property_append_usec,           "t", offsetof(Unit, inactive_exit_timestamp.realtime)   },
+        { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic)  },
+        { "ActiveEnterTimestamp", bus_property_append_usec,           "t", offsetof(Unit, active_enter_timestamp.realtime)    },
+        { "ActiveEnterTimestampMonotonic", bus_property_append_usec,  "t", offsetof(Unit, active_enter_timestamp.monotonic)   },
+        { "ActiveExitTimestamp",  bus_property_append_usec,           "t", offsetof(Unit, active_exit_timestamp.realtime)     },
+        { "ActiveExitTimestampMonotonic",  bus_property_append_usec,  "t", offsetof(Unit, active_exit_timestamp.monotonic)    },
+        { "InactiveEnterTimestamp", bus_property_append_usec,         "t", offsetof(Unit, inactive_enter_timestamp.realtime)  },
+        { "InactiveEnterTimestampMonotonic",bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.monotonic) },
+        { "CanStart",             bus_unit_append_can_start,          "b", 0 },
+        { "CanStop",              bus_unit_append_can_stop,           "b", 0 },
+        { "CanReload",            bus_unit_append_can_reload,         "b", 0 },
+        { "CanIsolate",           bus_unit_append_can_isolate,        "b", 0 },
+        { "Job",                  bus_unit_append_job,             "(uo)", 0 },
+        { "StopWhenUnneeded",     bus_property_append_bool,           "b", offsetof(Unit, stop_when_unneeded)                 },
+        { "RefuseManualStart",    bus_property_append_bool,           "b", offsetof(Unit, refuse_manual_start)                },
+        { "RefuseManualStop",     bus_property_append_bool,           "b", offsetof(Unit, refuse_manual_stop)                 },
+        { "AllowIsolate",         bus_property_append_bool,           "b", offsetof(Unit, allow_isolate)                      },
+        { "DefaultDependencies",  bus_property_append_bool,           "b", offsetof(Unit, default_dependencies)               },
+        { "OnFailureIsolate",     bus_property_append_bool,           "b", offsetof(Unit, on_failure_isolate)                 },
+        { "IgnoreOnIsolate",      bus_property_append_bool,           "b", offsetof(Unit, ignore_on_isolate)                  },
+        { "IgnoreOnSnapshot",     bus_property_append_bool,           "b", offsetof(Unit, ignore_on_snapshot)                 },
+        { "DefaultControlGroup",  bus_unit_append_default_cgroup,     "s", 0 },
+        { "ControlGroup",         bus_unit_append_cgroups,           "as", 0 },
+        { "ControlGroupAttributes", bus_unit_append_cgroup_attrs,"a(sss)", 0 },
+        { "NeedDaemonReload",     bus_unit_append_need_daemon_reload, "b", 0 },
+        { "JobTimeoutUSec",       bus_property_append_usec,           "t", offsetof(Unit, job_timeout)                        },
+        { "ConditionTimestamp",   bus_property_append_usec,           "t", offsetof(Unit, condition_timestamp.realtime)       },
+        { "ConditionTimestampMonotonic", bus_property_append_usec,    "t", offsetof(Unit, condition_timestamp.monotonic)      },
+        { "ConditionResult",      bus_property_append_bool,           "b", offsetof(Unit, condition_result)                   },
+        { "LoadError",            bus_unit_append_load_error,      "(ss)", 0 },
+        { NULL, }
+};
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
new file mode 100644
index 0000000..4f19a80
--- /dev/null
+++ b/src/core/dbus-unit.h
@@ -0,0 +1,139 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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"
+#include "dbus-common.h"
+
+#define BUS_UNIT_INTERFACE \
+        " <interface name=\"org.freedesktop.systemd1.Unit\">\n"         \
+        "  <method name=\"Start\">\n"                                   \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"Stop\">\n"                                    \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"Reload\">\n"                                  \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"Restart\">\n"                                 \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"TryRestart\">\n"                              \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ReloadOrRestart\">\n"                         \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"ReloadOrTryRestart\">\n"                      \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"Kill\">\n"                                    \
+        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"ResetFailed\"/>\n"                            \
+        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
+        "  <property name=\"Names\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"Following\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Requires\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"RequiresOverridable\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"Requisite\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"RequisiteOverridable\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"Wants\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"BindTo\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"RequiredBy\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"RequiredByOverridable\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"WantedBy\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"BoundBy\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"Conflicts\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ConflictedBy\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"Before\" type=\"as\" access=\"read\"/>\n"   \
+        "  <property name=\"After\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"OnFailure\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"Triggers\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"TriggeredBy\" type=\"as\" access=\"read\"/>\n"    \
+        "  <property name=\"PropagateReloadTo\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"PropagateReloadFrom\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"Description\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"LoadState\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"ActiveState\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"SubState\" type=\"s\" access=\"read\"/>\n"  \
+        "  <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"UnitFileState\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"InactiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ActiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ActiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"InactiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n"   \
+        "  <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"CanIsolate\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n"    \
+        "  <property name=\"StopWhenUnneeded\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"AllowIsolate\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"OnFailureIsolate\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"IgnoreOnIsolate\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"IgnoreOnSnapshot\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"ControlGroup\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ControlGroupAttributes\" type=\"a(sss)\" access=\"read\"/>\n" \
+        "  <property name=\"NeedDaemonReload\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"JobTimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ConditionTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ConditionTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"LoadError\" type=\"(ss)\" access=\"read\"/>\n" \
+        " </interface>\n"
+
+#define BUS_UNIT_INTERFACES_LIST                \
+        BUS_GENERIC_INTERFACES_LIST             \
+        "org.freedesktop.systemd1.Unit\0"
+
+extern const BusProperty bus_unit_properties[];
+
+void bus_unit_send_change_signal(Unit *u);
+void bus_unit_send_removed_signal(Unit *u);
+
+extern const DBusObjectPathVTable bus_unit_vtable;
+
+extern const char bus_unit_interface[];
+
+#endif
diff --git a/src/core/dbus.c b/src/core/dbus.c
new file mode 100644
index 0000000..ddf91f2
--- /dev/null
+++ b/src/core/dbus.c
@@ -0,0 +1,1483 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 "mkdir.h"
+#include "dbus-unit.h"
+#include "dbus-job.h"
+#include "dbus-manager.h"
+#include "dbus-service.h"
+#include "dbus-socket.h"
+#include "dbus-target.h"
+#include "dbus-device.h"
+#include "dbus-mount.h"
+#include "dbus-automount.h"
+#include "dbus-snapshot.h"
+#include "dbus-swap.h"
+#include "dbus-timer.h"
+#include "dbus-path.h"
+#include "bus-errors.h"
+#include "special.h"
+#include "dbus-common.h"
+
+#define CONNECTIONS_MAX 52
+
+/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
+#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
+/* Only used as a fallback */
+#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
+
+static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
+static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
+
+const char *const bus_interface_table[] = {
+        "org.freedesktop.DBus.Properties",     bus_properties_interface,
+        "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
+        "org.freedesktop.systemd1.Manager",    bus_manager_interface,
+        "org.freedesktop.systemd1.Job",        bus_job_interface,
+        "org.freedesktop.systemd1.Unit",       bus_unit_interface,
+        "org.freedesktop.systemd1.Service",    bus_service_interface,
+        "org.freedesktop.systemd1.Socket",     bus_socket_interface,
+        "org.freedesktop.systemd1.Target",     bus_target_interface,
+        "org.freedesktop.systemd1.Device",     bus_device_interface,
+        "org.freedesktop.systemd1.Mount",      bus_mount_interface,
+        "org.freedesktop.systemd1.Automount",  bus_automount_interface,
+        "org.freedesktop.systemd1.Snapshot",   bus_snapshot_interface,
+        "org.freedesktop.systemd1.Swap",       bus_swap_interface,
+        "org.freedesktop.systemd1.Timer",      bus_timer_interface,
+        "org.freedesktop.systemd1.Path",       bus_path_interface,
+        NULL
+};
+
+static void bus_done_api(Manager *m);
+static void bus_done_system(Manager *m);
+static void bus_done_private(Manager *m);
+static void shutdown_connection(Manager *m, DBusConnection *c);
+
+static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
+        Manager *m = data;
+
+        assert(bus);
+        assert(m);
+
+        /* We maintain two sets, one for those connections where we
+         * requested a dispatch, and another where we didn't. And then,
+         * we move the connections between the two sets. */
+
+        if (status == DBUS_DISPATCH_COMPLETE)
+                set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
+        else
+                set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
+}
+
+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, bus_events_to_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) {
+                        close_nointr_nofail(w->fd);
+                        free(w);
+                        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);
+
+        w = dbus_watch_get_data(bus_watch);
+        if (!w)
+                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);
+
+        w = dbus_watch_get_data(bus_watch);
+        if (!w)
+                return;
+
+        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_value;
+        }
+
+        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);
+
+        w = dbus_timeout_get_data(timeout);
+        if (!w)
+                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);
+
+        w = dbus_timeout_get_data(timeout);
+        if (!w)
+                return;
+
+        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;
+        DBusMessage *reply = NULL;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
+            dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
+                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_debug("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", bus_error_message(&error));
+                else  {
+                        if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
+                                log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
+
+                        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);
+                }
+        } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
+                const char *name;
+
+                if (!dbus_message_get_args(message, &error,
+                                           DBUS_TYPE_STRING, &name,
+                                           DBUS_TYPE_INVALID))
+                        log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
+                else  {
+                        int r;
+                        Unit *u;
+
+                        log_debug("Got D-Bus activation request for %s", name);
+
+                        if (manager_unit_pending_inactive(m, SPECIAL_DBUS_SERVICE) ||
+                            manager_unit_pending_inactive(m, SPECIAL_DBUS_SOCKET)) {
+                                r = -EADDRNOTAVAIL;
+                                dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
+                        } else {
+                                r = manager_load_unit(m, name, NULL, &error, &u);
+
+                                if (r >= 0 && u->refuse_manual_start)
+                                        r = -EPERM;
+
+                                if (r >= 0)
+                                        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
+                        }
+
+                        if (r < 0) {
+                                const char *id, *text;
+
+                                log_debug("D-Bus activation failed for %s: %s", name, strerror(-r));
+
+                                if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
+                                        goto oom;
+
+                                id = error.name ? error.name : bus_errno_to_dbus(r);
+                                text = bus_error(&error, r);
+
+                                if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
+                                    !dbus_message_append_args(reply,
+                                                              DBUS_TYPE_STRING, &name,
+                                                              DBUS_TYPE_STRING, &id,
+                                                              DBUS_TYPE_STRING, &text,
+                                                              DBUS_TYPE_INVALID))
+                                        goto oom;
+                        }
+
+                        /* On success we don't do anything, the service will be spawned now */
+                }
+        }
+
+        dbus_error_free(&error);
+
+        if (reply) {
+                if (!dbus_connection_send(connection, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        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 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);
+
+        if (m->api_bus != m->system_bus &&
+            (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
+             dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL))
+                log_debug("Got D-Bus request on system bus: %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_debug("System D-Bus connection terminated.");
+                bus_done_system(m);
+
+        } else if (m->running_as != MANAGER_SYSTEM &&
+                   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", bus_error_message(&error));
+                else
+                        cgroup_notify_empty(m, cgroup);
+        }
+
+        dbus_error_free(&error);
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
+        Manager *m = data;
+        DBusError error;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
+            dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
+                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"))
+                shutdown_connection(m, connection);
+        else if (m->running_as == MANAGER_SYSTEM &&
+                 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", bus_error_message(&error));
+                else
+                        cgroup_notify_empty(m, cgroup);
+
+                /* Forward the message to the system bus, so that user
+                 * instances are notified as well */
+
+                if (m->system_bus)
+                        dbus_connection_send(m->system_bus, message, NULL);
+        }
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+unsigned bus_dispatch(Manager *m) {
+        DBusConnection *c;
+
+        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 (m->queued_message_connection)
+                        if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL))
+                                return 0;
+
+                dbus_message_unref(m->queued_message);
+                m->queued_message = NULL;
+                m->queued_message_connection = NULL;
+        }
+
+        if ((c = set_first(m->bus_connections_for_dispatch))) {
+                if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE)
+                        set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c);
+
+                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", bus_error_message(&error));
+                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", bus_error_message(&error));
+                        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";
+        /* Allow replacing of our name, to ease implementation of
+         * reexecution, where we keep the old connection open until
+         * after the new connection is set up and the name installed
+         * to allow clients to synchronously wait for reexecution to
+         * finish */
+        uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
+        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 void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
+        DBusMessage *reply;
+        DBusError error;
+        Manager *m = userdata;
+
+        assert(m);
+
+        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("ListNames() failed: %s", bus_error_message(&error));
+                break;
+
+        case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
+                int r;
+                char **l;
+
+                if ((r = bus_parse_strv(reply, &l)) < 0)
+                        log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
+                else {
+                        char **t;
+
+                        STRV_FOREACH(t, l)
+                                /* This is a bit hacky, we say the
+                                 * owner of the name is the name
+                                 * itself, because we don't want the
+                                 * extra traffic to figure out the
+                                 * real owner. */
+                                manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
+
+                        strv_free(l);
+                }
+
+                break;
+        }
+
+        default:
+                assert_not_reached("Invalid reply message");
+        }
+
+        dbus_message_unref(reply);
+        dbus_error_free(&error);
+}
+
+static int query_name_list(Manager *m) {
+        DBusMessage *message = NULL;
+        DBusPendingCall *pending = NULL;
+
+        /* Asks for the currently installed bus names */
+
+        if (!(message = dbus_message_new_method_call(
+                              DBUS_SERVICE_DBUS,
+                              DBUS_PATH_DBUS,
+                              DBUS_INTERFACE_DBUS,
+                              "ListNames")))
+                goto oom;
+
+        if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
+                goto oom;
+
+        if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
+                goto oom;
+
+        dbus_message_unref(message);
+        dbus_pending_call_unref(pending);
+
+        /* We simple ask for the list and don't wait for it. Sooner or
+         * later we'll get 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)) {
+                log_error("Not enough memory");
+                return -ENOMEM;
+        }
+
+        if (set_put(m->bus_connections_for_dispatch, bus) < 0) {
+                log_error("Not enough memory");
+                return -ENOMEM;
+        }
+
+        dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL);
+        return 0;
+}
+
+static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
+        return uid == 0 || uid == geteuid();
+}
+
+static void bus_new_connection(
+                DBusServer *server,
+                DBusConnection *new_connection,
+                void *data) {
+
+        Manager *m = data;
+
+        assert(m);
+
+        if (set_size(m->bus_connections) >= CONNECTIONS_MAX) {
+                log_error("Too many concurrent connections.");
+                return;
+        }
+
+        dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
+
+        if (bus_setup_loop(m, new_connection) < 0)
+                return;
+
+        if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
+            !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
+            !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
+            !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) {
+                log_error("Not enough memory.");
+                return;
+        }
+
+        log_debug("Accepted connection on private bus.");
+
+        dbus_connection_ref(new_connection);
+}
+
+static int init_registered_system_bus(Manager *m) {
+        char *id;
+
+        if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
+                log_error("Not enough memory");
+                return -ENOMEM;
+        }
+
+        if (m->running_as != MANAGER_SYSTEM) {
+                DBusError error;
+
+                dbus_error_init(&error);
+
+                dbus_bus_add_match(m->system_bus,
+                                   "type='signal',"
+                                   "interface='org.freedesktop.systemd1.Agent',"
+                                   "member='Released',"
+                                   "path='/org/freedesktop/systemd1/agent'",
+                                   &error);
+
+                if (dbus_error_is_set(&error)) {
+                        log_error("Failed to register match: %s", bus_error_message(&error));
+                        dbus_error_free(&error);
+                        return -1;
+                }
+        }
+
+        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;
+}
+
+static int init_registered_api_bus(Manager *m) {
+        int 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)) {
+                log_error("Not enough memory");
+                return -ENOMEM;
+        }
+
+        /* Get NameOwnerChange messages */
+        dbus_bus_add_match(m->api_bus,
+                           "type='signal',"
+                           "sender='"DBUS_SERVICE_DBUS"',"
+                           "interface='"DBUS_INTERFACE_DBUS"',"
+                           "member='NameOwnerChanged',"
+                           "path='"DBUS_PATH_DBUS"'",
+                           NULL);
+
+        /* Get activation requests */
+        dbus_bus_add_match(m->api_bus,
+                           "type='signal',"
+                           "sender='"DBUS_SERVICE_DBUS"',"
+                           "interface='org.freedesktop.systemd1.Activator',"
+                           "member='ActivationRequest',"
+                           "path='"DBUS_PATH_DBUS"'",
+                           NULL);
+
+        r = request_name(m);
+        if (r < 0)
+                return r;
+
+        r = query_name_list(m);
+        if (r < 0)
+                return r;
+
+        if (m->running_as == MANAGER_USER) {
+                char *id;
+                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);
+        } else
+                log_debug("Successfully initialized API on the system bus");
+
+        return 0;
+}
+
+static void bus_register_cb(DBusPendingCall *pending, void *userdata) {
+        Manager *m = userdata;
+        DBusConnection **conn;
+        DBusMessage *reply;
+        DBusError error;
+        const char *name;
+        int r = 0;
+
+        dbus_error_init(&error);
+
+        conn = dbus_pending_call_get_data(pending, m->conn_data_slot);
+        assert(conn == &m->system_bus || conn == &m->api_bus);
+
+        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("Failed to register to bus: %s", bus_error_message(&error));
+                r = -1;
+                break;
+        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+                if (!dbus_message_get_args(reply, &error,
+                                           DBUS_TYPE_STRING, &name,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse Hello reply: %s", bus_error_message(&error));
+                        r = -1;
+                        break;
+                }
+
+                log_debug("Received name %s in reply to Hello", name);
+                if (!dbus_bus_set_unique_name(*conn, name)) {
+                        log_error("Failed to set unique name");
+                        r = -1;
+                        break;
+                }
+
+                if (conn == &m->system_bus) {
+                        r = init_registered_system_bus(m);
+                        if (r == 0 && m->running_as == MANAGER_SYSTEM)
+                                r = init_registered_api_bus(m);
+                } else
+                        r = init_registered_api_bus(m);
+
+                break;
+        default:
+                assert_not_reached("Invalid reply message");
+        }
+
+        dbus_message_unref(reply);
+        dbus_error_free(&error);
+
+        if (r < 0) {
+                if (conn == &m->system_bus) {
+                        log_debug("Failed setting up the system bus");
+                        bus_done_system(m);
+                } else {
+                        log_debug("Failed setting up the API bus");
+                        bus_done_api(m);
+                }
+        }
+}
+
+static int manager_bus_async_register(Manager *m, DBusConnection **conn) {
+        DBusMessage *message = NULL;
+        DBusPendingCall *pending = NULL;
+
+        message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+                                               DBUS_PATH_DBUS,
+                                               DBUS_INTERFACE_DBUS,
+                                               "Hello");
+        if (!message)
+                goto oom;
+
+        if (!dbus_connection_send_with_reply(*conn, message, &pending, -1))
+                goto oom;
+
+        if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL))
+                goto oom;
+
+        if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL))
+                goto oom;
+
+        dbus_message_unref(message);
+        dbus_pending_call_unref(pending);
+
+        return 0;
+oom:
+        if (pending) {
+                dbus_pending_call_cancel(pending);
+                dbus_pending_call_unref(pending);
+        }
+
+        if (message)
+                dbus_message_unref(message);
+
+        return -ENOMEM;
+}
+
+static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) {
+        const char *address;
+        DBusConnection *connection;
+        DBusError error;
+
+        switch (type) {
+        case DBUS_BUS_SYSTEM:
+                address = getenv("DBUS_SYSTEM_BUS_ADDRESS");
+                if (!address || !address[0])
+                        address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
+                break;
+        case DBUS_BUS_SESSION:
+                address = getenv("DBUS_SESSION_BUS_ADDRESS");
+                if (!address || !address[0])
+                        address = DBUS_SESSION_BUS_DEFAULT_ADDRESS;
+                break;
+        default:
+                assert_not_reached("Invalid bus type");
+        }
+
+        dbus_error_init(&error);
+
+        connection = dbus_connection_open_private(address, &error);
+        if (!connection) {
+                log_warning("Failed to open private bus connection: %s", bus_error_message(&error));
+                goto fail;
+        }
+
+        return connection;
+fail:
+        if (connection)
+                dbus_connection_close(connection);
+        dbus_error_free(&error);
+        return NULL;
+}
+
+static int bus_init_system(Manager *m) {
+        int r;
+
+        if (m->system_bus)
+                return 0;
+
+        m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM);
+        if (!m->system_bus) {
+                log_debug("Failed to connect to system D-Bus, retrying later");
+                r = 0;
+                goto fail;
+        }
+
+        r = bus_setup_loop(m, m->system_bus);
+        if (r < 0)
+                goto fail;
+
+        r = manager_bus_async_register(m, &m->system_bus);
+        if (r < 0)
+                goto fail;
+
+        return 0;
+fail:
+        bus_done_system(m);
+
+        return r;
+}
+
+static int bus_init_api(Manager *m) {
+        int r;
+
+        if (m->api_bus)
+                return 0;
+
+        if (m->running_as == MANAGER_SYSTEM) {
+                m->api_bus = m->system_bus;
+                /* In this mode there is no distinct connection to the API bus,
+                 * the API is published on the system bus.
+                 * bus_register_cb() is aware of that and will init the API
+                 * when the system bus gets registered.
+                 * No need to setup anything here. */
+                return 0;
+        }
+
+        m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION);
+        if (!m->api_bus) {
+                log_debug("Failed to connect to API D-Bus, retrying later");
+                r = 0;
+                goto fail;
+        }
+
+        r = bus_setup_loop(m, m->api_bus);
+        if (r < 0)
+                goto fail;
+
+        r = manager_bus_async_register(m, &m->api_bus);
+        if (r < 0)
+                goto fail;
+
+        return 0;
+fail:
+        bus_done_api(m);
+
+        return r;
+}
+
+static int bus_init_private(Manager *m) {
+        DBusError error;
+        int r;
+        const char *const external_only[] = {
+                "EXTERNAL",
+                NULL
+        };
+
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (m->private_bus)
+                return 0;
+
+        if (m->running_as == MANAGER_SYSTEM) {
+
+                /* We want the private bus only when running as init */
+                if (getpid() != 1)
+                        return 0;
+
+                unlink("/run/systemd/private");
+                m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
+        } else {
+                const char *e;
+                char *p;
+
+                e = getenv("XDG_RUNTIME_DIR");
+                if (!e)
+                        return 0;
+
+                if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) {
+                        log_error("Not enough memory");
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                mkdir_parents(p+10, 0755);
+                unlink(p+10);
+                m->private_bus = dbus_server_listen(p, &error);
+                free(p);
+        }
+
+        if (!m->private_bus) {
+                log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
+                r = -EIO;
+                goto fail;
+        }
+
+        if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) ||
+            !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
+            !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
+                log_error("Not enough memory");
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL);
+
+        log_debug("Successfully created private D-Bus server.");
+
+        return 0;
+
+fail:
+        bus_done_private(m);
+        dbus_error_free(&error);
+
+        return r;
+}
+
+int bus_init(Manager *m, bool try_bus_connect) {
+        int r;
+
+        if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
+            set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
+                goto oom;
+
+        if (m->name_data_slot < 0)
+                if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
+                        goto oom;
+
+        if (m->conn_data_slot < 0)
+                if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot))
+                        goto oom;
+
+        if (m->subscribed_data_slot < 0)
+                if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot))
+                        goto oom;
+
+        if (try_bus_connect) {
+                if ((r = bus_init_system(m)) < 0 ||
+                    (r = bus_init_api(m)) < 0)
+                        return r;
+        }
+
+        if ((r = bus_init_private(m)) < 0)
+                return r;
+
+        return 0;
+oom:
+        log_error("Not enough memory");
+        return -ENOMEM;
+}
+
+static void shutdown_connection(Manager *m, DBusConnection *c) {
+        Set *s;
+        Job *j;
+        Iterator i;
+
+        HASHMAP_FOREACH(j, m->jobs, i)
+                if (j->bus == c) {
+                        free(j->bus_client);
+                        j->bus_client = NULL;
+
+                        j->bus = NULL;
+                }
+
+        set_remove(m->bus_connections, c);
+        set_remove(m->bus_connections_for_dispatch, c);
+
+        if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
+                char *t;
+
+                while ((t = set_steal_first(s)))
+                        free(t);
+
+                set_free(s);
+        }
+
+        if (m->queued_message_connection == c) {
+                m->queued_message_connection = NULL;
+
+                if (m->queued_message) {
+                        dbus_message_unref(m->queued_message);
+                        m->queued_message = NULL;
+                }
+        }
+
+        dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
+        /* system manager cannot afford to block on DBus */
+        if (m->running_as != MANAGER_SYSTEM)
+                dbus_connection_flush(c);
+        dbus_connection_close(c);
+        dbus_connection_unref(c);
+}
+
+static void bus_done_api(Manager *m) {
+        if (!m->api_bus)
+                return;
+
+        if (m->running_as == MANAGER_USER)
+                shutdown_connection(m, m->api_bus);
+
+        m->api_bus = NULL;
+
+        if (m->queued_message) {
+                dbus_message_unref(m->queued_message);
+                m->queued_message = NULL;
+        }
+}
+
+static void bus_done_system(Manager *m) {
+        if (!m->system_bus)
+                return;
+
+        if (m->running_as == MANAGER_SYSTEM)
+                bus_done_api(m);
+
+        shutdown_connection(m, m->system_bus);
+        m->system_bus = NULL;
+}
+
+static void bus_done_private(Manager *m) {
+        if (!m->private_bus)
+                return;
+
+        dbus_server_disconnect(m->private_bus);
+        dbus_server_unref(m->private_bus);
+        m->private_bus = NULL;
+}
+
+void bus_done(Manager *m) {
+        DBusConnection *c;
+
+        bus_done_api(m);
+        bus_done_system(m);
+        bus_done_private(m);
+
+        while ((c = set_steal_first(m->bus_connections)))
+                shutdown_connection(m, c);
+
+        while ((c = set_steal_first(m->bus_connections_for_dispatch)))
+                shutdown_connection(m, c);
+
+        set_free(m->bus_connections);
+        set_free(m->bus_connections_for_dispatch);
+
+        if (m->name_data_slot >= 0)
+               dbus_pending_call_free_data_slot(&m->name_data_slot);
+
+        if (m->conn_data_slot >= 0)
+               dbus_pending_call_free_data_slot(&m->conn_data_slot);
+
+        if (m->subscribed_data_slot >= 0)
+                dbus_connection_free_data_slot(&m->subscribed_data_slot);
+}
+
+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 = BUS_PENDING_CALL_NAME(m, pending));
+        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", bus_error_message(&error));
+                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", bus_error_message(&error));
+                        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;
+}
+
+int bus_broadcast(Manager *m, DBusMessage *message) {
+        bool oom = false;
+        Iterator i;
+        DBusConnection *c;
+
+        assert(m);
+        assert(message);
+
+        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
+                if (c != m->system_bus || m->running_as == MANAGER_SYSTEM)
+                        oom = !dbus_connection_send(c, message, NULL);
+
+        SET_FOREACH(c, m->bus_connections, i)
+                if (c != m->system_bus || m->running_as == MANAGER_SYSTEM)
+                        oom = !dbus_connection_send(c, message, NULL);
+
+        return oom ? -ENOMEM : 0;
+}
+
+bool bus_has_subscriber(Manager *m) {
+        Iterator i;
+        DBusConnection *c;
+
+        assert(m);
+
+        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
+                if (bus_connection_has_subscriber(m, c))
+                        return true;
+
+        SET_FOREACH(c, m->bus_connections, i)
+                if (bus_connection_has_subscriber(m, c))
+                        return true;
+
+        return false;
+}
+
+bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
+        assert(m);
+        assert(c);
+
+        return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
+}
+
+int bus_fdset_add_all(Manager *m, FDSet *fds) {
+        Iterator i;
+        DBusConnection *c;
+
+        assert(m);
+        assert(fds);
+
+        /* When we are about to reexecute we add all D-Bus fds to the
+         * set to pass over to the newly executed systemd. They won't
+         * be used there however, except that they are closed at the
+         * very end of deserialization, those making it possible for
+         * clients to synchronously wait for systemd to reexec by
+         * simply waiting for disconnection */
+
+        SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
+                int fd;
+
+                if (dbus_connection_get_unix_fd(c, &fd)) {
+                        fd = fdset_put_dup(fds, fd);
+
+                        if (fd < 0)
+                                return fd;
+                }
+        }
+
+        SET_FOREACH(c, m->bus_connections, i) {
+                int fd;
+
+                if (dbus_connection_get_unix_fd(c, &fd)) {
+                        fd = fdset_put_dup(fds, fd);
+
+                        if (fd < 0)
+                                return fd;
+                }
+        }
+
+        return 0;
+}
+
+void bus_broadcast_finished(
+                Manager *m,
+                usec_t kernel_usec,
+                usec_t initrd_usec,
+                usec_t userspace_usec,
+                usec_t total_usec) {
+
+        DBusMessage *message;
+
+        assert(m);
+
+        message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
+        if (!message) {
+                log_error("Out of memory.");
+                return;
+        }
+
+        assert_cc(sizeof(usec_t) == sizeof(uint64_t));
+        if (!dbus_message_append_args(message,
+                                      DBUS_TYPE_UINT64, &kernel_usec,
+                                      DBUS_TYPE_UINT64, &initrd_usec,
+                                      DBUS_TYPE_UINT64, &userspace_usec,
+                                      DBUS_TYPE_UINT64, &total_usec,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Out of memory.");
+                goto finish;
+        }
+
+
+        if (bus_broadcast(m, message) < 0) {
+                log_error("Out of memory.");
+                goto finish;
+        }
+
+finish:
+        if (message)
+                dbus_message_unref(message);
+}
diff --git a/src/core/dbus.h b/src/core/dbus.h
new file mode 100644
index 0000000..bd539d0
--- /dev/null
+++ b/src/core/dbus.h
@@ -0,0 +1,53 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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"
+
+int bus_init(Manager *m, bool try_bus_connect);
+void bus_done(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);
+
+int bus_broadcast(Manager *m, DBusMessage *message);
+
+bool bus_has_subscriber(Manager *m);
+bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
+
+int bus_fdset_add_all(Manager *m, FDSet *fds);
+
+void bus_broadcast_finished(Manager *m, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec);
+
+#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot)
+#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot)
+
+extern const char * const bus_interface_table[];
+
+#endif
diff --git a/src/core/device.c b/src/core/device.c
new file mode 100644
index 0000000..0575379
--- /dev/null
+++ b/src/core/device.c
@@ -0,0 +1,616 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "def.h"
+
+static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
+        [DEVICE_DEAD] = UNIT_INACTIVE,
+        [DEVICE_PLUGGED] = UNIT_ACTIVE
+};
+
+static void device_unset_sysfs(Device *d) {
+        Device *first;
+
+        assert(d);
+
+        if (!d->sysfs)
+                return;
+
+        /* Remove this unit from the chain of devices which share the
+         * same sysfs path. */
+        first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
+        LIST_REMOVE(Device, same_sysfs, first, d);
+
+        if (first)
+                hashmap_remove_and_replace(UNIT(d)->manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
+        else
+                hashmap_remove(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
+
+        free(d->sysfs);
+        d->sysfs = NULL;
+}
+
+static void device_init(Unit *u) {
+        Device *d = DEVICE(u);
+
+        assert(d);
+        assert(UNIT(d)->load_state == UNIT_STUB);
+
+        /* In contrast to all other unit types we timeout jobs waiting
+         * for devices by default. This is because they otherwise wait
+         * indefinitely for plugged in devices, something which cannot
+         * happen for the other units since their operations time out
+         * anyway. */
+        UNIT(d)->job_timeout = DEFAULT_TIMEOUT_USEC;
+
+        UNIT(d)->ignore_on_isolate = true;
+        UNIT(d)->ignore_on_snapshot = true;
+}
+
+static void device_done(Unit *u) {
+        Device *d = DEVICE(u);
+
+        assert(d);
+
+        device_unset_sysfs(d);
+}
+
+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)->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], true);
+}
+
+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_PLUGGED);
+
+        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) {
+        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);
+        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_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
+        const char *sysfs, *model;
+        Unit *u = NULL;
+        int r;
+        bool delete;
+
+        assert(m);
+
+        if (!(sysfs = udev_device_get_syspath(dev)))
+                return -ENOMEM;
+
+        if ((r = device_find_escape_name(m, path, &u)) < 0)
+                return r;
+
+        if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
+                return -EEXIST;
+
+        if (!u) {
+                delete = true;
+
+                u = unit_new(m, sizeof(Device));
+                if (!u)
+                        return -ENOMEM;
+
+                r = device_add_escaped_name(u, path);
+                if (r < 0)
+                        goto fail;
+
+                unit_add_to_load_queue(u);
+        } else
+                delete = false;
+
+        /* If this was created via some dependency and has not
+         * actually been seen yet ->sysfs will not be
+         * initialized. Hence initialize it if necessary. */
+
+        if (!DEVICE(u)->sysfs) {
+                Device *first;
+
+                if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                if (!m->devices_by_sysfs)
+                        if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                first = hashmap_get(m->devices_by_sysfs, sysfs);
+                LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
+
+                if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 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 ((r = unit_set_description(u, path)) < 0)
+                        goto fail;
+
+        if (main) {
+                /* The additional systemd udev properties we only
+                 * interpret for the main object */
+                const char *wants, *alias;
+
+                if ((alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS"))) {
+                        if (!is_path(alias))
+                                log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, alias);
+                        else {
+                                if ((r = device_add_escaped_name(u, alias)) < 0)
+                                        goto fail;
+                        }
+                }
+
+                if ((wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"))) {
+                        char *state, *w;
+                        size_t l;
+
+                        FOREACH_WORD_QUOTED(w, l, wants, state) {
+                                char *e;
+
+                                if (!(e = strndup(w, l))) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true);
+                                free(e);
+
+                                if (r < 0)
+                                        goto fail;
+                        }
+                }
+        }
+
+        unit_add_to_dbus_queue(u);
+        return 0;
+
+fail:
+        log_warning("Failed to load device unit: %s", strerror(-r));
+
+        if (delete && u)
+                unit_free(u);
+
+        return r;
+}
+
+static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
+        const char *sysfs, *dn;
+        struct udev_list_entry *item = NULL, *first = NULL;
+
+        assert(m);
+
+        if (!(sysfs = udev_device_get_syspath(dev)))
+                return -ENOMEM;
+
+        /* Add the main unit named after the sysfs path */
+        device_update_unit(m, dev, sysfs, true);
+
+        /* Add an additional unit for the device node */
+        if ((dn = udev_device_get_devnode(dev)))
+                device_update_unit(m, dev, dn, false);
+
+        /* Add additional units for all symlinks */
+        first = udev_device_get_devlinks_list_entry(dev);
+        udev_list_entry_foreach(item, first) {
+                const char *p;
+                struct stat st;
+
+                /* Don't bother with the /dev/block links */
+                p = udev_list_entry_get_name(item);
+
+                if (path_startswith(p, "/dev/block/") ||
+                    path_startswith(p, "/dev/char/"))
+                        continue;
+
+                /* Verify that the symlink in the FS actually belongs
+                 * to this device. This is useful to deal with
+                 * conflicting devices, e.g. when two disks want the
+                 * same /dev/disk/by-label/xxx link because they have
+                 * the same label. We want to make sure that the same
+                 * device that won the symlink wins in systemd, so we
+                 * check the device node major/minor*/
+                if (stat(p, &st) >= 0)
+                        if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
+                            st.st_rdev != udev_device_get_devnum(dev))
+                                continue;
+
+                device_update_unit(m, dev, p, false);
+        }
+
+        if (update_state) {
+                Device *d, *l;
+
+                manager_dispatch_load_queue(m);
+
+                l = hashmap_get(m->devices_by_sysfs, sysfs);
+                LIST_FOREACH(same_sysfs, d, l)
+                        device_set_state(d, DEVICE_PLUGGED);
+        }
+
+        return 0;
+}
+
+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;
+        Device *d;
+
+        assert(m);
+        assert(dev);
+
+        if (!(sysfs = udev_device_get_syspath(dev)))
+                return -ENOMEM;
+
+        /* Remove all units of this sysfs path */
+        while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
+                device_unset_sysfs(d);
+                device_set_state(d, DEVICE_DEAD);
+        }
+
+        return 0;
+}
+
+static Unit *device_following(Unit *u) {
+        Device *d = DEVICE(u);
+        Device *other, *first = NULL;
+
+        assert(d);
+
+        if (startswith(u->id, "sys-"))
+                return NULL;
+
+        /* Make everybody follow the unit that's named after the sysfs path */
+        for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
+                if (startswith(UNIT(other)->id, "sys-"))
+                        return UNIT(other);
+
+        for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
+                if (startswith(UNIT(other)->id, "sys-"))
+                        return UNIT(other);
+
+                first = other;
+        }
+
+        return UNIT(first);
+}
+
+static int device_following_set(Unit *u, Set **_s) {
+        Device *d = DEVICE(u);
+        Device *other;
+        Set *s;
+        int r;
+
+        assert(d);
+        assert(_s);
+
+        if (!d->same_sysfs_prev && !d->same_sysfs_next) {
+                *_s = NULL;
+                return 0;
+        }
+
+        if (!(s = set_new(NULL, NULL)))
+                return -ENOMEM;
+
+        for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
+                if ((r = set_put(s, other)) < 0)
+                        goto fail;
+
+        for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
+                if ((r = set_put(s, other)) < 0)
+                        goto fail;
+
+        *_s = s;
+        return 1;
+
+fail:
+        set_free(s);
+        return r;
+}
+
+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;
+        }
+
+        hashmap_free(m->devices_by_sysfs);
+        m->devices_by_sysfs = 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;
+                }
+
+                /* This will fail if we are unprivileged, but that
+                 * should not matter much, as user instances won't run
+                 * during boot. */
+                udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
+
+                if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
+                        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_add_match_tag(e, "systemd") < 0) {
+                r = -EIO;
+                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, *ready;
+
+        assert(m);
+
+        if (events != EPOLLIN) {
+                static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
+
+                if (!ratelimit_test(&limit))
+                        log_error("Failed to get udev event: %m");
+                if (!(events & EPOLLIN))
+                        return;
+        }
+
+        if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
+                /*
+                 * libudev might filter-out devices which pass the bloom filter,
+                 * so getting NULL here is not necessarily an error
+                 */
+                return;
+        }
+
+        if (!(action = udev_device_get_action(dev))) {
+                log_error("Failed to get udev action string.");
+                goto fail;
+        }
+
+        ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
+
+        if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
+                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_PLUGGED] = "plugged"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
+
+const UnitVTable device_vtable = {
+        .suffix = ".device",
+        .object_size = sizeof(Device),
+        .sections =
+                "Unit\0"
+                "Device\0"
+                "Install\0",
+
+        .no_instances = true,
+
+        .init = device_init,
+
+        .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_interface = "org.freedesktop.systemd1.Device",
+        .bus_message_handler = bus_device_message_handler,
+        .bus_invalidating_properties =  bus_device_invalidating_properties,
+
+        .following = device_following,
+        .following_set = device_following_set,
+
+        .enumerate = device_enumerate,
+        .shutdown = device_shutdown
+};
diff --git a/src/core/device.h b/src/core/device.h
new file mode 100644
index 0000000..a05c3d3
--- /dev/null
+++ b/src/core/device.h
@@ -0,0 +1,59 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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_PLUGGED,
+        _DEVICE_STATE_MAX,
+        _DEVICE_STATE_INVALID = -1
+} DeviceState;
+
+struct Device {
+        Unit meta;
+
+        char *sysfs;
+
+        /* In order to be able to distinguish dependencies on
+        different device nodes we might end up creating multiple
+        devices for the same sysfs path. We chain them up here. */
+
+        LIST_FIELDS(struct Device, same_sysfs);
+
+        DeviceState state;
+};
+
+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/core/execute.c b/src/core/execute.c
new file mode 100644
index 0000000..179ca7e
--- /dev/null
+++ b/src/core/execute.c
@@ -0,0 +1,2113 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <linux/oom.h>
+
+#ifdef HAVE_PAM
+#include <security/pam_appl.h>
+#endif
+
+#include "execute.h"
+#include "strv.h"
+#include "macro.h"
+#include "capability.h"
+#include "util.h"
+#include "log.h"
+#include "ioprio.h"
+#include "securebits.h"
+#include "cgroup.h"
+#include "namespace.h"
+#include "tcpwrap.h"
+#include "exit-status.h"
+#include "missing.h"
+#include "utmp-wtmp.h"
+#include "def.h"
+#include "loopback-setup.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";
+}
+
+void exec_context_tty_reset(const ExecContext *context) {
+        assert(context);
+
+        if (context->tty_vhangup)
+                terminal_vhangup(tty_path(context));
+
+        if (context->tty_reset)
+                reset_terminal(tty_path(context));
+
+        if (context->tty_vt_disallocate && context->tty_path)
+                vt_disallocate(context->tty_path);
+}
+
+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 sockaddr_union sa;
+
+        assert(context);
+        assert(output < _EXEC_OUTPUT_MAX);
+        assert(ident);
+        assert(nfd >= 0);
+
+        fd = socket(AF_UNIX, SOCK_STREAM, 0);
+        if (fd < 0)
+                return -errno;
+
+        zero(sa);
+        sa.un.sun_family = AF_UNIX;
+        strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
+
+        r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+        if (r < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        if (shutdown(fd, SHUT_RD) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        dprintf(fd,
+                "%s\n"
+                "%i\n"
+                "%i\n"
+                "%i\n"
+                "%i\n"
+                "%i\n",
+                context->syslog_identifier ? context->syslog_identifier : ident,
+                context->syslog_priority,
+                !!context->syslog_level_prefix,
+                output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
+                output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
+                output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || output == EXEC_OUTPUT_KMSG_AND_CONSOLE || output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
+
+        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(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
+
+        if (is_terminal_input(std_input) && !apply_tty_stdin)
+                return EXEC_INPUT_NULL;
+
+        if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
+                return EXEC_INPUT_NULL;
+
+        return std_input;
+}
+
+static int fixup_output(ExecOutput std_output, int socket_fd) {
+
+        if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
+                return EXEC_OUTPUT_INHERIT;
+
+        return std_output;
+}
+
+static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
+        ExecInput i;
+
+        assert(context);
+
+        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+
+        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,
+                                     false)) < 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, bool apply_tty_stdin) {
+        ExecOutput o;
+        ExecInput i;
+
+        assert(context);
+        assert(ident);
+
+        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+        o = fixup_output(context->std_output, socket_fd);
+
+        /* This expects the input is already set up */
+
+        switch (o) {
+
+        case EXEC_OUTPUT_INHERIT:
+
+                /* If input got downgraded, inherit the original value */
+                if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
+                        return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
+
+                /* If the input is connected to anything that's not a /dev/null, inherit that... */
+                if (i != EXEC_INPUT_NULL)
+                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
+
+                /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
+                if (getppid() != 1)
+                        return STDOUT_FILENO;
+
+                /* We need to open /dev/null here anew, to get the
+                 * right access mode. So we fall through */
+
+        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_SYSLOG_AND_CONSOLE:
+        case EXEC_OUTPUT_KMSG:
+        case EXEC_OUTPUT_KMSG_AND_CONSOLE:
+        case EXEC_OUTPUT_JOURNAL:
+        case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
+                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, bool apply_tty_stdin) {
+        ExecOutput o, e;
+        ExecInput i;
+
+        assert(context);
+        assert(ident);
+
+        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+        o = fixup_output(context->std_output, socket_fd);
+        e = fixup_output(context->std_error, 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 &&
+            i == EXEC_INPUT_NULL &&
+            !is_terminal_input(context->std_input) &&
+            getppid () != 1)
+                return STDERR_FILENO;
+
+        /* Duplicate from 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_SYSLOG_AND_CONSOLE:
+        case EXEC_OUTPUT_KMSG:
+        case EXEC_OUTPUT_KMSG_AND_CONSOLE:
+        case EXEC_OUTPUT_JOURNAL:
+        case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
+                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,
+                             false)) < 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 enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
+        bool keep_groups = false;
+        int r;
+
+        assert(context);
+
+        /* Lookup and set GID and supplementary group list. Here too
+         * we avoid NSS lookups for gid=0. */
+
+        if (context->group || username) {
+
+                if (context->group) {
+                        const char *g = context->group;
+
+                        if ((r = get_group_creds(&g, &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 */
+                assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
+
+                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) {
+                        const char *g;
+
+                        if (k >= ngroups_max) {
+                                free(gids);
+                                return -E2BIG;
+                        }
+
+                        g = *i;
+                        r = get_group_creds(&g, gids+k);
+                        if (r < 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 privileges. */
+                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 capabilities. 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;
+}
+
+#ifdef HAVE_PAM
+
+static int null_conv(
+                int num_msg,
+                const struct pam_message **msg,
+                struct pam_response **resp,
+                void *appdata_ptr) {
+
+        /* We don't support conversations */
+
+        return PAM_CONV_ERR;
+}
+
+static int setup_pam(
+                const char *name,
+                const char *user,
+                const char *tty,
+                char ***pam_env,
+                int fds[], unsigned n_fds) {
+
+        static const struct pam_conv conv = {
+                .conv = null_conv,
+                .appdata_ptr = NULL
+        };
+
+        pam_handle_t *handle = NULL;
+        sigset_t ss, old_ss;
+        int pam_code = PAM_SUCCESS;
+        int err;
+        char **e = NULL;
+        bool close_session = false;
+        pid_t pam_pid = 0, parent_pid;
+
+        assert(name);
+        assert(user);
+        assert(pam_env);
+
+        /* We set up PAM in the parent process, then fork. The child
+         * will then stay around until killed via PR_GET_PDEATHSIG or
+         * systemd via the cgroup logic. It will then remove the PAM
+         * session again. The parent process will exec() the actual
+         * daemon. We do things this way to ensure that the main PID
+         * of the daemon is the one we initially fork()ed. */
+
+        if ((pam_code = pam_start(name, user, &conv, &handle)) != PAM_SUCCESS) {
+                handle = NULL;
+                goto fail;
+        }
+
+        if (tty)
+                if ((pam_code = pam_set_item(handle, PAM_TTY, tty)) != PAM_SUCCESS)
+                        goto fail;
+
+        if ((pam_code = pam_acct_mgmt(handle, PAM_SILENT)) != PAM_SUCCESS)
+                goto fail;
+
+        if ((pam_code = pam_open_session(handle, PAM_SILENT)) != PAM_SUCCESS)
+                goto fail;
+
+        close_session = true;
+
+        if ((!(e = pam_getenvlist(handle)))) {
+                pam_code = PAM_BUF_ERR;
+                goto fail;
+        }
+
+        /* Block SIGTERM, so that we know that it won't get lost in
+         * the child */
+        if (sigemptyset(&ss) < 0 ||
+            sigaddset(&ss, SIGTERM) < 0 ||
+            sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
+                goto fail;
+
+        parent_pid = getpid();
+
+        if ((pam_pid = fork()) < 0)
+                goto fail;
+
+        if (pam_pid == 0) {
+                int sig;
+                int r = EXIT_PAM;
+
+                /* The child's job is to reset the PAM session on
+                 * termination */
+
+                /* This string must fit in 10 chars (i.e. the length
+                 * of "/sbin/init"), to look pretty in /bin/ps */
+                rename_process("(sd-pam)");
+
+                /* Make sure we don't keep open the passed fds in this
+                child. We assume that otherwise only those fds are
+                open here that have been opened by PAM. */
+                close_many(fds, n_fds);
+
+                /* Wait until our parent died. This will most likely
+                 * not work since the kernel does not allow
+                 * unprivileged parents kill their privileged children
+                 * this way. We rely on the control groups kill logic
+                 * to do the rest for us. */
+                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+                        goto child_finish;
+
+                /* Check if our parent process might already have
+                 * died? */
+                if (getppid() == parent_pid) {
+                        for (;;) {
+                                if (sigwait(&ss, &sig) < 0) {
+                                        if (errno == EINTR)
+                                                continue;
+
+                                        goto child_finish;
+                                }
+
+                                assert(sig == SIGTERM);
+                                break;
+                        }
+                }
+
+                /* If our parent died we'll end the session */
+                if (getppid() != parent_pid)
+                        if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS)
+                                goto child_finish;
+
+                r = 0;
+
+        child_finish:
+                pam_end(handle, pam_code | PAM_DATA_SILENT);
+                _exit(r);
+        }
+
+        /* If the child was forked off successfully it will do all the
+         * cleanups, so forget about the handle here. */
+        handle = NULL;
+
+        /* Unblock SIGTERM again in the parent */
+        if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
+                goto fail;
+
+        /* We close the log explicitly here, since the PAM modules
+         * might have opened it, but we don't want this fd around. */
+        closelog();
+
+        *pam_env = e;
+        e = NULL;
+
+        return 0;
+
+fail:
+        if (pam_code != PAM_SUCCESS)
+                err = -EPERM;  /* PAM errors do not map to errno */
+        else
+                err = -errno;
+
+        if (handle) {
+                if (close_session)
+                        pam_code = pam_close_session(handle, PAM_DATA_SILENT);
+
+                pam_end(handle, pam_code | PAM_DATA_SILENT);
+        }
+
+        strv_free(e);
+
+        closelog();
+
+        if (pam_pid > 1) {
+                kill(pam_pid, SIGTERM);
+                kill(pam_pid, SIGCONT);
+        }
+
+        return err;
+}
+#endif
+
+static int do_capability_bounding_set_drop(uint64_t drop) {
+        unsigned long i;
+        cap_t old_cap = NULL, new_cap = NULL;
+        cap_flag_value_t fv;
+        int r;
+
+        /* If we are run as PID 1 we will lack CAP_SETPCAP by default
+         * in the effective set (yes, the kernel drops that when
+         * executing init!), so get it back temporarily so that we can
+         * call PR_CAPBSET_DROP. */
+
+        old_cap = cap_get_proc();
+        if (!old_cap)
+                return -errno;
+
+        if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (fv != CAP_SET) {
+                static const cap_value_t v = CAP_SETPCAP;
+
+                new_cap = cap_dup(old_cap);
+                if (!new_cap) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                if (cap_set_proc(new_cap) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+        }
+
+        for (i = 0; i <= cap_last_cap(); i++)
+                if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
+                        if (prctl(PR_CAPBSET_DROP, i) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+                }
+
+        r = 0;
+
+finish:
+        if (new_cap)
+                cap_free(new_cap);
+
+        if (old_cap) {
+                cap_set_proc(old_cap);
+                cap_free(old_cap);
+        }
+
+        return r;
+}
+
+static void rename_process_from_path(const char *path) {
+        char process_name[11];
+        const char *p;
+        size_t l;
+
+        /* This resulting string must fit in 10 chars (i.e. the length
+         * of "/sbin/init") to look pretty in /bin/ps */
+
+        p = file_name_from_path(path);
+        if (isempty(p)) {
+                rename_process("(...)");
+                return;
+        }
+
+        l = strlen(p);
+        if (l > 8) {
+                /* The end of the process name is usually more
+                 * interesting, since the first bit might just be
+                 * "systemd-" */
+                p = p + l - 8;
+                l = 8;
+        }
+
+        process_name[0] = '(';
+        memcpy(process_name+1, p, l);
+        process_name[1+l] = ')';
+        process_name[1+l+1] = 0;
+
+        rename_process(process_name);
+}
+
+int exec_spawn(ExecCommand *command,
+               char **argv,
+               const ExecContext *context,
+               int fds[], unsigned n_fds,
+               char **environment,
+               bool apply_permissions,
+               bool apply_chroot,
+               bool apply_tty_stdin,
+               bool confirm_spawn,
+               CGroupBonding *cgroup_bondings,
+               CGroupAttribute *cgroup_attributes,
+               pid_t *ret) {
+
+        pid_t pid;
+        int r;
+        char *line;
+        int socket_fd;
+        char **files_env = NULL;
+
+        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 ((r = exec_context_load_environment(context, &files_env)) < 0) {
+                log_error("Failed to load environment files: %s", strerror(-r));
+                return r;
+        }
+
+        if (!argv)
+                argv = command->argv;
+
+        if (!(line = exec_command_line(argv))) {
+                r = -ENOMEM;
+                goto fail_parent;
+        }
+
+        log_debug("About to execute: %s", line);
+        free(line);
+
+        r = cgroup_bonding_realize_list(cgroup_bondings);
+        if (r < 0)
+                goto fail_parent;
+
+        cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings);
+
+        if ((pid = fork()) < 0) {
+                r = -errno;
+                goto fail_parent;
+        }
+
+        if (pid == 0) {
+                int i, err;
+                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, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
+                unsigned n_env = 0;
+                int saved_stdout = -1, saved_stdin = -1;
+                bool keep_stdout = false, keep_stdin = false, set_access = false;
+
+                /* child */
+
+                rename_process_from_path(command->path);
+
+                /* We reset exactly these signals, since they are the
+                 * only ones we set to SIG_IGN in the main daemon. All
+                 * others we leave untouched because we set them to
+                 * SIG_DFL or a valid handler initially, both of which
+                 * will be demoted to SIG_DFL. */
+                default_signals(SIGNALS_CRASH_HANDLER,
+                                SIGNALS_IGNORE, -1);
+
+                if (context->ignore_sigpipe)
+                        ignore_signals(SIGPIPE, -1);
+
+                assert_se(sigemptyset(&ss) == 0);
+                if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
+                        err = -errno;
+                        r = EXIT_SIGNAL_MASK;
+                        goto fail_child;
+                }
+
+                /* Close sockets very early to make sure we don't
+                 * block init reexecution because it cannot bind its
+                 * sockets */
+                log_forget_fds();
+                err = close_all_fds(socket_fd >= 0 ? &socket_fd : fds,
+                                           socket_fd >= 0 ? 1 : n_fds);
+                if (err < 0) {
+                        r = EXIT_FDS;
+                        goto fail_child;
+                }
+
+                if (!context->same_pgrp)
+                        if (setsid() < 0) {
+                                err = -errno;
+                                r = EXIT_SETSID;
+                                goto fail_child;
+                        }
+
+                if (context->tcpwrap_name) {
+                        if (socket_fd >= 0)
+                                if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
+                                        err = -EACCES;
+                                        r = EXIT_TCPWRAP;
+                                        goto fail_child;
+                                }
+
+                        for (i = 0; i < (int) n_fds; i++) {
+                                if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) {
+                                        err = -EACCES;
+                                        r = EXIT_TCPWRAP;
+                                        goto fail_child;
+                                }
+                        }
+                }
+
+                exec_context_tty_reset(context);
+
+                /* We skip the confirmation step if we shall not apply the TTY */
+                if (confirm_spawn &&
+                    (!is_terminal_input(context->std_input) || apply_tty_stdin)) {
+                        char response;
+
+                        /* Set up terminal for the question */
+                        if ((r = setup_confirm_stdio(context,
+                                                     &saved_stdin, &saved_stdout))) {
+                                err = -errno;
+                                goto fail_child;
+                        }
+
+                        /* Now ask the question. */
+                        if (!(line = exec_command_line(argv))) {
+                                err = -ENOMEM;
+                                r = EXIT_MEMORY;
+                                goto fail_child;
+                        }
+
+                        r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line);
+                        free(line);
+
+                        if (r < 0 || response == 'n') {
+                                err = -ECANCELED;
+                                r = EXIT_CONFIRM;
+                                goto fail_child;
+                        } else if (response == 's') {
+                                err = r = 0;
+                                goto fail_child;
+                        }
+
+                        /* Release terminal for the question */
+                        if ((r = restore_confirm_stdio(context,
+                                                       &saved_stdin, &saved_stdout,
+                                                       &keep_stdin, &keep_stdout))) {
+                                err = -errno;
+                                goto fail_child;
+                        }
+                }
+
+                /* If a socket is connected to STDIN/STDOUT/STDERR, we
+                 * must sure to drop O_NONBLOCK */
+                if (socket_fd >= 0)
+                        fd_nonblock(socket_fd, false);
+
+                if (!keep_stdin) {
+                        err = setup_input(context, socket_fd, apply_tty_stdin);
+                        if (err < 0) {
+                                r = EXIT_STDIN;
+                                goto fail_child;
+                        }
+                }
+
+                if (!keep_stdout) {
+                        err = setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
+                        if (err < 0) {
+                                r = EXIT_STDOUT;
+                                goto fail_child;
+                        }
+                }
+
+                err = setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
+                if (err < 0) {
+                        r = EXIT_STDERR;
+                        goto fail_child;
+                }
+
+                if (cgroup_bondings) {
+                        err = cgroup_bonding_install_list(cgroup_bondings, 0);
+                        if (err < 0) {
+                                r = EXIT_CGROUP;
+                                goto fail_child;
+                        }
+                }
+
+                if (context->oom_score_adjust_set) {
+                        char t[16];
+
+                        snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
+                        char_array_0(t);
+
+                        if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
+                                /* Compatibility with Linux <= 2.6.35 */
+
+                                int adj;
+
+                                adj = (context->oom_score_adjust * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
+                                adj = CLAMP(adj, OOM_DISABLE, OOM_ADJUST_MAX);
+
+                                snprintf(t, sizeof(t), "%i", adj);
+                                char_array_0(t);
+
+                                if (write_one_line_file("/proc/self/oom_adj", t) < 0
+                                    && errno != EACCES) {
+                                        err = -errno;
+                                        r = EXIT_OOM_ADJUST;
+                                        goto fail_child;
+                                }
+                        }
+                }
+
+                if (context->nice_set)
+                        if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
+                                err = -errno;
+                                r = EXIT_NICE;
+                                goto fail_child;
+                        }
+
+                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) {
+                                err = -errno;
+                                r = EXIT_SETSCHEDULER;
+                                goto fail_child;
+                        }
+                }
+
+                if (context->cpuset)
+                        if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
+                                err = -errno;
+                                r = EXIT_CPUAFFINITY;
+                                goto fail_child;
+                        }
+
+                if (context->ioprio_set)
+                        if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
+                                err = -errno;
+                                r = EXIT_IOPRIO;
+                                goto fail_child;
+                        }
+
+                if (context->timer_slack_nsec_set)
+                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
+                                err = -errno;
+                                r = EXIT_TIMERSLACK;
+                                goto fail_child;
+                        }
+
+                if (context->utmp_id)
+                        utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
+
+                if (context->user) {
+                        username = context->user;
+                        err = get_user_creds(&username, &uid, &gid, &home);
+                        if (err < 0) {
+                                r = EXIT_USER;
+                                goto fail_child;
+                        }
+
+                        if (is_terminal_input(context->std_input)) {
+                                err = chown_terminal(STDIN_FILENO, uid);
+                                if (err < 0) {
+                                        r = EXIT_STDIN;
+                                        goto fail_child;
+                                }
+                        }
+
+                        if (cgroup_bondings && context->control_group_modify) {
+                                err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
+                                if (err >= 0)
+                                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid, context->control_group_persistent);
+                                if (err < 0) {
+                                        r = EXIT_CGROUP;
+                                        goto fail_child;
+                                }
+
+                                set_access = true;
+                        }
+                }
+
+                if (cgroup_bondings && !set_access && context->control_group_persistent >= 0)  {
+                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, (mode_t) -1, (uid_t) -1, (uid_t) -1, context->control_group_persistent);
+                        if (err < 0) {
+                                r = EXIT_CGROUP;
+                                goto fail_child;
+                        }
+                }
+
+                if (apply_permissions) {
+                        err = enforce_groups(context, username, gid);
+                        if (err < 0) {
+                                r = EXIT_GROUP;
+                                goto fail_child;
+                        }
+                }
+
+                umask(context->umask);
+
+#ifdef HAVE_PAM
+                if (context->pam_name && username) {
+                        err = setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds);
+                        if (err < 0) {
+                                r = EXIT_PAM;
+                                goto fail_child;
+                        }
+                }
+#endif
+                if (context->private_network) {
+                        if (unshare(CLONE_NEWNET) < 0) {
+                                err = -errno;
+                                r = EXIT_NETWORK;
+                                goto fail_child;
+                        }
+
+                        loopback_setup();
+                }
+
+                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) {
+                        err = setup_namespace(context->read_write_dirs,
+                                              context->read_only_dirs,
+                                              context->inaccessible_dirs,
+                                              context->private_tmp,
+                                              context->mount_flags);
+                        if (err < 0) {
+                                r = EXIT_NAMESPACE;
+                                goto fail_child;
+                        }
+                }
+
+                if (apply_chroot) {
+                        if (context->root_directory)
+                                if (chroot(context->root_directory) < 0) {
+                                        err = -errno;
+                                        r = EXIT_CHROOT;
+                                        goto fail_child;
+                                }
+
+                        if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
+                                err = -errno;
+                                r = EXIT_CHDIR;
+                                goto fail_child;
+                        }
+                } else {
+
+                        char *d;
+
+                        if (asprintf(&d, "%s/%s",
+                                     context->root_directory ? context->root_directory : "",
+                                     context->working_directory ? context->working_directory : "") < 0) {
+                                err = -ENOMEM;
+                                r = EXIT_MEMORY;
+                                goto fail_child;
+                        }
+
+                        if (chdir(d) < 0) {
+                                err = -errno;
+                                free(d);
+                                r = EXIT_CHDIR;
+                                goto fail_child;
+                        }
+
+                        free(d);
+                }
+
+                /* We repeat the fd closing here, to make sure that
+                 * nothing is leaked from the PAM modules */
+                err = close_all_fds(fds, n_fds);
+                if (err >= 0)
+                        err = shift_fds(fds, n_fds);
+                if (err >= 0)
+                        err = flags_fds(fds, n_fds, context->non_blocking);
+                if (err < 0) {
+                        r = EXIT_FDS;
+                        goto fail_child;
+                }
+
+                if (apply_permissions) {
+
+                        for (i = 0; i < RLIMIT_NLIMITS; i++) {
+                                if (!context->rlimit[i])
+                                        continue;
+
+                                if (setrlimit(i, context->rlimit[i]) < 0) {
+                                        err = -errno;
+                                        r = EXIT_LIMITS;
+                                        goto fail_child;
+                                }
+                        }
+
+                        if (context->capability_bounding_set_drop) {
+                                err = do_capability_bounding_set_drop(context->capability_bounding_set_drop);
+                                if (err < 0) {
+                                        r = EXIT_CAPABILITIES;
+                                        goto fail_child;
+                                }
+                        }
+
+                        if (context->user) {
+                                err = enforce_user(context, uid);
+                                if (err < 0) {
+                                        r = EXIT_USER;
+                                        goto fail_child;
+                                }
+                        }
+
+                        /* PR_GET_SECUREBITS is not privileged, 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) {
+                                        err = -errno;
+                                        r = EXIT_SECUREBITS;
+                                        goto fail_child;
+                                }
+
+                        if (context->capabilities)
+                                if (cap_set_proc(context->capabilities) < 0) {
+                                        err = -errno;
+                                        r = EXIT_CAPABILITIES;
+                                        goto fail_child;
+                                }
+                }
+
+                if (!(our_env = new0(char*, 7))) {
+                        err = -ENOMEM;
+                        r = EXIT_MEMORY;
+                        goto fail_child;
+                }
+
+                if (n_fds > 0)
+                        if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 ||
+                            asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
+                                err = -ENOMEM;
+                                r = EXIT_MEMORY;
+                                goto fail_child;
+                        }
+
+                if (home)
+                        if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
+                                err = -ENOMEM;
+                                r = EXIT_MEMORY;
+                                goto fail_child;
+                        }
+
+                if (username)
+                        if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
+                            asprintf(our_env + n_env++, "USER=%s", username) < 0) {
+                                err = -ENOMEM;
+                                r = EXIT_MEMORY;
+                                goto fail_child;
+                        }
+
+                if (is_terminal_input(context->std_input) ||
+                    context->std_output == EXEC_OUTPUT_TTY ||
+                    context->std_error == EXEC_OUTPUT_TTY)
+                        if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
+                                err = -ENOMEM;
+                                r = EXIT_MEMORY;
+                                goto fail_child;
+                        }
+
+                assert(n_env <= 7);
+
+                if (!(final_env = strv_env_merge(
+                                      5,
+                                      environment,
+                                      our_env,
+                                      context->environment,
+                                      files_env,
+                                      pam_env,
+                                      NULL))) {
+                        err = -ENOMEM;
+                        r = EXIT_MEMORY;
+                        goto fail_child;
+                }
+
+                if (!(final_argv = replace_env_argv(argv, final_env))) {
+                        err = -ENOMEM;
+                        r = EXIT_MEMORY;
+                        goto fail_child;
+                }
+
+                final_env = strv_env_clean(final_env);
+
+                execve(command->path, final_argv, final_env);
+                err = -errno;
+                r = EXIT_EXEC;
+
+        fail_child:
+                if (r != 0) {
+                        log_open();
+                        log_warning("Failed at step %s spawning %s: %s",
+                                    exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
+                                    command->path, strerror(-err));
+                }
+
+                strv_free(our_env);
+                strv_free(final_env);
+                strv_free(pam_env);
+                strv_free(files_env);
+                strv_free(final_argv);
+
+                if (saved_stdin >= 0)
+                        close_nointr_nofail(saved_stdin);
+
+                if (saved_stdout >= 0)
+                        close_nointr_nofail(saved_stdout);
+
+                _exit(r);
+        }
+
+        strv_free(files_env);
+
+        /* 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 %lu", command->path, (unsigned long) pid);
+
+        exec_status_start(&command->exec_status, pid);
+
+        *ret = pid;
+        return 0;
+
+fail_parent:
+        strv_free(files_env);
+
+        return r;
+}
+
+void exec_context_init(ExecContext *c) {
+        assert(c);
+
+        c->umask = 0022;
+        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
+        c->cpu_sched_policy = SCHED_OTHER;
+        c->syslog_priority = LOG_DAEMON|LOG_INFO;
+        c->syslog_level_prefix = true;
+        c->mount_flags = MS_SHARED;
+        c->kill_signal = SIGTERM;
+        c->send_sigkill = true;
+        c->control_group_persistent = -1;
+        c->ignore_sigpipe = true;
+}
+
+void exec_context_done(ExecContext *c) {
+        unsigned l;
+
+        assert(c);
+
+        strv_free(c->environment);
+        c->environment = NULL;
+
+        strv_free(c->environment_files);
+        c->environment_files = 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->tcpwrap_name);
+        c->tcpwrap_name = 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;
+
+        free(c->pam_name);
+        c->pam_name = 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;
+
+        if (c->cpuset)
+                CPU_FREE(c->cpuset);
+
+        free(c->utmp_id);
+        c->utmp_id = 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;
+        }
+}
+
+int exec_context_load_environment(const ExecContext *c, char ***l) {
+        char **i, **r = NULL;
+
+        assert(c);
+        assert(l);
+
+        STRV_FOREACH(i, c->environment_files) {
+                char *fn;
+                int k;
+                bool ignore = false;
+                char **p;
+
+                fn = *i;
+
+                if (fn[0] == '-') {
+                        ignore = true;
+                        fn ++;
+                }
+
+                if (!path_is_absolute(fn)) {
+
+                        if (ignore)
+                                continue;
+
+                        strv_free(r);
+                        return -EINVAL;
+                }
+
+                if ((k = load_env_file(fn, &p)) < 0) {
+
+                        if (ignore)
+                                continue;
+
+                        strv_free(r);
+                        return k;
+                }
+
+                if (r == NULL)
+                        r = p;
+                else {
+                        char **m;
+
+                        m = strv_env_merge(2, r, p);
+                        strv_free(r);
+                        strv_free(p);
+
+                        if (!m)
+                                return -ENOMEM;
+
+                        r = m;
+                }
+        }
+
+        *l = r;
+
+        return 0;
+}
+
+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"
+                "%sControlGroupModify: %s\n"
+                "%sControlGroupPersistent: %s\n"
+                "%sPrivateNetwork: %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),
+                prefix, yes_no(c->control_group_modify),
+                prefix, yes_no(c->control_group_persistent),
+                prefix, yes_no(c->private_network));
+
+        STRV_FOREACH(e, c->environment)
+                fprintf(f, "%sEnvironment: %s\n", prefix, *e);
+
+        STRV_FOREACH(e, c->environment_files)
+                fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
+
+        if (c->tcpwrap_name)
+                fprintf(f,
+                        "%sTCPWrapName: %s\n",
+                        prefix, c->tcpwrap_name);
+
+        if (c->nice_set)
+                fprintf(f,
+                        "%sNice: %i\n",
+                        prefix, c->nice);
+
+        if (c->oom_score_adjust_set)
+                fprintf(f,
+                        "%sOOMScoreAdjust: %i\n",
+                        prefix, c->oom_score_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->cpuset) {
+                fprintf(f, "%sCPUAffinity:", prefix);
+                for (i = 0; i < c->cpuset_ncpus; i++)
+                        if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
+                                fprintf(f, " %i", i);
+                fputs("\n", f);
+        }
+
+        if (c->timer_slack_nsec_set)
+                fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
+
+        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"
+                        "%sTTYReset: %s\n"
+                        "%sTTYVHangup: %s\n"
+                        "%sTTYVTDisallocate: %s\n",
+                        prefix, c->tty_path,
+                        prefix, yes_no(c->tty_reset),
+                        prefix, yes_no(c->tty_vhangup),
+                        prefix, yes_no(c->tty_vt_disallocate));
+
+        if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG || c->std_output == EXEC_OUTPUT_JOURNAL ||
+            c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE ||
+            c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG || c->std_error == EXEC_OUTPUT_JOURNAL ||
+            c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_JOURNAL_AND_CONSOLE)
+                fprintf(f,
+                        "%sSyslogFacility: %s\n"
+                        "%sSyslogLevel: %s\n",
+                        prefix, log_facility_unshifted_to_string(c->syslog_priority >> 3),
+                        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) {
+                unsigned long l;
+                fprintf(f, "%sCapabilityBoundingSet:", prefix);
+
+                for (l = 0; l <= cap_last_cap(); l++)
+                        if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
+                                char *t;
+
+                                if ((t = cap_to_name(l))) {
+                                        fprintf(f, " %s", t);
+                                        cap_free(t);
+                                }
+                        }
+
+                fputs("\n", f);
+        }
+
+        if (c->user)
+                fprintf(f, "%sUser: %s\n", prefix, c->user);
+        if (c->group)
+                fprintf(f, "%sGroup: %s\n", prefix, c->group);
+
+        if (strv_length(c->supplementary_groups) > 0) {
+                fprintf(f, "%sSupplementaryGroups:", prefix);
+                strv_fprintf(f, c->supplementary_groups);
+                fputs("\n", f);
+        }
+
+        if (c->pam_name)
+                fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
+
+        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);
+        }
+
+        fprintf(f,
+                "%sKillMode: %s\n"
+                "%sKillSignal: SIG%s\n"
+                "%sSendSIGKILL: %s\n"
+                "%sIgnoreSIGPIPE: %s\n",
+                prefix, kill_mode_to_string(c->kill_mode),
+                prefix, signal_to_string(c->kill_signal),
+                prefix, yes_no(c->send_sigkill),
+                prefix, yes_no(c->ignore_sigpipe));
+
+        if (c->utmp_id)
+                fprintf(f,
+                        "%sUtmpIdentifier: %s\n",
+                        prefix, c->utmp_id);
+}
+
+void exec_status_start(ExecStatus *s, pid_t pid) {
+        assert(s);
+
+        zero(*s);
+        s->pid = pid;
+        dual_timestamp_get(&s->start_timestamp);
+}
+
+void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) {
+        assert(s);
+
+        if (s->pid && s->pid != pid)
+                zero(*s);
+
+        s->pid = pid;
+        dual_timestamp_get(&s->exit_timestamp);
+
+        s->code = code;
+        s->status = status;
+
+        if (context) {
+                if (context->utmp_id)
+                        utmp_put_dead_process(context->utmp_id, pid, code, status);
+
+                exec_context_tty_reset(context);
+        }
+}
+
+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: %lu\n",
+                prefix, (unsigned long) s->pid);
+
+        if (s->start_timestamp.realtime > 0)
+                fprintf(f,
+                        "%sStart Timestamp: %s\n",
+                        prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
+
+        if (s->exit_timestamp.realtime > 0)
+                fprintf(f,
+                        "%sExit Timestamp: %s\n"
+                        "%sExit Code: %s\n"
+                        "%sExit Status: %i\n",
+                        prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime),
+                        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 kind of 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;
+}
+
+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"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+
+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_SYSLOG_AND_CONSOLE] = "syslog+console",
+        [EXEC_OUTPUT_KMSG] = "kmsg",
+        [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
+        [EXEC_OUTPUT_JOURNAL] = "journal",
+        [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
+        [EXEC_OUTPUT_SOCKET] = "socket"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
+
+static const char* const kill_mode_table[_KILL_MODE_MAX] = {
+        [KILL_CONTROL_GROUP] = "control-group",
+        [KILL_PROCESS] = "process",
+        [KILL_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
+
+static const char* const kill_who_table[_KILL_WHO_MAX] = {
+        [KILL_MAIN] = "main",
+        [KILL_CONTROL] = "control",
+        [KILL_ALL] = "all"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/core/execute.h b/src/core/execute.h
new file mode 100644
index 0000000..0d7e7dd
--- /dev/null
+++ b/src/core/execute.h
@@ -0,0 +1,233 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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 <linux/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/capability.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct CGroupBonding;
+struct CGroupAttribute;
+
+#include "list.h"
+#include "util.h"
+
+typedef enum KillMode {
+        KILL_CONTROL_GROUP = 0,
+        KILL_PROCESS,
+        KILL_NONE,
+        _KILL_MODE_MAX,
+        _KILL_MODE_INVALID = -1
+} KillMode;
+
+typedef enum KillWho {
+        KILL_MAIN,
+        KILL_CONTROL,
+        KILL_ALL,
+        _KILL_WHO_MAX,
+        _KILL_WHO_INVALID = -1
+} KillWho;
+
+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_SYSLOG_AND_CONSOLE,
+        EXEC_OUTPUT_KMSG,
+        EXEC_OUTPUT_KMSG_AND_CONSOLE,
+        EXEC_OUTPUT_JOURNAL,
+        EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
+        EXEC_OUTPUT_SOCKET,
+        _EXEC_OUTPUT_MAX,
+        _EXEC_OUTPUT_INVALID = -1
+} ExecOutput;
+
+struct ExecStatus {
+        dual_timestamp start_timestamp;
+        dual_timestamp 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 */
+        bool ignore;
+};
+
+struct ExecContext {
+        char **environment;
+        char **environment_files;
+
+        struct rlimit *rlimit[RLIMIT_NLIMITS];
+        char *working_directory, *root_directory;
+
+        mode_t umask;
+        int oom_score_adjust;
+        int nice;
+        int ioprio;
+        int cpu_sched_policy;
+        int cpu_sched_priority;
+
+        cpu_set_t *cpuset;
+        unsigned cpuset_ncpus;
+
+        ExecInput std_input;
+        ExecOutput std_output;
+        ExecOutput std_error;
+
+        unsigned long timer_slack_nsec;
+
+        char *tcpwrap_name;
+
+        char *tty_path;
+
+        bool tty_reset;
+        bool tty_vhangup;
+        bool tty_vt_disallocate;
+
+        bool ignore_sigpipe;
+
+        /* 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 *pam_name;
+
+        char *utmp_id;
+
+        char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
+        unsigned long mount_flags;
+
+        uint64_t capability_bounding_set_drop;
+
+        /* Not relevant for spawning processes, just for killing */
+        KillMode kill_mode;
+        int kill_signal;
+        bool send_sigkill;
+
+        cap_t capabilities;
+        int secure_bits;
+
+        int syslog_priority;
+        char *syslog_identifier;
+        bool syslog_level_prefix;
+
+        bool cpu_sched_reset_on_fork;
+        bool non_blocking;
+        bool private_tmp;
+        bool private_network;
+
+        bool control_group_modify;
+        int control_group_persistent;
+
+        /* 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 same_pgrp;
+
+        bool oom_score_adjust_set:1;
+        bool nice_set:1;
+        bool ioprio_set:1;
+        bool cpu_sched_set:1;
+        bool timer_slack_nsec_set:1;
+};
+
+int exec_spawn(ExecCommand *command,
+               char **argv,
+               const ExecContext *context,
+               int fds[], unsigned n_fds,
+               char **environment,
+               bool apply_permissions,
+               bool apply_chroot,
+               bool apply_tty_stdin,
+               bool confirm_spawn,
+               struct CGroupBonding *cgroup_bondings,
+               struct CGroupAttribute *cgroup_attributes,
+               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_context_tty_reset(const ExecContext *context);
+
+int exec_context_load_environment(const ExecContext *c, char ***l);
+
+void exec_status_start(ExecStatus *s, pid_t pid);
+void exec_status_exit(ExecStatus *s, ExecContext *context, 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);
+ExecOutput exec_output_from_string(const char *s);
+
+const char* exec_input_to_string(ExecInput i);
+ExecInput exec_input_from_string(const char *s);
+
+const char *kill_mode_to_string(KillMode k);
+KillMode kill_mode_from_string(const char *s);
+
+const char *kill_who_to_string(KillWho k);
+KillWho kill_who_from_string(const char *s);
+
+#endif
diff --git a/src/core/fdset.c b/src/core/fdset.c
new file mode 100644
index 0000000..e67fe6f
--- /dev/null
+++ b/src/core/fdset.c
@@ -0,0 +1,167 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 */
+
+                /* When reloading duplicates of the private bus
+                 * connection fds and suchlike are closed here, which
+                 * has no effect at all, since they are only
+                 * duplicates. So don't be surprised about these log
+                 * messages. */
+
+                log_debug("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/core/fdset.h b/src/core/fdset.h
new file mode 100644
index 0000000..044a9e6
--- /dev/null
+++ b/src/core/fdset.h
@@ -0,0 +1,40 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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/core/ima-setup.c b/src/core/ima-setup.c
new file mode 100644
index 0000000..03e43dc
--- /dev/null
+++ b/src/core/ima-setup.c
@@ -0,0 +1,115 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
+                                     TORSEC group -- http://security.polito.it
+
+  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 <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "ima-setup.h"
+#include "mount-setup.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+#include "label.h"
+
+#define IMA_SECFS_DIR "/sys/kernel/security/ima"
+#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
+#define IMA_POLICY_PATH "/etc/ima/ima-policy"
+
+int ima_setup(void) {
+
+#ifdef HAVE_IMA
+       struct stat st;
+       ssize_t policy_size = 0, written = 0;
+       char *policy;
+       int policyfd = -1, imafd = -1;
+       int result = 0;
+
+#ifndef HAVE_SELINUX
+       /* Mount the securityfs filesystem */
+       mount_setup_early();
+#endif
+
+       if (stat(IMA_POLICY_PATH, &st) < 0)
+               return 0;
+
+       policy_size = st.st_size;
+       if (stat(IMA_SECFS_DIR, &st) < 0) {
+               log_debug("IMA support is disabled in the kernel, ignoring.");
+               return 0;
+       }
+
+       if (stat(IMA_SECFS_POLICY, &st) < 0) {
+               log_error("Another IMA custom policy has already been loaded, "
+                         "ignoring.");
+               return 0;
+       }
+
+       policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
+       if (policyfd < 0) {
+               log_error("Failed to open the IMA custom policy file %s (%m), "
+                         "ignoring.", IMA_POLICY_PATH);
+               return 0;
+       }
+
+       imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
+       if (imafd < 0) {
+               log_error("Failed to open the IMA kernel interface %s (%m), "
+                         "ignoring.", IMA_SECFS_POLICY);
+               goto out;
+       }
+
+       policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
+       if (policy == MAP_FAILED) {
+               log_error("mmap() failed (%m), freezing");
+               result = -errno;
+               goto out;
+       }
+
+       written = loop_write(imafd, policy, (size_t)policy_size, false);
+       if (written != policy_size) {
+               log_error("Failed to load the IMA custom policy file %s (%m), "
+                         "ignoring.", IMA_POLICY_PATH);
+               goto out_mmap;
+       }
+
+       log_info("Successfully loaded the IMA custom policy %s.",
+                IMA_POLICY_PATH);
+out_mmap:
+       munmap(policy, policy_size);
+out:
+       if (policyfd >= 0)
+                close_nointr_nofail(policyfd);
+       if (imafd >= 0)
+                close_nointr_nofail(imafd);
+       if (result)
+                return result;
+#endif /* HAVE_IMA */
+
+       return 0;
+}
diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h
new file mode 100644
index 0000000..7d677cf
--- /dev/null
+++ b/src/core/ima-setup.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooimasetuphfoo
+#define fooimasetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
+                                     TORSEC group -- http://security.polito.it
+
+  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 ima_setup(void);
+
+#endif
diff --git a/src/core/initreq.h b/src/core/initreq.h
new file mode 100644
index 0000000..859042c
--- /dev/null
+++ b/src/core/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 separate 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/core/job.c b/src/core/job.c
new file mode 100644
index 0000000..bae6ab9
--- /dev/null
+++ b/src/core/job.c
@@ -0,0 +1,701 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <sys/timerfd.h>
+#include <sys/epoll.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;
+
+        j->timer_watch.type = WATCH_INVALID;
+
+        /* 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->job == j) {
+                        j->unit->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);
+
+        if (j->timer_watch.type != WATCH_INVALID) {
+                assert(j->timer_watch.type == WATCH_JOB_TIMER);
+                assert(j->timer_watch.data.job == j);
+                assert(j->timer_watch.fd >= 0);
+
+                assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
+                close_nointr_nofail(j->timer_watch.fd);
+        }
+
+        free(j->bus_client);
+        free(j);
+}
+
+JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
+        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
+         * explicitly asked for) is the requester. */
+
+        if (!(l = new0(JobDependency, 1)))
+                return NULL;
+
+        l->subject = subject;
+        l->object = object;
+        l->matters = matters;
+        l->conflicts = conflicts;
+
+        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_dump(Job *j, FILE*f, const char *prefix) {
+        assert(j);
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        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->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;
+}
+
+/*
+ * Merging is commutative, so imagine the matrix as symmetric. We store only
+ * its lower triangle to avoid duplication. We don't store the main diagonal,
+ * because A merged with A is simply A.
+ *
+ * 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.
+ */
+static const JobType job_merging_table[] = {
+/* What \ With       *  JOB_START         JOB_VERIFY_ACTIVE  JOB_STOP JOB_RELOAD   JOB_RELOAD_OR_START  JOB_RESTART JOB_TRY_RESTART */
+/************************************************************************************************************************************/
+/*JOB_START          */
+/*JOB_VERIFY_ACTIVE  */ JOB_START,
+/*JOB_STOP           */ -1,                  -1,
+/*JOB_RELOAD         */ JOB_RELOAD_OR_START, JOB_RELOAD,          -1,
+/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START,
+/*JOB_RESTART        */ JOB_RESTART,         JOB_RESTART,         -1, JOB_RESTART,         JOB_RESTART,
+/*JOB_TRY_RESTART    */ JOB_RESTART,         JOB_TRY_RESTART,     -1, JOB_TRY_RESTART,     JOB_RESTART, JOB_RESTART,
+};
+
+JobType job_type_lookup_merge(JobType a, JobType b) {
+        assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2);
+        assert(a >= 0 && a < _JOB_TYPE_MAX);
+        assert(b >= 0 && b < _JOB_TYPE_MAX);
+
+        if (a == b)
+                return a;
+
+        if (a < b) {
+                JobType tmp = a;
+                a = b;
+                b = tmp;
+        }
+
+        return job_merging_table[(a - 1) * a / 2 + b];
+}
+
+bool job_type_is_redundant(JobType a, UnitActiveState b) {
+        switch (a) {
+
+        case JOB_START:
+                return
+                        b == UNIT_ACTIVE ||
+                        b == UNIT_RELOADING;
+
+        case JOB_STOP:
+                return
+                        b == UNIT_INACTIVE ||
+                        b == UNIT_FAILED;
+
+        case JOB_VERIFY_ACTIVE:
+                return
+                        b == UNIT_ACTIVE ||
+                        b == UNIT_RELOADING;
+
+        case JOB_RELOAD:
+                return
+                        b == UNIT_RELOADING;
+
+        case JOB_RELOAD_OR_START:
+                return
+                        b == UNIT_ACTIVATING ||
+                        b == UNIT_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. */
+
+        /* First check if there is an override */
+        if (j->ignore_order)
+                return true;
+
+        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->dependencies[UNIT_AFTER], i)
+                        if (other->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->dependencies[UNIT_BEFORE], i)
+                if (other->job &&
+                    (other->job->type == JOB_STOP ||
+                     other->job->type == JOB_RESTART ||
+                     other->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;
+}
+
+static void job_change_type(Job *j, JobType newtype) {
+        log_debug("Converting job %s/%s -> %s/%s",
+                  j->unit->id, job_type_to_string(j->type),
+                  j->unit->id, job_type_to_string(newtype));
+
+        j->type = newtype;
+}
+
+int job_run_and_invalidate(Job *j) {
+        int r;
+        uint32_t id;
+        Manager *m;
+
+        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);
+
+        /* While we execute this operation the job might go away (for
+         * example: because it is replaced by a new, conflicting
+         * job.) To make sure we don't access a freed job later on we
+         * store the id here, so that we can verify the job is still
+         * valid. */
+        id = j->id;
+        m = j->manager;
+
+        switch (j->type) {
+
+                case JOB_RELOAD_OR_START:
+                        if (unit_active_state(j->unit) == UNIT_ACTIVE) {
+                                job_change_type(j, JOB_RELOAD);
+                                r = unit_reload(j->unit);
+                                break;
+                        }
+                        job_change_type(j, JOB_START);
+                        /* fall through */
+
+                case JOB_START:
+                        r = unit_start(j->unit);
+
+                        /* If this unit cannot be started, then simply wait */
+                        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_TRY_RESTART:
+                        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) {
+                                r = -ENOEXEC;
+                                break;
+                        }
+                        job_change_type(j, JOB_RESTART);
+                        /* fall through */
+
+                case JOB_STOP:
+                case JOB_RESTART:
+                        r = unit_stop(j->unit);
+
+                        /* If this unit cannot stopped, then simply wait. */
+                        if (r == -EBADR)
+                                r = 0;
+                        break;
+
+                case JOB_RELOAD:
+                        r = unit_reload(j->unit);
+                        break;
+
+                default:
+                        assert_not_reached("Unknown job type");
+        }
+
+        if ((j = manager_get_job(m, id))) {
+                if (r == -EALREADY)
+                        r = job_finish_and_invalidate(j, JOB_DONE);
+                else if (r == -ENOEXEC)
+                        r = job_finish_and_invalidate(j, JOB_SKIPPED);
+                else if (r == -EAGAIN)
+                        j->state = JOB_WAITING;
+                else if (r < 0)
+                        r = job_finish_and_invalidate(j, JOB_FAILED);
+        }
+
+        return r;
+}
+
+static void job_print_status_message(Unit *u, JobType t, JobResult result) {
+        assert(u);
+
+        if (t == JOB_START) {
+
+                switch (result) {
+
+                case JOB_DONE:
+                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Started %s", unit_description(u));
+                        break;
+
+                case JOB_FAILED:
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s", unit_description(u));
+                        unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
+                        break;
+
+                case JOB_DEPENDENCY:
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s", unit_description(u));
+                        break;
+
+                case JOB_TIMEOUT:
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s", unit_description(u));
+                        break;
+
+                default:
+                        ;
+                }
+
+        } else if (t == JOB_STOP) {
+
+                switch (result) {
+
+                case JOB_TIMEOUT:
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s", unit_description(u));
+                        break;
+
+                case JOB_DONE:
+                case JOB_FAILED:
+                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Stopped %s", unit_description(u));
+                        break;
+
+                default:
+                        ;
+                }
+        }
+}
+
+int job_finish_and_invalidate(Job *j, JobResult result) {
+        Unit *u;
+        Unit *other;
+        JobType t;
+        Iterator i;
+        bool recursed = false;
+
+        assert(j);
+        assert(j->installed);
+
+        job_add_to_dbus_queue(j);
+
+        /* Patch restart jobs so that they become normal start jobs */
+        if (result == JOB_DONE && j->type == JOB_RESTART) {
+
+                job_change_type(j, JOB_START);
+                j->state = JOB_WAITING;
+
+                job_add_to_run_queue(j);
+
+                u = j->unit;
+                goto finish;
+        }
+
+        j->result = result;
+
+        log_debug("Job %s/%s finished, result=%s", j->unit->id, job_type_to_string(j->type), job_result_to_string(result));
+
+        if (result == JOB_FAILED)
+                j->manager->n_failed_jobs ++;
+
+        u = j->unit;
+        t = j->type;
+        job_free(j);
+
+        job_print_status_message(u, t, result);
+
+        /* Fail depending jobs on failure */
+        if (result != JOB_DONE) {
+
+                if (t == JOB_START ||
+                    t == JOB_VERIFY_ACTIVE ||
+                    t == JOB_RELOAD_OR_START) {
+
+                        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
+                                if (other->job &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
+
+                        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
+                                if (other->job &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
+
+                        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
+                                if (other->job &&
+                                    !other->job->override &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
+
+                } else if (t == JOB_STOP) {
+
+                        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
+                                if (other->job &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
+                }
+        }
+
+        /* Trigger OnFailure dependencies that are not generated by
+         * the unit itself. We don't tread JOB_CANCELED as failure in
+         * this context. And JOB_FAILURE is already handled by the
+         * unit itself. */
+        if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
+                log_notice("Job %s/%s failed with result '%s'.",
+                           u->id,
+                           job_type_to_string(t),
+                           job_result_to_string(result));
+
+                unit_trigger_on_failure(u);
+        }
+
+finish:
+        /* Try to start the next jobs that can be started */
+        SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
+                if (other->job)
+                        job_add_to_run_queue(other->job);
+        SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
+                if (other->job)
+                        job_add_to_run_queue(other->job);
+
+        manager_check_finished(u->manager);
+
+        return recursed;
+}
+
+int job_start_timer(Job *j) {
+        struct itimerspec its;
+        struct epoll_event ev;
+        int fd, r;
+        assert(j);
+
+        if (j->unit->job_timeout <= 0 ||
+            j->timer_watch.type == WATCH_JOB_TIMER)
+                return 0;
+
+        assert(j->timer_watch.type == WATCH_INVALID);
+
+        if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        zero(its);
+        timespec_store(&its.it_value, j->unit->job_timeout);
+
+        if (timerfd_settime(fd, 0, &its, NULL) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        zero(ev);
+        ev.data.ptr = &j->timer_watch;
+        ev.events = EPOLLIN;
+
+        if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        j->timer_watch.type = WATCH_JOB_TIMER;
+        j->timer_watch.fd = fd;
+        j->timer_watch.data.job = j;
+
+        return 0;
+
+fail:
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
+
+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;
+
+        /* We don't check if anybody is subscribed here, since this
+         * job might just have been created and not yet assigned to a
+         * connection/client. */
+
+        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;
+}
+
+void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
+        assert(j);
+        assert(w == &j->timer_watch);
+
+        log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
+        job_finish_and_invalidate(j, JOB_TIMEOUT);
+}
+
+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",
+        [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
+        [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
+
+static const char* const job_result_table[_JOB_RESULT_MAX] = {
+        [JOB_DONE] = "done",
+        [JOB_CANCELED] = "canceled",
+        [JOB_TIMEOUT] = "timeout",
+        [JOB_FAILED] = "failed",
+        [JOB_DEPENDENCY] = "dependency",
+        [JOB_SKIPPED] = "skipped"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/core/job.h b/src/core/job.h
new file mode 100644
index 0000000..60a43e0
--- /dev/null
+++ b/src/core/job.h
@@ -0,0 +1,200 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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>
+#include <errno.h>
+
+typedef struct Job Job;
+typedef struct JobDependency JobDependency;
+typedef enum JobType JobType;
+typedef enum JobState JobState;
+typedef enum JobMode JobMode;
+typedef enum JobResult JobResult;
+
+#include "manager.h"
+#include "unit.h"
+#include "hashmap.h"
+#include "list.h"
+
+/* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */
+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,                /* Fail if a conflicting job is already queued */
+        JOB_REPLACE,             /* Replace an existing conflicting job */
+        JOB_ISOLATE,             /* Start a unit, and stop all others */
+        JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
+        JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
+        _JOB_MODE_MAX,
+        _JOB_MODE_INVALID = -1
+};
+
+enum JobResult {
+        JOB_DONE,
+        JOB_CANCELED,
+        JOB_TIMEOUT,
+        JOB_FAILED,
+        JOB_DEPENDENCY,
+        JOB_SKIPPED,
+        _JOB_RESULT_MAX,
+        _JOB_RESULT_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;
+        bool conflicts;
+};
+
+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;
+
+        Watch timer_watch;
+
+        /* Note that this bus object is not ref counted here. */
+        DBusConnection *bus;
+        char *bus_client;
+
+        JobResult result;
+
+        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;
+        bool ignore_order: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, bool conflicts);
+void job_dependency_free(JobDependency *l);
+
+bool job_is_anchor(Job *j);
+
+int job_merge(Job *j, Job *other);
+
+JobType job_type_lookup_merge(JobType a, JobType b);
+
+static inline int job_type_merge(JobType *a, JobType b) {
+        JobType t = job_type_lookup_merge(*a, b);
+        if (t < 0)
+                return -EEXIST;
+        *a = t;
+        return 0;
+}
+
+static inline bool job_type_is_mergeable(JobType a, JobType b) {
+        return job_type_lookup_merge(a, b) >= 0;
+}
+
+static inline bool job_type_is_conflicting(JobType a, JobType b) {
+        return !job_type_is_mergeable(a, b);
+}
+
+static inline bool job_type_is_superset(JobType a, JobType b) {
+        /* Checks whether operation a is a "superset" of b in its actions */
+        return a == job_type_lookup_merge(a, 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_start_timer(Job *j);
+void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w);
+
+int job_run_and_invalidate(Job *j);
+int job_finish_and_invalidate(Job *j, JobResult result);
+
+char *job_dbus_path(Job *j);
+
+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);
+
+const char* job_result_to_string(JobResult t);
+JobResult job_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
new file mode 100644
index 0000000..debf871
--- /dev/null
+++ b/src/core/kmod-setup.c
@@ -0,0 +1,96 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <libkmod.h>
+
+#include "macro.h"
+#include "execute.h"
+
+#include "kmod-setup.h"
+
+static const char * const kmod_table[] = {
+        "autofs4", "/sys/class/misc/autofs",
+        "ipv6",    "/sys/module/ipv6",
+        "unix",    "/proc/net/unix"
+};
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+static void systemd_kmod_log(void *data, int priority, const char *file, int line,
+                             const char *fn, const char *format, va_list args)
+{
+        log_meta(priority, file, line, fn, format, args);
+}
+#pragma GCC diagnostic pop
+
+int kmod_setup(void) {
+        unsigned i;
+        struct kmod_ctx *ctx = NULL;
+        struct kmod_module *mod;
+        int err;
+
+        for (i = 0; i < ELEMENTSOF(kmod_table); i += 2) {
+
+                if (access(kmod_table[i+1], F_OK) >= 0)
+                        continue;
+
+                log_debug("Your kernel apparently lacks built-in %s support. Might be a good idea to compile it in. "
+                          "We'll now try to work around this by loading the module...",
+                          kmod_table[i]);
+
+                if (!ctx) {
+                        ctx = kmod_new(NULL, NULL);
+                        if (!ctx) {
+                                log_error("Failed to allocate memory for kmod");
+                                return -ENOMEM;
+                        }
+
+                        kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
+
+                        kmod_load_resources(ctx);
+                }
+
+                err = kmod_module_new_from_name(ctx, kmod_table[i], &mod);
+                if (err < 0) {
+                        log_error("Failed to load module '%s'", kmod_table[i]);
+                        continue;
+                }
+
+                err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
+                if (err == 0)
+                        log_info("Inserted module '%s'", kmod_module_get_name(mod));
+                else if (err == KMOD_PROBE_APPLY_BLACKLIST)
+                        log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
+                else
+                        log_error("Failed to insert '%s'", kmod_module_get_name(mod));
+
+                kmod_module_unref(mod);
+        }
+
+        if (ctx)
+                kmod_unref(ctx);
+
+        return 0;
+}
diff --git a/src/core/kmod-setup.h b/src/core/kmod-setup.h
new file mode 100644
index 0000000..496aef3
--- /dev/null
+++ b/src/core/kmod-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fookmodsetuphfoo
+#define fookmodsetuphfoo
+
+/***
+  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 kmod_setup(void);
+
+#endif
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
new file mode 100644
index 0000000..d869ee0
--- /dev/null
+++ b/src/core/load-dropin.c
@@ -0,0 +1,150 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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, UnitDependency dependency) {
+        DIR *d;
+        struct dirent *de;
+        int r;
+
+        assert(u);
+        assert(path);
+
+        d = opendir(path);
+        if (!d) {
+
+                if (errno == ENOENT)
+                        return 0;
+
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                char *f;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                f = join(path, "/", de->d_name, NULL);
+                if (!f) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
+                free(f);
+
+                if (r < 0)
+                        log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
+        }
+
+        r = 0;
+
+finish:
+        closedir(d);
+        return r;
+}
+
+static int process_dir(Unit *u, const char *unit_path, const char *name, const char *suffix, UnitDependency dependency) {
+        int r;
+        char *path;
+
+        assert(u);
+        assert(unit_path);
+        assert(name);
+        assert(suffix);
+
+        path = join(unit_path, "/", name, suffix, NULL);
+        if (!path)
+                return -ENOMEM;
+
+        if (u->manager->unit_path_cache &&
+            !set_get(u->manager->unit_path_cache, path))
+                r = 0;
+        else
+                r = iterate_dir(u, path, dependency);
+        free(path);
+
+        if (r < 0)
+                return r;
+
+        if (u->instance) {
+                char *template;
+                /* Also try the template dir */
+
+                template = unit_name_template(name);
+                if (!template)
+                        return -ENOMEM;
+
+                path = join(unit_path, "/", template, suffix, NULL);
+                free(template);
+
+                if (!path)
+                        return -ENOMEM;
+
+                if (u->manager->unit_path_cache &&
+                    !set_get(u->manager->unit_path_cache, path))
+                        r = 0;
+                else
+                        r = iterate_dir(u, path, dependency);
+                free(path);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int unit_load_dropin(Unit *u) {
+        Iterator i;
+        char *t;
+
+        assert(u);
+
+        /* Load dependencies from supplementary drop-in directories */
+
+        SET_FOREACH(t, u->names, i) {
+                char **p;
+
+                STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
+                        int r;
+
+                        r = process_dir(u, *p, t, ".wants", UNIT_WANTS);
+                        if (r < 0)
+                                return r;
+
+                        r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
new file mode 100644
index 0000000..cf3a799
--- /dev/null
+++ b/src/core/load-dropin.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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/core/load-fragment.c b/src/core/load-fragment.c
new file mode 100644
index 0000000..637c82b
--- /dev/null
+++ b/src/core/load-fragment.c
@@ -0,0 +1,2445 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.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"
+#include "bus-errors.h"
+#include "utf8.h"
+
+#ifndef HAVE_SYSV_COMPAT
+int config_parse_warn_compat(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
+        return 0;
+}
+#endif
+
+int config_parse_unit_deps(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        UnitDependency d = ltype;
+        Unit *u = userdata;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                char *t, *k;
+                int r;
+
+                t = strndup(w, l);
+                if (!t)
+                        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);
+                if (r < 0)
+                        log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
+
+                free(k);
+        }
+
+        return 0;
+}
+
+int config_parse_unit_names(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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_QUOTED(w, l, rvalue, state) {
+                char *t, *k;
+                int r;
+
+                t = strndup(w, l);
+                if (!t)
+                        return -ENOMEM;
+
+                k = unit_name_printf(u, t);
+                free(t);
+                if (!k)
+                        return -ENOMEM;
+
+                r = unit_merge_by_name(u, k);
+                if (r < 0)
+                        log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
+
+                free(k);
+        }
+
+        return 0;
+}
+
+int config_parse_unit_string_printf(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        k = unit_full_printf(u, rvalue);
+        if (!k)
+                return -ENOMEM;
+
+        r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
+        free (k);
+
+        return r;
+}
+
+int config_parse_unit_strv_printf(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        k = unit_full_printf(u, rvalue);
+        if (!k)
+                return -ENOMEM;
+
+        r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
+        free(k);
+
+        return r;
+}
+
+int config_parse_unit_path_printf(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        k = unit_full_printf(u, rvalue);
+        if (!k)
+                return -ENOMEM;
+
+        r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
+        free(k);
+
+        return r;
+}
+
+int config_parse_socket_listen(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        SocketPort *p, *tail;
+        Socket *s;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        s = SOCKET(data);
+
+        p = new0(SocketPort, 1);
+        if (!p)
+                return -ENOMEM;
+
+        if (streq(lvalue, "ListenFIFO")) {
+                p->type = SOCKET_FIFO;
+
+                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                path_kill_slashes(p->path);
+
+        } else if (streq(lvalue, "ListenSpecial")) {
+                p->type = SOCKET_SPECIAL;
+
+                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                path_kill_slashes(p->path);
+
+        } else if (streq(lvalue, "ListenMessageQueue")) {
+
+                p->type = SOCKET_MQUEUE;
+
+                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                path_kill_slashes(p->path);
+
+        } else if (streq(lvalue, "ListenNetlink")) {
+                char  *k;
+                int r;
+
+                p->type = SOCKET_SOCKET;
+                k = unit_full_printf(UNIT(s), rvalue);
+                r = socket_address_parse_netlink(&p->address, k);
+                free(k);
+
+                if (r < 0) {
+                        log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
+                        free(p);
+                        return 0;
+                }
+
+        } else {
+                char *k;
+                int r;
+
+                p->type = SOCKET_SOCKET;
+                k = unit_full_printf(UNIT(s), rvalue);
+                r = socket_address_parse(&p->address, k);
+                free(k);
+
+                if (r < 0) {
+                        log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
+                        free(p);
+                        return 0;
+                }
+
+                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) {
+                        log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
+                        free(p);
+                        return 0;
+                }
+        }
+
+        p->fd = -1;
+
+        if (s->ports) {
+                LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
+                LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
+        } else
+                LIST_PREPEND(SocketPort, port, s->ports, p);
+
+        return 0;
+}
+
+int config_parse_socket_bind(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Socket *s;
+        SocketAddressBindIPv6Only b;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        s = SOCKET(data);
+
+        if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
+                int r;
+
+                if ((r = parse_boolean(rvalue)) < 0) {
+                        log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+
+                s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
+        } else
+                s->bind_ipv6_only = b;
+
+        return 0;
+}
+
+int config_parse_exec_nice(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int priority;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atoi(rvalue, &priority) < 0) {
+                log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
+                return 0;
+        }
+
+        if (priority < PRIO_MIN || priority >= PRIO_MAX) {
+                log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->nice = priority;
+        c->nice_set = true;
+
+        return 0;
+}
+
+int config_parse_exec_oom_score_adjust(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        int oa;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atoi(rvalue, &oa) < 0) {
+                log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
+                log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->oom_score_adjust = oa;
+        c->oom_score_adjust_set = true;
+
+        return 0;
+}
+
+int config_parse_exec(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecCommand **e = data, *nce;
+        char *path, **n;
+        unsigned k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(e);
+
+        /* We accept an absolute path as first argument, or
+         * alternatively an absolute prefixed with @ to allow
+         * overriding of argv[0]. */
+
+        e += ltype;
+
+        for (;;) {
+                char *w;
+                size_t l;
+                char *state;
+                bool honour_argv0 = false, ignore = false;
+
+                path = NULL;
+                nce = NULL;
+                n = NULL;
+
+                rvalue += strspn(rvalue, WHITESPACE);
+
+                if (rvalue[0] == 0)
+                        break;
+
+                if (rvalue[0] == '-') {
+                        ignore = true;
+                        rvalue ++;
+                }
+
+                if (rvalue[0] == '@') {
+                        honour_argv0 = true;
+                        rvalue ++;
+                }
+
+                if (*rvalue != '/') {
+                        log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+
+                k = 0;
+                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                        if (strncmp(w, ";", MAX(l, 1U)) == 0)
+                                break;
+
+                        k++;
+                }
+
+                n = new(char*, k + !honour_argv0);
+                if (!n)
+                        return -ENOMEM;
+
+                k = 0;
+                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                        if (strncmp(w, ";", MAX(l, 1U)) == 0)
+                                break;
+
+                        if (honour_argv0 && w == rvalue) {
+                                assert(!path);
+
+                                path = strndup(w, l);
+                                if (!path) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                if (!utf8_is_valid(path)) {
+                                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
+                                        r = 0;
+                                        goto fail;
+                                }
+
+                        } else {
+                                char *c;
+
+                                c = n[k++] = cunescape_length(w, l);
+                                if (!c) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                if (!utf8_is_valid(c)) {
+                                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
+                                        r = 0;
+                                        goto fail;
+                                }
+                        }
+                }
+
+                n[k] = NULL;
+
+                if (!n[0]) {
+                        log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
+                        r = 0;
+                        goto fail;
+                }
+
+                if (!path) {
+                        path = strdup(n[0]);
+                        if (!path) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+                }
+
+                assert(path_is_absolute(path));
+
+                nce = new0(ExecCommand, 1);
+                if (!nce) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                nce->argv = n;
+                nce->path = path;
+                nce->ignore = ignore;
+
+                path_kill_slashes(nce->path);
+
+                exec_command_append_list(e, nce);
+
+                rvalue = state;
+        }
+
+        return 0;
+
+fail:
+        n[k] = NULL;
+        strv_free(n);
+        free(path);
+        free(nce);
+
+        return r;
+}
+
+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");
+
+int config_parse_socket_bindtodevice(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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");
+
+int config_parse_facility(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+
+        int *o = data, x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((x = log_facility_unshifted_from_string(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *o = (x << 3) | LOG_PRI(*o);
+
+        return 0;
+}
+
+int config_parse_level(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *o = (*o & LOG_FACMASK) | x;
+        return 0;
+}
+
+int config_parse_exec_io_class(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
+        c->ioprio_set = true;
+
+        return 0;
+}
+
+int config_parse_exec_io_priority(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
+        c->ioprio_set = true;
+
+        return 0;
+}
+
+int config_parse_exec_cpu_sched_policy(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->cpu_sched_policy = x;
+        c->cpu_sched_set = true;
+
+        return 0;
+}
+
+int config_parse_exec_cpu_sched_prio(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->cpu_sched_priority = i;
+        c->cpu_sched_set = true;
+
+        return 0;
+}
+
+int config_parse_exec_cpu_affinity(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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_QUOTED(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 (!(c->cpuset))
+                        if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
+                                return -ENOMEM;
+
+                if (r < 0 || cpu >= c->cpuset_ncpus) {
+                        log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+
+                CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
+        }
+
+        return 0;
+}
+
+int config_parse_exec_capabilities(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (c->capabilities)
+                cap_free(c->capabilities);
+        c->capabilities = cap;
+
+        return 0;
+}
+
+int config_parse_exec_secure_bits(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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_QUOTED(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, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+        }
+
+        return 0;
+}
+
+int config_parse_exec_bounding_set(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        char *w;
+        size_t l;
+        char *state;
+        bool invert = false;
+        uint64_t sum = 0;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (rvalue[0] == '~') {
+                invert = true;
+                rvalue++;
+        }
+
+        /* Note that we store this inverted internally, since the
+         * kernel wants it like this. But we actually expose it
+         * non-inverted everywhere to have a fully normalized
+         * interface. */
+
+        FOREACH_WORD_QUOTED(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, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+
+                sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+        }
+
+        if (invert)
+                c->capability_bounding_set_drop |= sum;
+        else
+                c->capability_bounding_set_drop |= ~sum;
+
+        return 0;
+}
+
+int config_parse_exec_timer_slack_nsec(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ExecContext *c = data;
+        unsigned long u;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atolu(rvalue, &u) < 0) {
+                log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c->timer_slack_nsec = u;
+
+        return 0;
+}
+
+int config_parse_limit(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        struct rlimit **rl = data;
+        unsigned long long u;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        rl += ltype;
+
+        if (streq(rvalue, "infinity"))
+                u = (unsigned long long) RLIM_INFINITY;
+        else if (safe_atollu(rvalue, &u) < 0) {
+                log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (!*rl)
+                if (!(*rl = new(struct rlimit, 1)))
+                        return -ENOMEM;
+
+        (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
+        return 0;
+}
+
+int config_parse_unit_cgroup(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *w;
+        size_t l;
+        char *state;
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                char *t, *k;
+                int r;
+
+                t = strndup(w, l);
+                if (!t)
+                        return -ENOMEM;
+
+                k = unit_full_printf(u, t);
+                free(t);
+
+                if (!k)
+                        return -ENOMEM;
+
+                t = cunescape(k);
+                free(k);
+
+                if (!t)
+                        return -ENOMEM;
+
+                r = unit_add_cgroup_from_text(u, t);
+                free(t);
+
+                if (r < 0) {
+                        log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+        }
+
+        return 0;
+}
+
+#ifdef HAVE_SYSV_COMPAT
+int config_parse_sysv_priority(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *priority = data;
+        int i;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atoi(rvalue, &i) < 0 || i < 0) {
+                log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *priority = (int) i;
+        return 0;
+}
+#endif
+
+int config_parse_fsck_passno(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *passno = data;
+        int i;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atoi(rvalue, &i) || i < 0) {
+                log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *passno = (int) i;
+        return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
+
+int config_parse_kill_signal(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *sig = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(sig);
+
+        if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
+                log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *sig = r;
+        return 0;
+}
+
+int config_parse_exec_mount_flags(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                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_QUOTED(w, l, rvalue, state) {
+                if (strncmp(w, "shared", MAX(l, 6U)) == 0)
+                        flags |= MS_SHARED;
+                else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
+                        flags |= MS_SLAVE;
+                else if (strncmp(w, "private", MAX(l, 7U)) == 0)
+                        flags |= MS_PRIVATE;
+                else {
+                        log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+        }
+
+        c->mount_flags = flags;
+        return 0;
+}
+
+int config_parse_timer(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Timer *t = data;
+        usec_t u;
+        TimerValue *v;
+        TimerBase b;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((b = timer_base_from_string(lvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
+                return 0;
+        }
+
+        if (parse_usec(rvalue, &u) < 0) {
+                log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (!(v = new0(TimerValue, 1)))
+                return -ENOMEM;
+
+        v->base = b;
+        v->value = u;
+
+        LIST_PREPEND(TimerValue, value, t->values, v);
+
+        return 0;
+}
+
+int config_parse_timer_unit(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Timer *t = data;
+        int r;
+        DBusError error;
+        Unit *u;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        dbus_error_init(&error);
+
+        if (endswith(rvalue, ".timer")) {
+                log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
+        if (r < 0) {
+                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+                dbus_error_free(&error);
+                return 0;
+        }
+
+        unit_ref_set(&t->unit, u);
+
+        return 0;
+}
+
+int config_parse_path_spec(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Path *p = data;
+        PathSpec *s;
+        PathType b;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((b = path_type_from_string(lvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
+                return 0;
+        }
+
+        if (!path_is_absolute(rvalue)) {
+                log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (!(s = new0(PathSpec, 1)))
+                return -ENOMEM;
+
+        if (!(s->path = strdup(rvalue))) {
+                free(s);
+                return -ENOMEM;
+        }
+
+        path_kill_slashes(s->path);
+
+        s->type = b;
+        s->inotify_fd = -1;
+
+        LIST_PREPEND(PathSpec, spec, p->specs, s);
+
+        return 0;
+}
+
+int config_parse_path_unit(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Path *t = data;
+        int r;
+        DBusError error;
+        Unit *u;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        dbus_error_init(&error);
+
+        if (endswith(rvalue, ".path")) {
+                log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
+                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+                dbus_error_free(&error);
+                return 0;
+        }
+
+        unit_ref_set(&t->unit, u);
+
+        return 0;
+}
+
+int config_parse_socket_service(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Socket *s = data;
+        int r;
+        DBusError error;
+        Unit *x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        dbus_error_init(&error);
+
+        if (!endswith(rvalue, ".service")) {
+                log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
+        if (r < 0) {
+                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+                dbus_error_free(&error);
+                return 0;
+        }
+
+        unit_ref_set(&s->service, x);
+
+        return 0;
+}
+
+int config_parse_service_sockets(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Service *s = data;
+        int r;
+        char *state, *w;
+        size_t l;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                char *t, *k;
+
+                t = strndup(w, l);
+                if (!t)
+                        return -ENOMEM;
+
+                k = unit_name_printf(UNIT(s), t);
+                free(t);
+
+                if (!k)
+                        return -ENOMEM;
+
+                if (!endswith(k, ".socket")) {
+                        log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
+                        free(k);
+                        continue;
+                }
+
+                r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
+                if (r < 0)
+                        log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
+
+                r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
+                if (r < 0)
+                        return r;
+
+                free(k);
+        }
+
+        return 0;
+}
+
+int config_parse_unit_env_file(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char ***env = data, **k;
+        Unit *u = userdata;
+        char *s;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        s = unit_full_printf(u, rvalue);
+        if (!s)
+                return -ENOMEM;
+
+        if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
+                log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
+                free(s);
+                return 0;
+        }
+
+        k = strv_append(*env, s);
+        free(s);
+        if (!k)
+                return -ENOMEM;
+
+        strv_free(*env);
+        *env = k;
+
+        return 0;
+}
+
+int config_parse_ip_tos(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *ip_tos = data, x;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((x = ip_tos_from_string(rvalue)) < 0)
+                if (safe_atoi(rvalue, &x) < 0) {
+                        log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
+
+        *ip_tos = x;
+        return 0;
+}
+
+int config_parse_unit_condition_path(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ConditionType cond = ltype;
+        Unit *u = data;
+        bool trigger, negate;
+        Condition *c;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        trigger = rvalue[0] == '|';
+        if (trigger)
+                rvalue++;
+
+        negate = rvalue[0] == '!';
+        if (negate)
+                rvalue++;
+
+        if (!path_is_absolute(rvalue)) {
+                log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        c = condition_new(cond, rvalue, trigger, negate);
+        if (!c)
+                return -ENOMEM;
+
+        LIST_PREPEND(Condition, conditions, u->conditions, c);
+        return 0;
+}
+
+int config_parse_unit_condition_string(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        ConditionType cond = ltype;
+        Unit *u = data;
+        bool trigger, negate;
+        Condition *c;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((trigger = rvalue[0] == '|'))
+                rvalue++;
+
+        if ((negate = rvalue[0] == '!'))
+                rvalue++;
+
+        if (!(c = condition_new(cond, rvalue, trigger, negate)))
+                return -ENOMEM;
+
+        LIST_PREPEND(Condition, conditions, u->conditions, c);
+        return 0;
+}
+
+int config_parse_unit_condition_null(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = data;
+        Condition *c;
+        bool trigger, negate;
+        int b;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if ((trigger = rvalue[0] == '|'))
+                rvalue++;
+
+        if ((negate = rvalue[0] == '!'))
+                rvalue++;
+
+        if ((b = parse_boolean(rvalue)) < 0) {
+                log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (!b)
+                negate = !negate;
+
+        if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
+                return -ENOMEM;
+
+        LIST_PREPEND(Condition, conditions, u->conditions, c);
+        return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
+
+int config_parse_unit_cgroup_attr(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = data;
+        char **l;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        l = strv_split_quoted(rvalue);
+        if (!l)
+                return -ENOMEM;
+
+        if (strv_length(l) != 2) {
+                log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
+        strv_free(l);
+
+        if (r < 0) {
+                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
+int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
+        Unit *u = data;
+        int r;
+        unsigned long ul;
+        char *t;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
+                log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (asprintf(&t, "%lu", ul) < 0)
+                return -ENOMEM;
+
+        r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
+        free(t);
+
+        if (r < 0) {
+                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
+int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
+        Unit *u = data;
+        int r;
+        off_t sz;
+        char *t;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
+                log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
+                return -ENOMEM;
+
+        r = unit_add_cgroup_attribute(u,
+                                      "memory",
+                                      streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
+                                      t, NULL);
+        free(t);
+
+        if (r < 0) {
+                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
+static int device_map(const char *controller, const char *name, const char *value, char **ret) {
+        char **l;
+
+        assert(controller);
+        assert(name);
+        assert(value);
+        assert(ret);
+
+        l = strv_split_quoted(value);
+        if (!l)
+                return -ENOMEM;
+
+        assert(strv_length(l) >= 1);
+
+        if (streq(l[0], "*")) {
+
+                if (asprintf(ret, "a *:*%s%s",
+                             isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+        } else {
+                struct stat st;
+
+                if (stat(l[0], &st) < 0) {
+                        log_warning("Couldn't stat device %s", l[0]);
+                        strv_free(l);
+                        return -errno;
+                }
+
+                if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
+                        log_warning("%s is not a device.", l[0]);
+                        strv_free(l);
+                        return -ENODEV;
+                }
+
+                if (asprintf(ret, "%c %u:%u%s%s",
+                             S_ISCHR(st.st_mode) ? 'c' : 'b',
+                             major(st.st_rdev), minor(st.st_rdev),
+                             isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
+
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+        }
+
+        strv_free(l);
+        return 0;
+}
+
+int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
+        Unit *u = data;
+        char **l;
+        int r;
+        unsigned k;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        l = strv_split_quoted(rvalue);
+        if (!l)
+                return -ENOMEM;
+
+        k = strv_length(l);
+        if (k < 1 || k > 2) {
+                log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
+                log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
+                log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+        strv_free(l);
+
+        r = unit_add_cgroup_attribute(u, "devices",
+                                      streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
+                                      rvalue, device_map);
+
+        if (r < 0) {
+                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
+static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
+        struct stat st;
+        char **l;
+        dev_t d;
+
+        assert(controller);
+        assert(name);
+        assert(value);
+        assert(ret);
+
+        l = strv_split_quoted(value);
+        if (!l)
+                return -ENOMEM;
+
+        assert(strv_length(l) == 2);
+
+        if (stat(l[0], &st) < 0) {
+                log_warning("Couldn't stat device %s", l[0]);
+                strv_free(l);
+                return -errno;
+        }
+
+        if (S_ISBLK(st.st_mode))
+                d = st.st_rdev;
+        else if (major(st.st_dev) != 0) {
+                /* If this is not a device node then find the block
+                 * device this file is stored on */
+                d = st.st_dev;
+
+                /* If this is a partition, try to get the originating
+                 * block device */
+                block_get_whole_disk(d, &d);
+        } else {
+                log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
+                strv_free(l);
+                return -ENODEV;
+        }
+
+        if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
+                strv_free(l);
+                return -ENOMEM;
+        }
+
+        strv_free(l);
+        return 0;
+}
+
+int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
+        Unit *u = data;
+        int r;
+        unsigned long ul;
+        const char *device = NULL, *weight;
+        unsigned k;
+        char *t, **l;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        l = strv_split_quoted(rvalue);
+        if (!l)
+                return -ENOMEM;
+
+        k = strv_length(l);
+        if (k < 1 || k > 2) {
+                log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (k == 1)
+                weight = l[0];
+        else {
+                device = l[0];
+                weight = l[1];
+        }
+
+        if (device && !path_is_absolute(device)) {
+                log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
+                log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (device)
+                r = asprintf(&t, "%s %lu", device, ul);
+        else
+                r = asprintf(&t, "%lu", ul);
+        strv_free(l);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        if (device)
+                r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
+        else
+                r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
+        free(t);
+
+        if (r < 0) {
+                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
+int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
+        Unit *u = data;
+        int r;
+        off_t bytes;
+        unsigned k;
+        char *t, **l;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        l = strv_split_quoted(rvalue);
+        if (!l)
+                return -ENOMEM;
+
+        k = strv_length(l);
+        if (k != 2) {
+                log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (!path_is_absolute(l[0])) {
+                log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
+                log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
+                strv_free(l);
+                return 0;
+        }
+
+        r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
+        strv_free(l);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        r = unit_add_cgroup_attribute(u, "blkio",
+                                      streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
+                                      t, blkio_map);
+        free(t);
+
+        if (r < 0) {
+                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        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, *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, but only if it is a valid
+                 * unit name. */
+                name = file_name_from_path(*filename);
+
+                if (unit_name_is_valid(name, true)) {
+
+                        id = set_get(names, name);
+                        if (!id) {
+                                id = strdup(name);
+                                if (!id)
+                                        return -ENOMEM;
+
+                                r = set_put(names, id);
+                                if (r < 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_and_make_absolute(*filename, &target)) < 0)
+                        return r;
+
+                free(*filename);
+                *filename = target;
+        }
+
+        if (!(f = fdopen(fd, "re"))) {
+                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)->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 int load_from_path(Unit *u, const char *path) {
+        int r;
+        Set *symlink_names;
+        FILE *f = NULL;
+        char *filename = NULL, *id = NULL;
+        Unit *merged;
+        struct stat st;
+
+        assert(u);
+        assert(path);
+
+        symlink_names = set_new(string_hash_func, string_compare_func);
+        if (!symlink_names)
+                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->manager->lookup_paths.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 (u->manager->unit_path_cache &&
+                            !set_get(u->manager->unit_path_cache, filename))
+                                r = -ENOENT;
+                        else
+                                r = open_follow(&filename, &f, symlink_names, &id);
+
+                        if (r < 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) {
+                /* Hmm, no suitable file found? */
+                r = 0;
+                goto finish;
+        }
+
+        merged = u;
+        if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
+                goto finish;
+
+        if (merged != u) {
+                u->load_state = UNIT_MERGED;
+                r = 0;
+                goto finish;
+        }
+
+        zero(st);
+        if (fstat(fileno(f), &st) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (null_or_empty(&st))
+                u->load_state = UNIT_MASKED;
+        else {
+                /* Now, parse the file contents */
+                r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
+                if (r < 0)
+                        goto finish;
+
+                u->load_state = UNIT_LOADED;
+        }
+
+        free(u->fragment_path);
+        u->fragment_path = filename;
+        filename = NULL;
+
+        u->fragment_mtime = timespec_load(&st.st_mtim);
+
+        r = 0;
+
+finish:
+        set_free_free(symlink_names);
+        free(filename);
+
+        if (f)
+                fclose(f);
+
+        return r;
+}
+
+int unit_load_fragment(Unit *u) {
+        int r;
+        Iterator i;
+        const char *t;
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+        assert(u->id);
+
+        /* First, try to find the unit under its id. We always look
+         * for unit files in the default directories, to make it easy
+         * to override things by placing things in /etc/systemd/system */
+        if ((r = load_from_path(u, u->id)) < 0)
+                return r;
+
+        /* Try to find an alias we can load this with */
+        if (u->load_state == UNIT_STUB)
+                SET_FOREACH(t, u->names, i) {
+
+                        if (t == u->id)
+                                continue;
+
+                        if ((r = load_from_path(u, t)) < 0)
+                                return r;
+
+                        if (u->load_state != UNIT_STUB)
+                                break;
+                }
+
+        /* And now, try looking for it under the suggested (originally linked) path */
+        if (u->load_state == UNIT_STUB && u->fragment_path) {
+
+                if ((r = load_from_path(u, u->fragment_path)) < 0)
+                        return r;
+
+                if (u->load_state == UNIT_STUB) {
+                        /* Hmm, this didn't work? Then let's get rid
+                         * of the fragment path stored for us, so that
+                         * we don't point to an invalid location. */
+                        free(u->fragment_path);
+                        u->fragment_path = NULL;
+                }
+        }
+
+        /* Look for a template */
+        if (u->load_state == UNIT_STUB && u->instance) {
+                char *k;
+
+                if (!(k = unit_name_template(u->id)))
+                        return -ENOMEM;
+
+                r = load_from_path(u, k);
+                free(k);
+
+                if (r < 0)
+                        return r;
+
+                if (u->load_state == UNIT_STUB)
+                        SET_FOREACH(t, u->names, i) {
+
+                                if (t == u->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->load_state != UNIT_STUB)
+                                        break;
+                        }
+        }
+
+        return 0;
+}
+
+void unit_dump_config_items(FILE *f) {
+        static const struct {
+                const ConfigParserCallback callback;
+                const char *rvalue;
+        } table[] = {
+                { config_parse_int,                   "INTEGER" },
+                { config_parse_unsigned,              "UNSIGNED" },
+                { config_parse_bytes_size,            "SIZE" },
+                { config_parse_bool,                  "BOOLEAN" },
+                { config_parse_string,                "STRING" },
+                { config_parse_path,                  "PATH" },
+                { config_parse_unit_path_printf,      "PATH" },
+                { config_parse_strv,                  "STRING [...]" },
+                { config_parse_exec_nice,             "NICE" },
+                { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
+                { config_parse_exec_io_class,         "IOCLASS" },
+                { config_parse_exec_io_priority,      "IOPRIORITY" },
+                { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
+                { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
+                { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
+                { config_parse_mode,                  "MODE" },
+                { config_parse_unit_env_file,         "FILE" },
+                { config_parse_output,                "OUTPUT" },
+                { config_parse_input,                 "INPUT" },
+                { config_parse_facility,              "FACILITY" },
+                { config_parse_level,                 "LEVEL" },
+                { config_parse_exec_capabilities,     "CAPABILITIES" },
+                { config_parse_exec_secure_bits,      "SECUREBITS" },
+                { config_parse_exec_bounding_set,     "BOUNDINGSET" },
+                { config_parse_exec_timer_slack_nsec, "TIMERSLACK" },
+                { config_parse_limit,                 "LIMIT" },
+                { config_parse_unit_cgroup,           "CGROUP [...]" },
+                { config_parse_unit_deps,             "UNIT [...]" },
+                { config_parse_unit_names,            "UNIT [...]" },
+                { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
+                { config_parse_service_type,          "SERVICETYPE" },
+                { config_parse_service_restart,       "SERVICERESTART" },
+#ifdef HAVE_SYSV_COMPAT
+                { config_parse_sysv_priority,         "SYSVPRIORITY" },
+#else
+                { config_parse_warn_compat,           "NOTSUPPORTED" },
+#endif
+                { config_parse_kill_mode,             "KILLMODE" },
+                { config_parse_kill_signal,           "SIGNAL" },
+                { config_parse_socket_listen,         "SOCKET [...]" },
+                { config_parse_socket_bind,           "SOCKETBIND" },
+                { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
+                { config_parse_usec,                  "SECONDS" },
+                { config_parse_path_strv,             "PATH [...]" },
+                { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
+                { config_parse_unit_string_printf,    "STRING" },
+                { config_parse_timer,                 "TIMER" },
+                { config_parse_timer_unit,            "NAME" },
+                { config_parse_path_spec,             "PATH" },
+                { config_parse_path_unit,             "UNIT" },
+                { config_parse_notify_access,         "ACCESS" },
+                { config_parse_ip_tos,                "TOS" },
+                { config_parse_unit_condition_path,   "CONDITION" },
+                { config_parse_unit_condition_string, "CONDITION" },
+                { config_parse_unit_condition_null,   "CONDITION" },
+        };
+
+        const char *prev = NULL;
+        const char *i;
+
+        assert(f);
+
+        NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
+                const char *rvalue = "OTHER", *lvalue;
+                unsigned j;
+                size_t prefix_len;
+                const char *dot;
+                const ConfigPerfItem *p;
+
+                assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
+
+                dot = strchr(i, '.');
+                lvalue = dot ? dot + 1 : i;
+                prefix_len = dot-i;
+
+                if (dot)
+                        if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
+                                if (prev)
+                                        fputc('\n', f);
+
+                                fprintf(f, "[%.*s]\n", (int) prefix_len, i);
+                        }
+
+                for (j = 0; j < ELEMENTSOF(table); j++)
+                        if (p->parse == table[j].callback) {
+                                rvalue = table[j].rvalue;
+                                break;
+                        }
+
+                fprintf(f, "%s=%s\n", lvalue, rvalue);
+                prev = i;
+        }
+}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
new file mode 100644
index 0000000..79fc76d
--- /dev/null
+++ b/src/core/load-fragment.h
@@ -0,0 +1,91 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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);
+
+int config_parse_warn_compat(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_deps(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_names(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_socket_listen(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_socket_bind(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_oom_score_adjust(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_service_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_service_restart(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_socket_bindtodevice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_output(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_input(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_io_class(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_io_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_cpu_sched_policy(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_cpu_sched_prio(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_timer_slack_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_sysv_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_fsck_passno(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_kill_signal(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_mount_flags(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_timer(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_timer_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_path_spec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_path_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_socket_service(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_service_sockets(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_env_file(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_ip_tos(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_condition_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_condition_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_notify_access(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_start_limit_action(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+
+/* gperf prototypes */
+const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
+extern const char load_fragment_gperf_nulstr[];
+
+#endif
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
new file mode 100644
index 0000000..7f692e9
--- /dev/null
+++ b/src/core/locale-setup.c
@@ -0,0 +1,251 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <stdlib.h>
+#include <errno.h>
+
+#include "locale-setup.h"
+#include "util.h"
+#include "macro.h"
+#include "virt.h"
+
+enum {
+        /* We don't list LC_ALL here on purpose. People should be
+         * using LANG instead. */
+
+        VARIABLE_LANG,
+        VARIABLE_LANGUAGE,
+        VARIABLE_LC_CTYPE,
+        VARIABLE_LC_NUMERIC,
+        VARIABLE_LC_TIME,
+        VARIABLE_LC_COLLATE,
+        VARIABLE_LC_MONETARY,
+        VARIABLE_LC_MESSAGES,
+        VARIABLE_LC_PAPER,
+        VARIABLE_LC_NAME,
+        VARIABLE_LC_ADDRESS,
+        VARIABLE_LC_TELEPHONE,
+        VARIABLE_LC_MEASUREMENT,
+        VARIABLE_LC_IDENTIFICATION,
+        _VARIABLE_MAX
+};
+
+static const char * const variable_names[_VARIABLE_MAX] = {
+        [VARIABLE_LANG] = "LANG",
+        [VARIABLE_LANGUAGE] = "LANGUAGE",
+        [VARIABLE_LC_CTYPE] = "LC_CTYPE",
+        [VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
+        [VARIABLE_LC_TIME] = "LC_TIME",
+        [VARIABLE_LC_COLLATE] = "LC_COLLATE",
+        [VARIABLE_LC_MONETARY] = "LC_MONETARY",
+        [VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
+        [VARIABLE_LC_PAPER] = "LC_PAPER",
+        [VARIABLE_LC_NAME] = "LC_NAME",
+        [VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
+        [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
+        [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
+        [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
+};
+
+int locale_setup(void) {
+        char *variables[_VARIABLE_MAX];
+        int r = 0, i;
+
+        zero(variables);
+
+        if (detect_container(NULL) <= 0)
+                if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
+#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
+                                        "LANG",                     &variables[VARIABLE_LANG],
+#endif
+                                        "locale.LANG",              &variables[VARIABLE_LANG],
+                                        "locale.LANGUAGE",          &variables[VARIABLE_LANGUAGE],
+                                        "locale.LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
+                                        "locale.LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
+                                        "locale.LC_TIME",           &variables[VARIABLE_LC_TIME],
+                                        "locale.LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
+                                        "locale.LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
+                                        "locale.LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
+                                        "locale.LC_PAPER",          &variables[VARIABLE_LC_PAPER],
+                                        "locale.LC_NAME",           &variables[VARIABLE_LC_NAME],
+                                        "locale.LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
+                                        "locale.LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
+                                        "locale.LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
+                                        "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
+                                        NULL)) < 0) {
+
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
+                }
+
+        /* Hmm, nothing set on the kernel cmd line? Then let's
+         * try /etc/locale.conf */
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/locale.conf", NEWLINE,
+                               "LANG",              &variables[VARIABLE_LANG],
+                               "LANGUAGE",          &variables[VARIABLE_LANGUAGE],
+                               "LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
+                               "LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
+                               "LC_TIME",           &variables[VARIABLE_LC_TIME],
+                               "LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
+                               "LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
+                               "LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
+                               "LC_PAPER",          &variables[VARIABLE_LC_PAPER],
+                               "LC_NAME",           &variables[VARIABLE_LC_NAME],
+                               "LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
+                               "LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
+                               "LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
+                               "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/locale.conf: %s", strerror(-r));
+        }
+
+#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MEEGO)
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
+                                "LANG", &variables[VARIABLE_LANG],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
+        }
+
+#elif defined(TARGET_SUSE)
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/sysconfig/language", NEWLINE,
+                                "RC_LANG", &variables[VARIABLE_LANG],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/sysconfig/language: %s", strerror(-r));
+        }
+
+#elif defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/default/locale", NEWLINE,
+                                "LANG",              &variables[VARIABLE_LANG],
+                                "LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
+                                "LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
+                                "LC_TIME",           &variables[VARIABLE_LC_TIME],
+                                "LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
+                                "LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
+                                "LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
+                                "LC_PAPER",          &variables[VARIABLE_LC_PAPER],
+                                "LC_NAME",           &variables[VARIABLE_LC_NAME],
+                                "LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
+                                "LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
+                                "LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
+                                "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/default/locale: %s", strerror(-r));
+        }
+
+#elif defined(TARGET_ARCH)
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/rc.conf", NEWLINE,
+                                "LOCALE", &variables[VARIABLE_LANG],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
+        }
+
+#elif defined(TARGET_GENTOO)
+        /* Gentoo's openrc expects locale variables in /etc/env.d/
+         * These files are later compiled by env-update into shell
+         * export commands at /etc/profile.env, with variables being
+         * exported by openrc's runscript (so /etc/init.d/)
+         */
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/profile.env", NEWLINE,
+                                "export LANG",              &variables[VARIABLE_LANG],
+                                "export LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
+                                "export LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
+                                "export LC_TIME",           &variables[VARIABLE_LC_TIME],
+                                "export LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
+                                "export LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
+                                "export LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
+                                "export LC_PAPER",          &variables[VARIABLE_LC_PAPER],
+                                "export LC_NAME",           &variables[VARIABLE_LC_NAME],
+                                "export LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
+                                "export LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
+                                "export LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
+                                "export LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/profile.env: %s", strerror(-r));
+        }
+#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA )
+        if (r <= 0 &&
+            (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
+                                "LANG",              &variables[VARIABLE_LANG],
+                                "LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
+                                "LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
+                                "LC_TIME",           &variables[VARIABLE_LC_TIME],
+                                "LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
+                                "LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
+                                "LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
+                                "LC_PAPER",          &variables[VARIABLE_LC_PAPER],
+                                "LC_NAME",           &variables[VARIABLE_LC_NAME],
+                                "LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
+                                "LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
+                                "LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
+                                "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
+        }
+
+#endif
+
+        if (!variables[VARIABLE_LANG]) {
+                if (!(variables[VARIABLE_LANG] = strdup("C"))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+        }
+
+        for (i = 0; i < _VARIABLE_MAX; i++) {
+
+                if (variables[i]) {
+                        if (setenv(variable_names[i], variables[i], 1) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+                } else
+                        unsetenv(variable_names[i]);
+        }
+
+        r = 0;
+
+finish:
+        for (i = 0; i < _VARIABLE_MAX; i++)
+                free(variables[i]);
+
+        return r;
+}
diff --git a/src/core/locale-setup.h b/src/core/locale-setup.h
new file mode 100644
index 0000000..09a6bc6
--- /dev/null
+++ b/src/core/locale-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foolocalesetuphfoo
+#define foolocalesetuphfoo
+
+/***
+  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 locale_setup(void);
+
+#endif
diff --git a/src/core/manager.c b/src/core/manager.c
new file mode 100644
index 0000000..312527a
--- /dev/null
+++ b/src/core/manager.c
@@ -0,0 +1,3235 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <sys/poll.h>
+#include <sys/reboot.h>
+#include <sys/ioctl.h>
+#include <linux/kd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#ifdef HAVE_AUDIT
+#include <libaudit.h>
+#endif
+
+#include <systemd/sd-daemon.h>
+
+#include "manager.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "strv.h"
+#include "log.h"
+#include "util.h"
+#include "mkdir.h"
+#include "ratelimit.h"
+#include "cgroup.h"
+#include "mount-setup.h"
+#include "unit-name.h"
+#include "dbus-unit.h"
+#include "dbus-job.h"
+#include "missing.h"
+#include "path-lookup.h"
+#include "special.h"
+#include "bus-errors.h"
+#include "exit-status.h"
+#include "virt.h"
+#include "watchdog.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)
+
+/* Where clients shall send notification messages to */
+#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify"
+#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify"
+
+static int manager_setup_notify(Manager *m) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_un un;
+        } sa;
+        struct epoll_event ev;
+        int one = 1, r;
+        mode_t u;
+
+        assert(m);
+
+        m->notify_watch.type = WATCH_NOTIFY;
+        if ((m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
+                log_error("Failed to allocate notification socket: %m");
+                return -errno;
+        }
+
+        zero(sa);
+        sa.sa.sa_family = AF_UNIX;
+
+        if (getpid() != 1)
+                snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull());
+        else {
+                unlink(NOTIFY_SOCKET_SYSTEM);
+                strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path));
+        }
+
+        if (sa.un.sun_path[0] == '@')
+                sa.un.sun_path[0] = 0;
+
+        u = umask(0111);
+        r = bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
+        umask(u);
+
+        if (r < 0) {
+                log_error("bind() failed: %m");
+                return -errno;
+        }
+
+        if (setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
+                log_error("SO_PASSCRED failed: %m");
+                return -errno;
+        }
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.ptr = &m->notify_watch;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
+                return -errno;
+
+        if (sa.un.sun_path[0] == 0)
+                sa.un.sun_path[0] = '@';
+
+        if (!(m->notify_socket = strdup(sa.un.sun_path)))
+                return -ENOMEM;
+
+        log_debug("Using notification socket %s", m->notify_socket);
+
+        return 0;
+}
+
+static int enable_special_signals(Manager *m) {
+        int 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|O_CLOEXEC)) < 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);
+
+        sigset_add_many(&mask,
+                        SIGCHLD,     /* Child died */
+                        SIGTERM,     /* Reexecute daemon */
+                        SIGHUP,      /* Reload configuration */
+                        SIGUSR1,     /* systemd/upstart: reconnect to D-Bus */
+                        SIGUSR2,     /* systemd: dump status */
+                        SIGINT,      /* Kernel sends us this on control-alt-del */
+                        SIGWINCH,    /* Kernel sends us this on kbrequest (alt-arrowup) */
+                        SIGPWR,      /* Some kernel drivers and upsd send us this on power failure */
+                        SIGRTMIN+0,  /* systemd: start default.target */
+                        SIGRTMIN+1,  /* systemd: isolate rescue.target */
+                        SIGRTMIN+2,  /* systemd: isolate emergency.target */
+                        SIGRTMIN+3,  /* systemd: start halt.target */
+                        SIGRTMIN+4,  /* systemd: start poweroff.target */
+                        SIGRTMIN+5,  /* systemd: start reboot.target */
+                        SIGRTMIN+6,  /* systemd: start kexec.target */
+                        SIGRTMIN+13, /* systemd: Immediate halt */
+                        SIGRTMIN+14, /* systemd: Immediate poweroff */
+                        SIGRTMIN+15, /* systemd: Immediate reboot */
+                        SIGRTMIN+16, /* systemd: Immediate kexec */
+                        SIGRTMIN+20, /* systemd: enable status messages */
+                        SIGRTMIN+21, /* systemd: disable status messages */
+                        SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
+                        SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
+                        SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
+                        SIGRTMIN+27, /* systemd: set log target to console */
+                        SIGRTMIN+28, /* systemd: set log target to kmsg */
+                        SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
+                        -1);
+        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_SYSTEM)
+                return enable_special_signals(m);
+
+        return 0;
+}
+
+static void manager_strip_environment(Manager *m) {
+        assert(m);
+
+        /* Remove variables from the inherited set that are part of
+         * the container interface:
+         * http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface */
+        strv_remove_prefix(m->environment, "container=");
+        strv_remove_prefix(m->environment, "container_");
+
+        /* Remove variables from the inherited set that are part of
+         * the initrd interface:
+         * http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface */
+        strv_remove_prefix(m->environment, "RD_");
+}
+
+int manager_new(ManagerRunningAs running_as, 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;
+
+        dual_timestamp_get(&m->startup_timestamp);
+
+        m->running_as = running_as;
+        m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
+        m->exit_code = _MANAGER_EXIT_CODE_INVALID;
+        m->pin_cgroupfs_fd = -1;
+
+#ifdef HAVE_AUDIT
+        m->audit_fd = -1;
+#endif
+
+        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
+        m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
+
+        m->environment = strv_copy(environ);
+        if (!m->environment)
+                goto fail;
+
+        manager_strip_environment(m);
+
+        if (running_as == MANAGER_SYSTEM) {
+                m->default_controllers = strv_new("cpu", NULL);
+                if (!m->default_controllers)
+                        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 = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
+                goto fail;
+
+        if ((r = manager_setup_signals(m)) < 0)
+                goto fail;
+
+        if ((r = manager_setup_cgroup(m)) < 0)
+                goto fail;
+
+        if ((r = manager_setup_notify(m)) < 0)
+                goto fail;
+
+        /* Try to connect to the busses, if possible. */
+        if ((r = bus_init(m, running_as != MANAGER_SYSTEM)) < 0)
+                goto fail;
+
+#ifdef HAVE_AUDIT
+        if ((m->audit_fd = audit_open()) < 0 &&
+            /* If the kernel lacks netlink or audit support,
+             * don't worry about it. */
+            errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
+                log_error("Failed to connect to audit log: %m");
+#endif
+
+        m->taint_usr = dir_is_empty("/usr") > 0;
+
+        *_m = m;
+        return 0;
+
+fail:
+        manager_free(m);
+        return r;
+}
+
+static unsigned manager_dispatch_cleanup_queue(Manager *m) {
+        Unit *u;
+        unsigned n = 0;
+
+        assert(m);
+
+        while ((u = m->cleanup_queue)) {
+                assert(u->in_cleanup_queue);
+
+                unit_free(u);
+                n++;
+        }
+
+        return n;
+}
+
+enum {
+        GC_OFFSET_IN_PATH,  /* This one is on the path we were traveling */
+        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->gc_marker == gc_marker + GC_OFFSET_GOOD ||
+            u->gc_marker == gc_marker + GC_OFFSET_BAD ||
+            u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
+                return;
+
+        if (u->in_cleanup_queue)
+                goto bad;
+
+        if (unit_check_gc(u))
+                goto good;
+
+        u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
+
+        is_bad = true;
+
+        SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
+                unit_gc_sweep(other, gc_marker);
+
+                if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
+                        goto good;
+
+                if (other->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->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->gc_marker = gc_marker + GC_OFFSET_BAD;
+        unit_add_to_cleanup_queue(u);
+        return;
+
+good:
+        u->gc_marker = gc_marker + GC_OFFSET_GOOD;
+}
+
+static unsigned manager_dispatch_gc_queue(Manager *m) {
+        Unit *u;
+        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 ((u = m->gc_queue)) {
+                assert(u->in_gc_queue);
+
+                unit_gc_sweep(u, gc_marker);
+
+                LIST_REMOVE(Unit, gc_queue, m->gc_queue, u);
+                u->in_gc_queue = false;
+
+                n++;
+
+                if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
+                    u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
+                        log_debug("Collecting %s", u->id);
+                        u->gc_marker = gc_marker + GC_OFFSET_BAD;
+                        unit_add_to_cleanup_queue(u);
+                }
+        }
+
+        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);
+
+        manager_dispatch_cleanup_queue(m);
+
+        assert(!m->load_queue);
+        assert(!m->run_queue);
+        assert(!m->dbus_unit_queue);
+        assert(!m->dbus_job_queue);
+        assert(!m->cleanup_queue);
+        assert(!m->gc_queue);
+
+        assert(hashmap_isempty(m->transaction_jobs));
+        assert(hashmap_isempty(m->jobs));
+        assert(hashmap_isempty(m->units));
+}
+
+void manager_free(Manager *m) {
+        UnitType c;
+
+        assert(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);
+
+        manager_undo_generators(m);
+
+        bus_done(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);
+        if (m->notify_watch.fd >= 0)
+                close_nointr_nofail(m->notify_watch.fd);
+
+#ifdef HAVE_AUDIT
+        if (m->audit_fd >= 0)
+                audit_close(m->audit_fd);
+#endif
+
+        free(m->notify_socket);
+
+        lookup_paths_free(&m->lookup_paths);
+        strv_free(m->environment);
+
+        strv_free(m->default_controllers);
+
+        hashmap_free(m->cgroup_bondings);
+        set_free_free(m->unit_path_cache);
+
+        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->id != k)
+                        continue;
+
+                if ((q = unit_coldplug(u)) < 0)
+                        r = q;
+        }
+
+        return r;
+}
+
+static void manager_build_unit_path_cache(Manager *m) {
+        char **i;
+        DIR *d = NULL;
+        int r;
+
+        assert(m);
+
+        set_free_free(m->unit_path_cache);
+
+        if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) {
+                log_error("Failed to allocate unit path cache.");
+                return;
+        }
+
+        /* This simply builds a list of files we know exist, so that
+         * we don't always have to go to disk */
+
+        STRV_FOREACH(i, m->lookup_paths.unit_path) {
+                struct dirent *de;
+
+                if (!(d = opendir(*i))) {
+                        log_error("Failed to open directory: %m");
+                        continue;
+                }
+
+                while ((de = readdir(d))) {
+                        char *p;
+
+                        if (ignore_file(de->d_name))
+                                continue;
+
+                        p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
+                        if (!p) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        if ((r = set_put(m->unit_path_cache, p)) < 0) {
+                                free(p);
+                                goto fail;
+                        }
+                }
+
+                closedir(d);
+                d = NULL;
+        }
+
+        return;
+
+fail:
+        log_error("Failed to build unit path cache: %s", strerror(-r));
+
+        set_free_free(m->unit_path_cache);
+        m->unit_path_cache = NULL;
+
+        if (d)
+                closedir(d);
+}
+
+int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+        int r, q;
+
+        assert(m);
+
+        manager_run_generators(m);
+
+        manager_build_unit_path_cache(m);
+
+        /* If we will deserialize make sure that during enumeration
+         * this is already known, so we increase the counter here
+         * already */
+        if (serialization)
+                m->n_reloading ++;
+
+        /* 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;
+
+        if (serialization) {
+                assert(m->n_reloading > 0);
+                m->n_reloading --;
+        }
+
+        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 bool job_is_conflicted_by(Job *j) {
+        JobDependency *l;
+
+        assert(j);
+
+        /* Returns true if this job is pulled in by a least one
+         * ConflictedBy dependency. */
+
+        LIST_FOREACH(object, l, j->object_list)
+                if (l->conflicts)
+                        return true;
+
+        return false;
+}
+
+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
+         * with 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 && !k->matters_to_anchor) {
+
+                                /* Both jobs don't matter, so let's
+                                 * find the one that is smarter to
+                                 * remove. Let's think positive and
+                                 * rather remove stops then starts --
+                                 * except if something is being
+                                 * stopped because it is conflicted by
+                                 * another unit in which case we
+                                 * rather remove the start. */
+
+                                log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
+                                log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
+
+                                if (j->type == JOB_STOP) {
+
+                                        if (job_is_conflicted_by(j))
+                                                d = k;
+                                        else
+                                                d = j;
+
+                                } else if (k->type == JOB_STOP) {
+
+                                        if (job_is_conflicted_by(k))
+                                                d = j;
+                                        else
+                                                d = k;
+                                } else
+                                        d = j;
+
+                        } else 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("Fixing conflicting jobs by deleting job %s/%s", d->unit->id, job_type_to_string(d->type));
+                        transaction_delete_job(m, d, true);
+                        return 0;
+                }
+
+        return -EINVAL;
+}
+
+static int transaction_merge_jobs(Manager *m, DBusError *e) {
+        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 (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 */
+                        dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.",
+                                       job_type_to_string(t), job_type_to_string(k->type), k->unit->id);
+                        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->job)
+                        job_type_merge(&t, j->unit->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);
+                }
+
+                if (j->unit->job && !j->installed)
+                        transaction_merge_and_delete_job(m, j, j->unit->job, 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) &&
+                                    (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) &&
+                                    (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type)))
+                                        continue;
+
+                                changes_something = true;
+                                break;
+                        }
+
+                        if (changes_something)
+                                continue;
+
+                        /* log_debug("Found redundant job %s/%s, dropping.", j->unit->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, DBusError *e) {
+        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. */
+
+        /* Have we seen this before? */
+        if (j->generation == generation) {
+                Job *k, *delete;
+
+                /* If the marker is NULL we have been here already and
+                 * decided the job was loop-free from here. Hence
+                 * shortcut things and return right-away. */
+                if (!j->marker)
+                        return 0;
+
+                /* So, the marker is not NULL and 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_warning("Found ordering cycle on %s/%s", j->unit->id, job_type_to_string(j->type));
+
+                delete = NULL;
+                for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
+
+                        log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type));
+
+                        if (!delete &&
+                            !k->installed &&
+                            !unit_matters_to_anchor(k->unit, k)) {
+                                /* Ok, we can drop this one, so let's
+                                 * do so. */
+                                delete = k;
+                        }
+
+                        /* Check if this in fact was the beginning of
+                         * the cycle */
+                        if (k == j)
+                                break;
+                }
+
+
+                if (delete) {
+                        log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type));
+                        transaction_delete_unit(m, delete->unit);
+                        return -EAGAIN;
+                }
+
+                log_error("Unable to break cycle");
+
+                dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details.");
+                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. We use
+         * a special marker for the beginning: we point to
+         * ourselves. */
+        j->marker = from ? from : j;
+        j->generation = generation;
+
+        /* We assume that the the dependencies are bidirectional, and
+         * hence can ignore UNIT_AFTER */
+        SET_FOREACH(u, j->unit->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->job))
+                                continue;
+
+                if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 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, DBusError *e) {
+        Job *j;
+        int r;
+        Iterator i;
+        unsigned g;
+
+        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. */
+
+        g = (*generation)++;
+
+        HASHMAP_FOREACH(j, m->transaction_jobs, i)
+                if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 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) {
+                                /* log_debug("Keeping job %s/%s because of %s/%s", */
+                                /*           j->unit->id, job_type_to_string(j->type), */
+                                /*           j->object_list->subject ? j->object_list->subject->unit->id : "root", */
+                                /*           j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
+                                continue;
+                        }
+
+                        /* log_debug("Garbage collecting job %s/%s", j->unit->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, DBusError *e) {
+        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->job &&
+                    j->unit->job != j &&
+                    !job_type_is_superset(j->type, j->unit->job->type)) {
+
+                        dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
+                        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->job &&
+                                        job_type_is_conflicting(j->type, j->unit->job->type);
+
+                                if (!stops_running_service && !changes_existing_job)
+                                        continue;
+
+                                if (stops_running_service)
+                                        log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type));
+
+                                if (changes_existing_job)
+                                        log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type));
+
+                                /* Ok, let's get rid of this */
+                                log_debug("Deleting %s/%s to minimize impact.", j->unit->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, JobMode mode) {
+        Iterator i;
+        Job *j;
+        int r;
+
+        /* Moves the transaction jobs to the set of active jobs */
+
+        if (mode == JOB_ISOLATE) {
+
+                /* When isolating first kill all installed jobs which
+                 * aren't part of the new transaction */
+        rescan:
+                HASHMAP_FOREACH(j, m->jobs, i) {
+                        assert(j->installed);
+
+                        if (hashmap_get(m->transaction_jobs, j->unit))
+                                continue;
+
+                        /* 'j' itself is safe to remove, but if other jobs
+                           are invalidated recursively, our iterator may become
+                           invalid and we need to start over. */
+                        if (job_finish_and_invalidate(j, JOB_CANCELED) > 0)
+                                goto rescan;
+                }
+        }
+
+        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) {
+                        /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */
+                        continue;
+                }
+
+                if (j->unit->job)
+                        job_free(j->unit->job);
+
+                j->unit->job = j;
+                j->installed = true;
+                m->n_installed_jobs ++;
+
+                /* 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);
+                job_start_timer(j);
+
+                log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
+        }
+
+        /* 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, DBusError *e) {
+        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. */
+        if (mode == JOB_FAIL)
+                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. */
+                if (mode != JOB_ISOLATE)
+                        transaction_collect_garbage(m);
+
+                /* Fifth step: verify order makes sense and correct
+                 * cycles if necessary and possible */
+                if ((r = transaction_verify_order(m, &generation, e)) >= 0)
+                        break;
+
+                if (r != -EAGAIN) {
+                        log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, 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, e)) >= 0)
+                        break;
+
+                if (r != -EAGAIN) {
+                        log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
+                        goto rollback;
+                }
+
+                /* Seventh step: an entry got dropped, let's garbage
+                 * collect its dependencies. */
+                if (mode != JOB_ISOLATE)
+                        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, e)) < 0) {
+                        log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
+                        goto rollback;
+                }
+
+        /* Tenth step: apply changes */
+        if ((r = transaction_apply(m, mode)) < 0) {
+                log_warning("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;
+
+        assert(m);
+        assert(unit);
+
+        /* Looks for an existing 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->job && unit->job->type == type)
+                j = unit->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 (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->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->id, job_type_to_string(other->type),
+                                  j->unit->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,
+                bool conflicts,
+                bool ignore_requirements,
+                bool ignore_order,
+                DBusError *e,
+                Job **_ret) {
+        Job *ret;
+        Iterator i;
+        Unit *dep;
+        int r;
+        bool is_new;
+
+        assert(m);
+        assert(type < _JOB_TYPE_MAX);
+        assert(unit);
+
+        /* log_debug("Pulling in %s/%s from %s/%s", */
+        /*           unit->id, job_type_to_string(type), */
+        /*           by ? by->unit->id : "NA", */
+        /*           by ? job_type_to_string(by->type) : "NA"); */
+
+        if (unit->load_state != UNIT_LOADED &&
+            unit->load_state != UNIT_ERROR &&
+            unit->load_state != UNIT_MASKED) {
+                dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
+                return -EINVAL;
+        }
+
+        if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
+                dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
+                               "Unit %s failed to load: %s. "
+                               "See system logs and 'systemctl status %s' for details.",
+                               unit->id,
+                               strerror(-unit->load_error),
+                               unit->id);
+                return -EINVAL;
+        }
+
+        if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
+                dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
+                return -EINVAL;
+        }
+
+        if (!unit_job_is_applicable(unit, type)) {
+                dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id);
+                return -EBADR;
+        }
+
+        /* First add the job. */
+        if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
+                return -ENOMEM;
+
+        ret->ignore_order = ret->ignore_order || ignore_order;
+
+        /* Then, add a link to the job. */
+        if (!job_dependency_new(by, ret, matters, conflicts))
+                return -ENOMEM;
+
+        if (is_new && !ignore_requirements) {
+                Set *following;
+
+                /* If we are following some other unit, make sure we
+                 * add all dependencies of everybody following. */
+                if (unit_following_set(ret->unit, &following) > 0) {
+                        SET_FOREACH(dep, following, i)
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        set_free(following);
+                }
+
+                /* Finally, recursively add in all dependencies. */
+                if (type == JOB_START || type == JOB_RELOAD_OR_START) {
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) {
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                }
+
+                if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i)
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i)
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+                }
+
+                if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) {
+
+                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) {
+                                r = transaction_add_job_and_dependencies(m, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL);
+
+                                if (r < 0) {
+                                        log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+                        }
+                }
+
+                /* 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->id != k)
+                        continue;
+
+                if (u->ignore_on_isolate)
+                        continue;
+
+                /* No need to stop inactive jobs */
+                if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
+                        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, false, false, false, NULL, NULL)) < 0)
+                        log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r));
+        }
+
+        return 0;
+}
+
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, 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) {
+                dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start.");
+                return -EINVAL;
+        }
+
+        if (mode == JOB_ISOLATE && !unit->allow_isolate) {
+                dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+                return -EPERM;
+        }
+
+        log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
+
+        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false,
+                                                      mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
+                                                      mode == JOB_IGNORE_DEPENDENCIES, e, &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, e)) < 0)
+                return r;
+
+        log_debug("Enqueued job %s/%s as %u", unit->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, DBusError *e, 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, NULL, &unit)) < 0)
+                return r;
+
+        return manager_add_job(m, type, unit, mode, override, e, _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) {
+        Unit *u;
+        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 ((u = m->load_queue)) {
+                assert(u->in_load_queue);
+
+                unit_load(u);
+                n++;
+        }
+
+        m->dispatching_load_queue = false;
+        return n;
+}
+
+int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
+        Unit *ret;
+        UnitType t;
+        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)) {
+                dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path);
+                return -EINVAL;
+        }
+
+        if (!name)
+                name = file_name_from_path(path);
+
+        t = unit_name_to_type(name);
+
+        if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid_no_type(name, false)) {
+                dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
+                return -EINVAL;
+        }
+
+        ret = manager_get_unit(m, name);
+        if (ret) {
+                *_ret = ret;
+                return 1;
+        }
+
+        ret = unit_new(m, unit_vtable[t]->object_size);
+        if (!ret)
+                return -ENOMEM;
+
+        if (path) {
+                ret->fragment_path = strdup(path);
+                if (!ret->fragment_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, DBusError *e, 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, e, _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->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_finish_and_invalidate(j, JOB_CANCELED);
+}
+
+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;
+        Unit *u;
+        unsigned n = 0;
+
+        assert(m);
+
+        if (m->dispatching_dbus_queue)
+                return 0;
+
+        m->dispatching_dbus_queue = true;
+
+        while ((u = m->dbus_unit_queue)) {
+                assert(u->in_dbus_queue);
+
+                bus_unit_send_change_signal(u);
+                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_process_notify_fd(Manager *m) {
+        ssize_t n;
+
+        assert(m);
+
+        for (;;) {
+                char buf[4096];
+                struct msghdr msghdr;
+                struct iovec iovec;
+                struct ucred *ucred;
+                union {
+                        struct cmsghdr cmsghdr;
+                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+                } control;
+                Unit *u;
+                char **tags;
+
+                zero(iovec);
+                iovec.iov_base = buf;
+                iovec.iov_len = sizeof(buf)-1;
+
+                zero(control);
+                zero(msghdr);
+                msghdr.msg_iov = &iovec;
+                msghdr.msg_iovlen = 1;
+                msghdr.msg_control = &control;
+                msghdr.msg_controllen = sizeof(control);
+
+                if ((n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT)) <= 0) {
+                        if (n >= 0)
+                                return -EIO;
+
+                        if (errno == EAGAIN || errno == EINTR)
+                                break;
+
+                        return -errno;
+                }
+
+                if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
+                    control.cmsghdr.cmsg_level != SOL_SOCKET ||
+                    control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
+                    control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
+                        log_warning("Received notify message without credentials. Ignoring.");
+                        continue;
+                }
+
+                ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
+
+                if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid))))
+                        if (!(u = cgroup_unit_by_pid(m, ucred->pid))) {
+                                log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
+                                continue;
+                        }
+
+                assert((size_t) n < sizeof(buf));
+                buf[n] = 0;
+                if (!(tags = strv_split(buf, "\n\r")))
+                        return -ENOMEM;
+
+                log_debug("Got notification message for unit %s", u->id);
+
+                if (UNIT_VTABLE(u)->notify_message)
+                        UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags);
+
+                strv_free(tags);
+        }
+
+        return 0;
+}
+
+static int manager_dispatch_sigchld(Manager *m) {
+        assert(m);
+
+        for (;;) {
+                siginfo_t si;
+                Unit *u;
+                int r;
+
+                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_comm(si.si_pid, &name);
+                        log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
+                        free(name);
+                }
+
+                /* Let's flush any message the dying child might still
+                 * have queued for us. This ensures that the process
+                 * still exists in /proc so that we can figure out
+                 * which cgroup and hence unit it belongs to. */
+                if ((r = manager_process_notify_fd(m)) < 0)
+                        return r;
+
+                /* And now figure out the unit this belongs to */
+                if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid))))
+                        u = cgroup_unit_by_pid(m, si.si_pid);
+
+                /* 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 %lu died (code=%s, status=%i/%s)",
+                          (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, EXIT_STATUS_FULL)
+                                : signal_to_string(si.si_status)));
+
+                if (!u)
+                        continue;
+
+                log_debug("Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
+
+                hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
+                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
+        }
+
+        return 0;
+}
+
+static int manager_start_target(Manager *m, const char *name, JobMode mode) {
+        int r;
+        DBusError error;
+
+        dbus_error_init(&error);
+
+        log_debug("Activating special unit %s", name);
+
+        if ((r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL)) < 0)
+                log_error("Failed to enqueue %s job: %s", name, bus_error(&error, r));
+
+        dbus_error_free(&error);
+
+        return 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 == EINTR || errno == EAGAIN)
+                                break;
+
+                        return -errno;
+                }
+
+                if (sfsi.ssi_pid > 0) {
+                        char *p = NULL;
+
+                        get_process_comm(sfsi.ssi_pid, &p);
+
+                        log_debug("Received SIG%s from PID %lu (%s).",
+                                  signal_to_string(sfsi.ssi_signo),
+                                  (unsigned long) sfsi.ssi_pid, strna(p));
+                        free(p);
+                } else
+                        log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo));
+
+                switch (sfsi.ssi_signo) {
+
+                case SIGCHLD:
+                        sigchld = true;
+                        break;
+
+                case SIGTERM:
+                        if (m->running_as == MANAGER_SYSTEM) {
+                                /* This is for compatibility with the
+                                 * original sysvinit */
+                                m->exit_code = MANAGER_REEXECUTE;
+                                break;
+                        }
+
+                        /* Fall through */
+
+                case SIGINT:
+                        if (m->running_as == MANAGER_SYSTEM) {
+                                manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE);
+                                break;
+                        }
+
+                        /* Run the exit target if there is one, if not, just exit. */
+                        if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
+                                m->exit_code = MANAGER_EXIT;
+                                return 0;
+                        }
+
+                        break;
+
+                case SIGWINCH:
+                        if (m->running_as == MANAGER_SYSTEM)
+                                manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
+
+                        /* This is a nop on non-init */
+                        break;
+
+                case SIGPWR:
+                        if (m->running_as == MANAGER_SYSTEM)
+                                manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
+
+                        /* 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(m, true);
+                        }
+
+                        if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
+                                log_info("Loading D-Bus service...");
+                                manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
+                        }
+
+                        break;
+                }
+
+                case SIGUSR2: {
+                        FILE *f;
+                        char *dump = NULL;
+                        size_t size;
+
+                        if (!(f = open_memstream(&dump, &size))) {
+                                log_warning("Failed to allocate memory stream.");
+                                break;
+                        }
+
+                        manager_dump_units(m, f, "\t");
+                        manager_dump_jobs(m, f, "\t");
+
+                        if (ferror(f)) {
+                                fclose(f);
+                                free(dump);
+                                log_warning("Failed to write status stream");
+                                break;
+                        }
+
+                        fclose(f);
+                        log_dump(LOG_INFO, dump);
+                        free(dump);
+
+                        break;
+                }
+
+                case SIGHUP:
+                        m->exit_code = MANAGER_RELOAD;
+                        break;
+
+                default: {
+
+                        /* Starting SIGRTMIN+0 */
+                        static const char * const target_table[] = {
+                                [0] = SPECIAL_DEFAULT_TARGET,
+                                [1] = SPECIAL_RESCUE_TARGET,
+                                [2] = SPECIAL_EMERGENCY_TARGET,
+                                [3] = SPECIAL_HALT_TARGET,
+                                [4] = SPECIAL_POWEROFF_TARGET,
+                                [5] = SPECIAL_REBOOT_TARGET,
+                                [6] = SPECIAL_KEXEC_TARGET
+                        };
+
+                        /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
+                        static const ManagerExitCode code_table[] = {
+                                [0] = MANAGER_HALT,
+                                [1] = MANAGER_POWEROFF,
+                                [2] = MANAGER_REBOOT,
+                                [3] = MANAGER_KEXEC
+                        };
+
+                        if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
+                            (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
+                                int idx = (int) sfsi.ssi_signo - SIGRTMIN;
+                                manager_start_target(m, target_table[idx],
+                                                     (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
+                                break;
+                        }
+
+                        if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
+                            (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
+                                m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
+                                break;
+                        }
+
+                        switch (sfsi.ssi_signo - SIGRTMIN) {
+
+                        case 20:
+                                log_debug("Enabling showing of status.");
+                                manager_set_show_status(m, true);
+                                break;
+
+                        case 21:
+                                log_debug("Disabling showing of status.");
+                                manager_set_show_status(m, false);
+                                break;
+
+                        case 22:
+                                log_set_max_level(LOG_DEBUG);
+                                log_notice("Setting log level to debug.");
+                                break;
+
+                        case 23:
+                                log_set_max_level(LOG_INFO);
+                                log_notice("Setting log level to info.");
+                                break;
+
+                        case 26:
+                                log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+                                log_notice("Setting log target to journal-or-kmsg.");
+                                break;
+
+                        case 27:
+                                log_set_target(LOG_TARGET_CONSOLE);
+                                log_notice("Setting log target to console.");
+                                break;
+
+                        case 28:
+                                log_set_target(LOG_TARGET_KMSG);
+                                log_notice("Setting log target to kmsg.");
+                                break;
+
+                        case 29:
+                                log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+                                log_notice("Setting log target to syslog-or-kmsg.");
+                                break;
+
+                        default:
+                                log_warning("Got unhandled signal <%s>.", signal_to_string(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_se(w = ev->data.ptr);
+
+        if (w->type == WATCH_INVALID)
+                return 0;
+
+        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_NOTIFY:
+
+                /* An incoming daemon notification event? */
+                if (ev->events != EPOLLIN)
+                        return -EINVAL;
+
+                if ((r = manager_process_notify_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_UNIT_TIMER:
+        case WATCH_JOB_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;
+                }
+
+                if (w->type == WATCH_UNIT_TIMER)
+                        UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
+                else
+                        job_timer_event(w->data.job, v, w);
+                break;
+        }
+
+        case WATCH_MOUNT:
+                /* Some mount table change, intended for the mount subsystem */
+                mount_fd_event(m, ev->events);
+                break;
+
+        case WATCH_SWAP:
+                /* Some swap table change, intended for the swap subsystem */
+                swap_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:
+                log_error("event type=%i", w->type);
+                assert_not_reached("Unknown epoll event type.");
+        }
+
+        return 0;
+}
+
+int manager_loop(Manager *m) {
+        int r;
+        int wait_msec = -1;
+
+        RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
+
+        assert(m);
+        m->exit_code = MANAGER_RUNNING;
+
+        /* Release the path cache */
+        set_free_free(m->unit_path_cache);
+        m->unit_path_cache = NULL;
+
+        manager_check_finished(m);
+
+        /* There might still be some zombies hanging around from
+         * before we were exec()'ed. Leat's reap them */
+        r = manager_dispatch_sigchld(m);
+        if (r < 0)
+                return r;
+
+        /* Sleep for half the watchdog time */
+        if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)  {
+                wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
+                if (wait_msec <= 0)
+                        wait_msec = 1;
+        }
+
+        while (m->exit_code == MANAGER_RUNNING) {
+                struct epoll_event event;
+                int n;
+
+                if (wait_msec >= 0)
+                        watchdog_ping();
+
+                if (!ratelimit_test(&rl)) {
+                        /* Yay, something is going seriously wrong, pause a little */
+                        log_warning("Looping too fast. Throttling execution a little.");
+                        sleep(1);
+                        continue;
+                }
+
+                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 (swap_dispatch_reload(m) > 0)
+                        continue;
+
+                n = epoll_wait(m->epoll_fd, &event, 1, wait_msec);
+                if (n < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+                } else if (n == 0)
+                        continue;
+
+                assert(n == 1);
+
+                r = process_event(m, &event);
+                if (r < 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;
+}
+
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
+
+#ifdef HAVE_AUDIT
+        char *p;
+
+        if (m->audit_fd < 0)
+                return;
+
+        /* Don't generate audit events if the service was already
+         * started and we're just deserializing */
+        if (m->n_reloading > 0)
+                return;
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
+        if (u->type != UNIT_SERVICE)
+                return;
+
+        if (!(p = unit_name_to_prefix_and_instance(u->id))) {
+                log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
+                return;
+        }
+
+        if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
+                log_warning("Failed to send audit message: %m");
+
+                if (errno == EPERM) {
+                        /* We aren't allowed to send audit messages?
+                         * Then let's not retry again, to avoid
+                         * spamming the user with the same and same
+                         * messages over and over. */
+
+                        audit_close(m->audit_fd);
+                        m->audit_fd = -1;
+                }
+        }
+
+        free(p);
+#endif
+
+}
+
+void manager_send_unit_plymouth(Manager *m, Unit *u) {
+        int fd = -1;
+        union sockaddr_union sa;
+        int n = 0;
+        char *message = NULL;
+
+        /* Don't generate plymouth events if the service was already
+         * started and we're just deserializing */
+        if (m->n_reloading > 0)
+                return;
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
+        if (u->type != UNIT_SERVICE &&
+            u->type != UNIT_MOUNT &&
+            u->type != UNIT_SWAP)
+                return;
+
+        /* We set SOCK_NONBLOCK here so that we rather drop the
+         * message then wait for plymouth */
+        if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
+                log_error("socket() failed: %m");
+                return;
+        }
+
+        zero(sa);
+        sa.sa.sa_family = AF_UNIX;
+        strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
+        if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+
+                if (errno != EPIPE &&
+                    errno != EAGAIN &&
+                    errno != ENOENT &&
+                    errno != ECONNREFUSED &&
+                    errno != ECONNRESET &&
+                    errno != ECONNABORTED)
+                        log_error("connect() failed: %m");
+
+                goto finish;
+        }
+
+        if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
+                log_error("Out of memory");
+                goto finish;
+        }
+
+        errno = 0;
+        if (write(fd, message, n + 1) != n + 1) {
+
+                if (errno != EPIPE &&
+                    errno != EAGAIN &&
+                    errno != ENOENT &&
+                    errno != ECONNREFUSED &&
+                    errno != ECONNRESET &&
+                    errno != ECONNABORTED)
+                        log_error("Failed to write Plymouth message: %m");
+
+                goto finish;
+        }
+
+finish:
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        free(message);
+}
+
+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(Manager *m, FILE **_f) {
+        char *path = NULL;
+        mode_t saved_umask;
+        int fd;
+        FILE *f;
+
+        assert(_f);
+
+        if (m->running_as == MANAGER_SYSTEM)
+                asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
+        else
+                asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
+
+        if (!path)
+                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+")))
+                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);
+
+        m->n_reloading ++;
+
+        fprintf(f, "current-job-id=%i\n", m->current_job_id);
+        fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
+
+        dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
+        dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp);
+        dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
+
+        fputc('\n', f);
+
+        HASHMAP_FOREACH_KEY(u, t, m->units, i) {
+                if (u->id != t)
+                        continue;
+
+                if (!unit_can_serialize(u))
+                        continue;
+
+                /* Start marker */
+                fputs(u->id, f);
+                fputc('\n', f);
+
+                if ((r = unit_serialize(u, f, fds)) < 0) {
+                        m->n_reloading --;
+                        return r;
+                }
+        }
+
+        assert(m->n_reloading > 0);
+        m->n_reloading --;
+
+        if (ferror(f))
+                return -EIO;
+
+        r = bus_fdset_add_all(m, fds);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
+        int r = 0;
+
+        assert(m);
+        assert(f);
+
+        log_debug("Deserializing state...");
+
+        m->n_reloading ++;
+
+        for (;;) {
+                char line[LINE_MAX], *l;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                r = 0;
+                        else
+                                r = -errno;
+
+                        goto finish;
+                }
+
+                char_array_0(line);
+                l = strstrip(line);
+
+                if (l[0] == 0)
+                        break;
+
+                if (startswith(l, "current-job-id=")) {
+                        uint32_t id;
+
+                        if (safe_atou32(l+15, &id) < 0)
+                                log_debug("Failed to parse current job id value %s", l+15);
+                        else
+                                m->current_job_id = MAX(m->current_job_id, id);
+                } else if (startswith(l, "taint-usr=")) {
+                        int b;
+
+                        if ((b = parse_boolean(l+10)) < 0)
+                                log_debug("Failed to parse taint /usr flag %s", l+10);
+                        else
+                                m->taint_usr = m->taint_usr || b;
+                } else if (startswith(l, "initrd-timestamp="))
+                        dual_timestamp_deserialize(l+17, &m->initrd_timestamp);
+                else if (startswith(l, "startup-timestamp="))
+                        dual_timestamp_deserialize(l+18, &m->startup_timestamp);
+                else if (startswith(l, "finish-timestamp="))
+                        dual_timestamp_deserialize(l+17, &m->finish_timestamp);
+                else
+                        log_debug("Unknown serialization item '%s'", l);
+        }
+
+        for (;;) {
+                Unit *u;
+                char name[UNIT_NAME_MAX+2];
+
+                /* Start marker */
+                if (!fgets(name, sizeof(name), f)) {
+                        if (feof(f))
+                                r = 0;
+                        else
+                                r = -errno;
+
+                        goto finish;
+                }
+
+                char_array_0(name);
+
+                if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0)
+                        goto finish;
+
+                if ((r = unit_deserialize(u, f, fds)) < 0)
+                        goto finish;
+        }
+
+finish:
+        if (ferror(f)) {
+                r = -EIO;
+                goto finish;
+        }
+
+        assert(m->n_reloading > 0);
+        m->n_reloading --;
+
+        return r;
+}
+
+int manager_reload(Manager *m) {
+        int r, q;
+        FILE *f;
+        FDSet *fds;
+
+        assert(m);
+
+        if ((r = manager_open_serialization(m, &f)) < 0)
+                return r;
+
+        m->n_reloading ++;
+
+        if (!(fds = fdset_new())) {
+                m->n_reloading --;
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if ((r = manager_serialize(m, f, fds)) < 0) {
+                m->n_reloading --;
+                goto finish;
+        }
+
+        if (fseeko(f, 0, SEEK_SET) < 0) {
+                m->n_reloading --;
+                r = -errno;
+                goto finish;
+        }
+
+        /* From here on there is no way back. */
+        manager_clear_jobs_and_units(m);
+        manager_undo_generators(m);
+
+        /* Find new unit paths */
+        lookup_paths_free(&m->lookup_paths);
+        if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
+                r = q;
+
+        manager_run_generators(m);
+
+        manager_build_unit_path_cache(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;
+
+        assert(m->n_reloading > 0);
+        m->n_reloading--;
+
+finish:
+        if (f)
+                fclose(f);
+
+        if (fds)
+                fdset_free(fds);
+
+        return r;
+}
+
+bool manager_is_booting_or_shutting_down(Manager *m) {
+        Unit *u;
+
+        assert(m);
+
+        /* Is the initial job still around? */
+        if (manager_get_job(m, m->default_unit_job_id))
+                return true;
+
+        /* Is there a job for the shutdown target? */
+        u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
+        if (u)
+                return !!u->job;
+
+        return false;
+}
+
+void manager_reset_failed(Manager *m) {
+        Unit *u;
+        Iterator i;
+
+        assert(m);
+
+        HASHMAP_FOREACH(u, m->units, i)
+                unit_reset_failed(u);
+}
+
+bool manager_unit_pending_inactive(Manager *m, const char *name) {
+        Unit *u;
+
+        assert(m);
+        assert(name);
+
+        /* Returns true if the unit is inactive or going down */
+        if (!(u = manager_get_unit(m, name)))
+                return true;
+
+        return unit_pending_inactive(u);
+}
+
+void manager_check_finished(Manager *m) {
+        char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
+        usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0;
+
+        assert(m);
+
+        if (dual_timestamp_is_set(&m->finish_timestamp))
+                return;
+
+        if (hashmap_size(m->jobs) > 0)
+                return;
+
+        dual_timestamp_get(&m->finish_timestamp);
+
+        if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
+
+                userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
+                total_usec = m->finish_timestamp.monotonic;
+
+                if (dual_timestamp_is_set(&m->initrd_timestamp)) {
+
+                        kernel_usec = m->initrd_timestamp.monotonic;
+                        initrd_usec = m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic;
+
+                        log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
+                                 format_timespan(kernel, sizeof(kernel), kernel_usec),
+                                 format_timespan(initrd, sizeof(initrd), initrd_usec),
+                                 format_timespan(userspace, sizeof(userspace), userspace_usec),
+                                 format_timespan(sum, sizeof(sum), total_usec));
+                } else {
+                        kernel_usec = m->startup_timestamp.monotonic;
+                        initrd_usec = 0;
+
+                        log_info("Startup finished in %s (kernel) + %s (userspace) = %s.",
+                                 format_timespan(kernel, sizeof(kernel), kernel_usec),
+                                 format_timespan(userspace, sizeof(userspace), userspace_usec),
+                                 format_timespan(sum, sizeof(sum), total_usec));
+                }
+        } else {
+                userspace_usec = initrd_usec = kernel_usec = 0;
+                total_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
+
+                log_debug("Startup finished in %s.",
+                          format_timespan(sum, sizeof(sum), total_usec));
+        }
+
+        bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec);
+
+        sd_notifyf(false,
+                   "READY=1\nSTATUS=Startup finished in %s.",
+                   format_timespan(sum, sizeof(sum), total_usec));
+}
+
+void manager_run_generators(Manager *m) {
+        DIR *d = NULL;
+        const char *generator_path;
+        const char *argv[3];
+        mode_t u;
+
+        assert(m);
+
+        generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
+        if (!(d = opendir(generator_path))) {
+
+                if (errno == ENOENT)
+                        return;
+
+                log_error("Failed to enumerate generator directory: %m");
+                return;
+        }
+
+        if (!m->generator_unit_path) {
+                const char *p;
+                char user_path[] = "/tmp/systemd-generator-XXXXXX";
+
+                if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
+                        p = "/run/systemd/generator";
+
+                        if (mkdir_p(p, 0755) < 0) {
+                                log_error("Failed to create generator directory: %m");
+                                goto finish;
+                        }
+
+                } else {
+                        if (!(p = mkdtemp(user_path))) {
+                                log_error("Failed to create generator directory: %m");
+                                goto finish;
+                        }
+                }
+
+                if (!(m->generator_unit_path = strdup(p))) {
+                        log_error("Failed to allocate generator unit path.");
+                        goto finish;
+                }
+        }
+
+        argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
+        argv[1] = m->generator_unit_path;
+        argv[2] = NULL;
+
+        u = umask(0022);
+        execute_directory(generator_path, d, (char**) argv);
+        umask(u);
+
+        if (rmdir(m->generator_unit_path) >= 0) {
+                /* Uh? we were able to remove this dir? I guess that
+                 * means the directory was empty, hence let's shortcut
+                 * this */
+
+                free(m->generator_unit_path);
+                m->generator_unit_path = NULL;
+                goto finish;
+        }
+
+        if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) {
+                char **l;
+
+                if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) {
+                        log_error("Failed to add generator directory to unit search path: %m");
+                        goto finish;
+                }
+
+                strv_free(m->lookup_paths.unit_path);
+                m->lookup_paths.unit_path = l;
+
+                log_debug("Added generator unit path %s to search path.", m->generator_unit_path);
+        }
+
+finish:
+        if (d)
+                closedir(d);
+}
+
+void manager_undo_generators(Manager *m) {
+        assert(m);
+
+        if (!m->generator_unit_path)
+                return;
+
+        strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
+        rm_rf(m->generator_unit_path, false, true, false);
+
+        free(m->generator_unit_path);
+        m->generator_unit_path = NULL;
+}
+
+int manager_set_default_controllers(Manager *m, char **controllers) {
+        char **l;
+
+        assert(m);
+
+        if (!(l = strv_copy(controllers)))
+                return -ENOMEM;
+
+        strv_free(m->default_controllers);
+        m->default_controllers = l;
+
+        return 0;
+}
+
+void manager_recheck_journal(Manager *m) {
+        Unit *u;
+
+        assert(m);
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
+        u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
+        if (u && SOCKET(u)->state != SOCKET_RUNNING) {
+                log_close_journal();
+                return;
+        }
+
+        u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE);
+        if (u && SERVICE(u)->state != SERVICE_RUNNING) {
+                log_close_journal();
+                return;
+        }
+
+        /* Hmm, OK, so the socket is fully up and the service is up
+         * too, then let's make use of the thing. */
+        log_open();
+}
+
+void manager_set_show_status(Manager *m, bool b) {
+        assert(m);
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
+        m->show_status = b;
+
+        if (b)
+                touch("/run/systemd/show-status");
+        else
+                unlink("/run/systemd/show-status");
+}
+
+bool manager_get_show_status(Manager *m) {
+        assert(m);
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return false;
+
+        if (m->show_status)
+                return true;
+
+        /* If Plymouth is running make sure we show the status, so
+         * that there's something nice to see when people press Esc */
+
+        return plymouth_running();
+}
+
+static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
+        [MANAGER_SYSTEM] = "system",
+        [MANAGER_USER] = "user"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);
diff --git a/src/core/manager.h b/src/core/manager.h
new file mode 100644
index 0000000..9ecc926
--- /dev/null
+++ b/src/core/manager.h
@@ -0,0 +1,304 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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 131072 /* 128K */
+
+typedef struct Manager Manager;
+typedef enum WatchType WatchType;
+typedef struct Watch Watch;
+
+typedef enum ManagerExitCode {
+        MANAGER_RUNNING,
+        MANAGER_EXIT,
+        MANAGER_RELOAD,
+        MANAGER_REEXECUTE,
+        MANAGER_REBOOT,
+        MANAGER_POWEROFF,
+        MANAGER_HALT,
+        MANAGER_KEXEC,
+        _MANAGER_EXIT_CODE_MAX,
+        _MANAGER_EXIT_CODE_INVALID = -1
+} ManagerExitCode;
+
+typedef enum ManagerRunningAs {
+        MANAGER_SYSTEM,
+        MANAGER_USER,
+        _MANAGER_RUNNING_AS_MAX,
+        _MANAGER_RUNNING_AS_INVALID = -1
+} ManagerRunningAs;
+
+enum WatchType {
+        WATCH_INVALID,
+        WATCH_SIGNAL,
+        WATCH_NOTIFY,
+        WATCH_FD,
+        WATCH_UNIT_TIMER,
+        WATCH_JOB_TIMER,
+        WATCH_MOUNT,
+        WATCH_SWAP,
+        WATCH_UDEV,
+        WATCH_DBUS_WATCH,
+        WATCH_DBUS_TIMEOUT
+};
+
+struct Watch {
+        int fd;
+        WatchType type;
+        union {
+                struct Unit *unit;
+                struct Job *job;
+                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"
+#include "path-lookup.h"
+
+struct Manager {
+        /* Note that the set of units we know of is allowed to be
+         * inconsistent. 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(Unit, units_by_type[_UNIT_TYPE_MAX]);
+
+        /* Units that need to be loaded */
+        LIST_HEAD(Unit, 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(Unit, dbus_unit_queue);
+        LIST_HEAD(Job, dbus_job_queue);
+
+        /* Units to remove */
+        LIST_HEAD(Unit, cleanup_queue);
+
+        /* Units to check when doing GC */
+        LIST_HEAD(Unit, 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 */
+
+        char *notify_socket;
+
+        Watch notify_watch;
+        Watch signal_watch;
+
+        int epoll_fd;
+
+        unsigned n_snapshots;
+
+        LookupPaths lookup_paths;
+        Set *unit_path_cache;
+
+        char **environment;
+        char **default_controllers;
+
+        usec_t runtime_watchdog;
+        usec_t shutdown_watchdog;
+
+        dual_timestamp initrd_timestamp;
+        dual_timestamp startup_timestamp;
+        dual_timestamp finish_timestamp;
+
+        char *generator_unit_path;
+
+        /* Data specific to the device subsystem */
+        struct udev* udev;
+        struct udev_monitor* udev_monitor;
+        Watch udev_watch;
+        Hashmap *devices_by_sysfs;
+
+        /* Data specific to the mount subsystem */
+        FILE *proc_self_mountinfo;
+        Watch mount_watch;
+
+        /* Data specific to the swap filesystem */
+        FILE *proc_swaps;
+        Hashmap *swaps_by_proc_swaps;
+        bool request_reload;
+        Watch swap_watch;
+
+        /* Data specific to the D-Bus subsystem */
+        DBusConnection *api_bus, *system_bus;
+        DBusServer *private_bus;
+        Set *bus_connections, *bus_connections_for_dispatch;
+
+        DBusMessage *queued_message; /* This is used during reloading:
+                                      * before the reload we queue the
+                                      * reply message here, and
+                                      * afterwards we send it */
+        DBusConnection *queued_message_connection; /* The connection to send the queued message on */
+
+        Hashmap *watch_bus;  /* D-Bus names => Unit object n:1 */
+        int32_t name_data_slot;
+        int32_t conn_data_slot;
+        int32_t subscribed_data_slot;
+
+        uint32_t current_job_id;
+        uint32_t default_unit_job_id;
+
+        /* 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_hierarchy;
+
+        usec_t gc_queue_timestamp;
+        int gc_marker;
+        unsigned n_in_gc_queue;
+
+        /* Make sure the user cannot accidentally unmount our cgroup
+         * file system */
+        int pin_cgroupfs_fd;
+
+        /* Audit fd */
+#ifdef HAVE_AUDIT
+        int audit_fd;
+#endif
+
+        /* Flags */
+        ManagerRunningAs running_as;
+        ManagerExitCode exit_code:5;
+
+        bool dispatching_load_queue:1;
+        bool dispatching_run_queue:1;
+        bool dispatching_dbus_queue:1;
+
+        bool taint_usr:1;
+
+        bool show_status;
+        bool confirm_spawn;
+#ifdef HAVE_SYSV_COMPAT
+        bool sysv_console;
+#endif
+        bool mount_auto;
+        bool swap_auto;
+
+        ExecOutput default_std_output, default_std_error;
+
+        /* non-zero if we are reloading or reexecuting, */
+        int n_reloading;
+
+        unsigned n_installed_jobs;
+        unsigned n_failed_jobs;
+};
+
+int manager_new(ManagerRunningAs running_as, 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, DBusError *e, Unit **_ret);
+int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret);
+
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, DBusError *e, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, DBusError *e, 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_set_default_controllers(Manager *m, char **controllers);
+
+int manager_loop(Manager *m);
+
+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(Manager *m, 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);
+
+bool manager_is_booting_or_shutting_down(Manager *m);
+
+void manager_reset_failed(Manager *m);
+
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
+void manager_send_unit_plymouth(Manager *m, Unit *u);
+
+bool manager_unit_pending_inactive(Manager *m, const char *name);
+
+void manager_check_finished(Manager *m);
+
+void manager_run_generators(Manager *m);
+void manager_undo_generators(Manager *m);
+
+void manager_recheck_journal(Manager *m);
+
+void manager_set_show_status(Manager *m, bool b);
+bool manager_get_show_status(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/core/mount.c b/src/core/mount.c
new file mode 100644
index 0000000..7dbeaf9
--- /dev/null
+++ b/src/core/mount.c
@@ -0,0 +1,1930 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 "mkdir.h"
+#include "mount-setup.h"
+#include "unit-name.h"
+#include "dbus-mount.h"
+#include "special.h"
+#include "bus-errors.h"
+#include "exit-status.h"
+#include "def.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_RELOADING,
+        [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
+        [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
+        [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
+        [MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
+        [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
+        [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
+        [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
+        [MOUNT_FAILED] = UNIT_FAILED
+};
+
+static void mount_init(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        m->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        m->directory_mode = 0755;
+
+        exec_context_init(&m->exec_context);
+
+        /* The stdio/kmsg bridge socket is on /, in order to avoid a
+         * dep loop, don't use kmsg logging for -.mount */
+        if (!unit_has_name(u, "-.mount")) {
+                m->exec_context.std_output = u->manager->default_std_output;
+                m->exec_context.std_error = u->manager->default_std_error;
+        }
+
+        /* 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.same_pgrp = true;
+
+        m->timer_watch.type = WATCH_INVALID;
+
+        m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
+
+        UNIT(m)->ignore_on_isolate = true;
+}
+
+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 MountParameters* get_mount_parameters_configured(Mount *m) {
+        assert(m);
+
+        if (m->from_fragment)
+                return &m->parameters_fragment;
+        else if (m->from_etc_fstab)
+                return &m->parameters_etc_fstab;
+
+        return NULL;
+}
+
+static MountParameters* get_mount_parameters(Mount *m) {
+        assert(m);
+
+        if (m->from_proc_self_mountinfo)
+                return &m->parameters_proc_self_mountinfo;
+
+        return get_mount_parameters_configured(m);
+}
+
+static int mount_add_mount_links(Mount *m) {
+        Unit *other;
+        int r;
+        MountParameters *pm;
+
+        assert(m);
+
+        pm = get_mount_parameters_configured(m);
+
+        /* Adds in links to other mount points that might lie below or
+         * above us in the hierarchy */
+
+        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_MOUNT]) {
+                Mount *n = MOUNT(other);
+                MountParameters *pn;
+
+                if (n == m)
+                        continue;
+
+                if (UNIT(n)->load_state != UNIT_LOADED)
+                        continue;
+
+                pn = get_mount_parameters_configured(n);
+
+                if (path_startswith(m->where, n->where)) {
+
+                        if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
+                                return r;
+
+                        if (pn)
+                                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(n), UNIT_AFTER, UNIT(m), true)) < 0)
+                                return r;
+
+                        if (pm)
+                                if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
+                                        return r;
+
+                } else if (pm && pm->what && path_startswith(pm->what, n->where)) {
+
+                        if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
+                                return r;
+
+                        if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
+                                return r;
+
+                } else if (pn && pn->what && path_startswith(pn->what, m->where)) {
+
+                        if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
+                                return r;
+
+                        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) {
+        Unit *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP])
+                if ((r = swap_add_one_mount_link(SWAP(other), m)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int mount_add_path_links(Mount *m) {
+        Unit *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH])
+                if ((r = path_add_one_mount_link(PATH(other), m)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int mount_add_automount_links(Mount *m) {
+        Unit *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_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) {
+        Unit *other;
+        int r;
+
+        assert(m);
+
+        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_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 NULL;
+
+        zero(me);
+        me.mnt_opts = (char*) haystack;
+
+        return hasmntopt(&me, needle);
+}
+
+static bool mount_is_network(MountParameters *p) {
+        assert(p);
+
+        if (mount_test_option(p->options, "_netdev"))
+                return true;
+
+        if (p->fstype && fstype_is_network(p->fstype))
+                return true;
+
+        return false;
+}
+
+static bool mount_is_bind(MountParameters *p) {
+        assert(p);
+
+        if (mount_test_option(p->options, "bind"))
+                return true;
+
+        if (p->fstype && streq(p->fstype, "bind"))
+                return true;
+
+        return false;
+}
+
+static bool needs_quota(MountParameters *p) {
+        assert(p);
+
+        if (mount_is_network(p))
+                return false;
+
+        if (mount_is_bind(p))
+                return false;
+
+        return mount_test_option(p->options, "usrquota") ||
+                mount_test_option(p->options, "grpquota") ||
+                mount_test_option(p->options, "quota") ||
+                mount_test_option(p->options, "usrjquota") ||
+                mount_test_option(p->options, "grpjquota");
+}
+
+static int mount_add_fstab_links(Mount *m) {
+        const char *target, *after, *tu_wants = NULL;
+        MountParameters *p;
+        Unit *tu;
+        int r;
+        bool noauto, nofail, handle, automount;
+
+        assert(m);
+
+        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+                return 0;
+
+        if (!(p = get_mount_parameters_configured(m)))
+                return 0;
+
+        if (p != &m->parameters_etc_fstab)
+                return 0;
+
+        noauto = !!mount_test_option(p->options, "noauto");
+        nofail = !!mount_test_option(p->options, "nofail");
+        automount =
+                mount_test_option(p->options, "comment=systemd.automount") ||
+                mount_test_option(p->options, "x-systemd-automount");
+        handle =
+                automount ||
+                mount_test_option(p->options, "comment=systemd.mount") ||
+                mount_test_option(p->options, "x-systemd-mount") ||
+                UNIT(m)->manager->mount_auto;
+
+        if (mount_is_network(p)) {
+                target = SPECIAL_REMOTE_FS_TARGET;
+                after = tu_wants = SPECIAL_REMOTE_FS_PRE_TARGET;
+        } else {
+                target = SPECIAL_LOCAL_FS_TARGET;
+                after = SPECIAL_LOCAL_FS_PRE_TARGET;
+        }
+
+        r = manager_load_unit(UNIT(m)->manager, target, NULL, NULL, &tu);
+        if (r < 0)
+                return r;
+
+        if (tu_wants) {
+                r = unit_add_dependency_by_name(tu, UNIT_WANTS, tu_wants, NULL, true);
+                if (r < 0)
+                        return r;
+        }
+
+        if (after) {
+                r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
+                if (r < 0)
+                        return r;
+        }
+
+        if (automount) {
+                Unit *am;
+
+                if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0)
+                        return r;
+
+                /* If auto is configured as well also pull in the
+                 * mount right-away, but don't rely on it. */
+                if (!noauto) /* automount + auto */
+                        if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0)
+                                return r;
+
+                /* Install automount unit */
+                if (!nofail) /* automount + fail */
+                        return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, am, true);
+                else /* automount + nofail */
+                        return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_WANTS, am, true);
+
+        } else if (handle && !noauto) {
+
+                /* Automatically add mount points that aren't natively
+                 * configured to local-fs.target */
+
+                if (!nofail) /* auto + fail */
+                        return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
+                else /* auto + nofail */
+                        return unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true);
+        }
+
+        return 0;
+}
+
+static int mount_add_device_links(Mount *m) {
+        MountParameters *p;
+        int r;
+
+        assert(m);
+
+        if (!(p = get_mount_parameters_configured(m)))
+                return 0;
+
+        if (!p->what)
+                return 0;
+
+        if (!mount_is_bind(p) &&
+            !path_equal(m->where, "/") &&
+            p == &m->parameters_etc_fstab) {
+                bool nofail, noauto;
+
+                noauto = !!mount_test_option(p->options, "noauto");
+                nofail = !!mount_test_option(p->options, "nofail");
+
+                if ((r = unit_add_node_link(UNIT(m), p->what,
+                                            !noauto && nofail &&
+                                            UNIT(m)->manager->running_as == MANAGER_SYSTEM)) < 0)
+                        return r;
+        }
+
+        if (p->passno > 0 &&
+            !mount_is_bind(p) &&
+            UNIT(m)->manager->running_as == MANAGER_SYSTEM &&
+            !path_equal(m->where, "/")) {
+                char *name;
+                Unit *fsck;
+                /* Let's add in the fsck service */
+
+                /* aka SPECIAL_FSCK_SERVICE */
+                if (!(name = unit_name_from_path_instance("fsck", p->what, ".service")))
+                        return -ENOMEM;
+
+                if ((r = manager_load_unit_prepare(UNIT(m)->manager, name, NULL, NULL, &fsck)) < 0) {
+                        log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
+                        free(name);
+                        return r;
+                }
+
+                free(name);
+
+                SERVICE(fsck)->fsck_passno = p->passno;
+
+                if ((r = unit_add_two_dependencies(UNIT(m), UNIT_AFTER, UNIT_REQUIRES, fsck, true)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int mount_add_default_dependencies(Mount *m) {
+        int r;
+        MountParameters *p;
+
+        assert(m);
+
+        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+                return 0;
+
+        p = get_mount_parameters_configured(m);
+        if (p && needs_quota(p)) {
+                if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true)) < 0 ||
+                    (r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true)) < 0)
+                        return r;
+        }
+
+        if (!path_equal(m->where, "/"))
+                if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int mount_fix_timeouts(Mount *m) {
+        MountParameters *p;
+        const char *timeout = NULL;
+        Unit *other;
+        Iterator i;
+        usec_t u;
+        char *t;
+        int r;
+
+        assert(m);
+
+        if (!(p = get_mount_parameters_configured(m)))
+                return 0;
+
+        /* Allow configuration how long we wait for a device that
+         * backs a mount point to show up. This is useful to support
+         * endless device timeouts for devices that show up only after
+         * user input, like crypto devices. */
+
+        if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout")))
+                timeout += 31;
+        else if ((timeout = mount_test_option(p->options, "x-systemd-device-timeout")))
+                timeout += 25;
+        else
+                return 0;
+
+        t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE));
+        if (!t)
+                return -ENOMEM;
+
+        r = parse_usec(t, &u);
+        free(t);
+
+        if (r < 0) {
+                log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout);
+                return r;
+        }
+
+        SET_FOREACH(other, UNIT(m)->dependencies[UNIT_AFTER], i) {
+                if (other->type != UNIT_DEVICE)
+                        continue;
+
+                other->job_timeout = u;
+        }
+
+        return 0;
+}
+
+static int mount_verify(Mount *m) {
+        bool b;
+        char *e;
+        assert(m);
+
+        if (UNIT(m)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!m->from_etc_fstab && !m->from_fragment && !m->from_proc_self_mountinfo)
+                return -ENOENT;
+
+        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)->id);
+                return -EINVAL;
+        }
+
+        if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
+                log_error("Cannot create mount unit for API file system %s. Refusing.", m->where);
+                return -EINVAL;
+        }
+
+        if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
+                log_error("%s's What setting is missing. Refusing.", UNIT(m)->id);
+                return -EBADMSG;
+        }
+
+        if (m->exec_context.pam_name && m->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int mount_load(Unit *u) {
+        Mount *m = MOUNT(u);
+        int r;
+
+        assert(u);
+        assert(u->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->load_state == UNIT_LOADED) {
+                if ((r = unit_add_exec_dependencies(u, &m->exec_context)) < 0)
+                        return r;
+
+                if (UNIT(m)->fragment_path)
+                        m->from_fragment = true;
+                else if (m->from_etc_fstab)
+                        /* We always add several default dependencies to fstab mounts,
+                         * but we do not want the implicit complementing of Wants= with After=
+                         * in the target unit that this mount unit will be hooked into. */
+                        UNIT(m)->default_dependencies = false;
+
+                if (!m->where)
+                        if (!(m->where = unit_name_to_path(u->id)))
+                                return -ENOMEM;
+
+                path_kill_slashes(m->where);
+
+                if (!UNIT(m)->description)
+                        if ((r = unit_set_description(u, m->where)) < 0)
+                                return r;
+
+                if ((r = mount_add_device_links(m)) < 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_path_links(m)) < 0)
+                        return r;
+
+                if ((r = mount_add_automount_links(m)) < 0)
+                        return r;
+
+                if ((r = mount_add_fstab_links(m)) < 0)
+                        return r;
+
+                if (UNIT(m)->default_dependencies || m->from_etc_fstab)
+                        if ((r = mount_add_default_dependencies(m)) < 0)
+                                return r;
+
+                if ((r = unit_add_default_cgroups(u)) < 0)
+                        return r;
+
+                mount_fix_timeouts(m);
+        }
+
+        return mount_verify(m);
+}
+
+static int mount_notify_automount(Mount *m, int status) {
+        Unit *p;
+        int r;
+        Iterator i;
+
+        assert(m);
+
+        SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
+                if (p->type == UNIT_AUTOMOUNT) {
+                         r = automount_send_ready(AUTOMOUNT(p), status);
+                         if (r < 0)
+                                 return r;
+                }
+
+        return 0;
+}
+
+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_FAILED)
+                mount_notify_automount(m, -ENODEV);
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(m)->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], m->reload_result == MOUNT_SUCCESS);
+        m->reload_result = MOUNT_SUCCESS;
+}
+
+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);
+
+        p = get_mount_parameters(m);
+
+        fprintf(f,
+                "%sMount State: %s\n"
+                "%sResult: %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"
+                "%sDirectoryMode: %04o\n",
+                prefix, mount_state_to_string(m->state),
+                prefix, mount_result_to_string(m->result),
+                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, m->directory_mode);
+
+        if (m->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %lu\n",
+                        prefix, (unsigned 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,
+                            UNIT(m)->manager->environment,
+                            true,
+                            true,
+                            true,
+                            UNIT(m)->manager->confirm_spawn,
+                            UNIT(m)->cgroup_bondings,
+                            UNIT(m)->cgroup_attributes,
+                            &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, MountResult f) {
+        assert(m);
+
+        if (f != MOUNT_SUCCESS)
+                m->result = f;
+
+        mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
+}
+
+static void mount_enter_mounted(Mount *m, MountResult f) {
+        assert(m);
+
+        if (f != MOUNT_SUCCESS)
+                m->result = f;
+
+        mount_set_state(m, MOUNT_MOUNTED);
+}
+
+static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
+        int r;
+        Set *pid_set = NULL;
+        bool wait_for_exit = false;
+
+        assert(m);
+
+        if (f != MOUNT_SUCCESS)
+                m->result = f;
+
+        if (m->exec_context.kill_mode != KILL_NONE) {
+                int sig = (state == MOUNT_MOUNTING_SIGTERM ||
+                           state == MOUNT_UNMOUNTING_SIGTERM ||
+                           state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL;
+
+                if (m->control_pid > 0) {
+                        if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
+
+                                log_warning("Failed to kill control process %li: %m", (long) m->control_pid);
+                        else
+                                wait_for_exit = true;
+                }
+
+                if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+
+                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        /* Exclude the control pid from being killed via the cgroup */
+                        if (m->control_pid > 0)
+                                if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0)
+                                        goto fail;
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, pid_set)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                        log_warning("Failed to kill control group: %s", strerror(-r));
+                        } else if (r > 0)
+                                wait_for_exit = true;
+
+                        set_free(pid_set);
+                        pid_set = NULL;
+                }
+        }
+
+        if (wait_for_exit) {
+                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, MOUNT_SUCCESS);
+        else
+                mount_enter_dead(m, MOUNT_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
+
+        if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
+                mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
+        else
+                mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
+
+        if (pid_set)
+                set_free(pid_set);
+}
+
+static void mount_enter_unmounting(Mount *m) {
+        int r;
+
+        assert(m);
+
+        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' task: %s", UNIT(m)->id, strerror(-r));
+        mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
+}
+
+static void mount_enter_mounting(Mount *m) {
+        int r;
+        MountParameters *p;
+
+        assert(m);
+
+        m->control_command_id = MOUNT_EXEC_MOUNT;
+        m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
+
+        mkdir_p(m->where, m->directory_mode);
+
+        /* Create the source directory for bind-mounts if needed */
+        p = get_mount_parameters_configured(m);
+        if (p && mount_is_bind(p))
+                mkdir_p(p->what, m->directory_mode);
+
+        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.fstype : "auto",
+                                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' task: %s", UNIT(m)->id, strerror(-r));
+        mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
+}
+
+static void mount_enter_mounting_done(Mount *m) {
+        assert(m);
+
+        mount_set_state(m, MOUNT_MOUNTING_DONE);
+}
+
+static void mount_enter_remounting(Mount *m) {
+        int r;
+
+        assert(m);
+
+        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 ? m->parameters_fragment.fstype : "auto",
+                                "-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)
+                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:
+        log_warning("%s failed to run 'remount' task: %s", UNIT(m)->id, strerror(-r));
+        m->reload_result = MOUNT_FAILURE_RESOURCES;
+        mount_enter_mounted(m, MOUNT_SUCCESS);
+}
+
+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 ||
+            m->state == MOUNT_MOUNTING_SIGTERM ||
+            m->state == MOUNT_MOUNTING_SIGKILL)
+                return -EAGAIN;
+
+        /* Already on it! */
+        if (m->state == MOUNT_MOUNTING)
+                return 0;
+
+        assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
+
+        m->result = MOUNT_SUCCESS;
+        m->reload_result = MOUNT_SUCCESS;
+
+        mount_enter_mounting(m);
+        return 0;
+}
+
+static int mount_stop(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        /* Already on it */
+        if (m->state == MOUNT_UNMOUNTING ||
+            m->state == MOUNT_UNMOUNTING_SIGKILL ||
+            m->state == MOUNT_UNMOUNTING_SIGTERM ||
+            m->state == MOUNT_MOUNTING_SIGTERM ||
+            m->state == MOUNT_MOUNTING_SIGKILL)
+                return 0;
+
+        assert(m->state == MOUNT_MOUNTING ||
+               m->state == MOUNT_MOUNTING_DONE ||
+               m->state == MOUNT_MOUNTED ||
+               m->state == MOUNT_REMOUNTING ||
+               m->state == MOUNT_REMOUNTING_SIGTERM ||
+               m->state == MOUNT_REMOUNTING_SIGKILL);
+
+        mount_enter_unmounting(m);
+        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);
+        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, "result", mount_result_to_string(m->result));
+        unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result));
+
+        if (m->control_pid > 0)
+                unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) 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);
+
+        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, "result")) {
+                MountResult f;
+
+                f = mount_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != MOUNT_SUCCESS)
+                        m->result = f;
+
+        } else if (streq(key, "reload-result")) {
+                MountResult f;
+
+                f = mount_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse reload result value %s", value);
+                else if (f != MOUNT_SUCCESS)
+                        m->reload_result = f;
+
+        } else if (streq(key, "control-pid")) {
+                pid_t pid;
+
+                if (parse_pid(value, &pid) < 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        m->control_pid = 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);
+        MountResult f;
+
+        assert(m);
+        assert(pid >= 0);
+
+        if (pid != m->control_pid)
+                return;
+
+        m->control_pid = 0;
+
+        if (is_clean_exit(code, status))
+                f = MOUNT_SUCCESS;
+        else if (code == CLD_EXITED)
+                f = MOUNT_FAILURE_EXIT_CODE;
+        else if (code == CLD_KILLED)
+                f = MOUNT_FAILURE_SIGNAL;
+        else if (code == CLD_DUMPED)
+                f = MOUNT_FAILURE_CORE_DUMP;
+        else
+                assert_not_reached("Unknown code");
+
+        if (f != MOUNT_SUCCESS)
+                m->result = f;
+
+        if (m->control_command) {
+                exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status);
+
+                m->control_command = NULL;
+                m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
+        }
+
+        log_full(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+                 "%s mount process exited, code=%s status=%i", u->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:
+
+                if (f == MOUNT_SUCCESS)
+                        mount_enter_mounted(m, f);
+                else if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, f);
+                else
+                        mount_enter_dead(m, f);
+                break;
+
+        case MOUNT_REMOUNTING:
+        case MOUNT_REMOUNTING_SIGKILL:
+        case MOUNT_REMOUNTING_SIGTERM:
+
+                m->reload_result = f;
+                if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, MOUNT_SUCCESS);
+                else
+                        mount_enter_dead(m, MOUNT_SUCCESS);
+
+                break;
+
+        case MOUNT_UNMOUNTING:
+        case MOUNT_UNMOUNTING_SIGKILL:
+        case MOUNT_UNMOUNTING_SIGTERM:
+
+                if (f == MOUNT_SUCCESS)
+                        mount_enter_dead(m, f);
+                else if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, f);
+                else
+                        mount_enter_dead(m, f);
+                break;
+
+        default:
+                assert_not_reached("Uh, control process died at wrong time.");
+        }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
+}
+
+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->id);
+                mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
+                break;
+
+        case MOUNT_REMOUNTING:
+                log_warning("%s remounting timed out. Stopping.", u->id);
+                m->reload_result = MOUNT_FAILURE_TIMEOUT;
+                mount_enter_mounted(m, MOUNT_SUCCESS);
+                break;
+
+        case MOUNT_UNMOUNTING:
+                log_warning("%s unmounting timed out. Stopping.", u->id);
+                mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
+                break;
+
+        case MOUNT_MOUNTING_SIGTERM:
+                if (m->exec_context.send_sigkill) {
+                        log_warning("%s mounting timed out. Killing.", u->id);
+                        mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->id);
+
+                        if (m->from_proc_self_mountinfo)
+                                mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
+                        else
+                                mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case MOUNT_REMOUNTING_SIGTERM:
+                if (m->exec_context.send_sigkill) {
+                        log_warning("%s remounting timed out. Killing.", u->id);
+                        mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->id);
+
+                        if (m->from_proc_self_mountinfo)
+                                mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
+                        else
+                                mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case MOUNT_UNMOUNTING_SIGTERM:
+                if (m->exec_context.send_sigkill) {
+                        log_warning("%s unmounting timed out. Killing.", u->id);
+                        mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->id);
+
+                        if (m->from_proc_self_mountinfo)
+                                mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
+                        else
+                                mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case MOUNT_MOUNTING_SIGKILL:
+        case MOUNT_REMOUNTING_SIGKILL:
+        case MOUNT_UNMOUNTING_SIGKILL:
+                log_warning("%s mount process still around after SIGKILL. Ignoring.", u->id);
+
+                if (m->from_proc_self_mountinfo)
+                        mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
+                else
+                        mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+                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,
+                int passno,
+                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) || mount_point_ignore(where))
+                return 0;
+
+        if (streq(fstype, "autofs"))
+                return 0;
+
+        /* probably some kind of swap, ignore */
+        if (!is_path(where))
+                return 0;
+
+        e = unit_name_from_path(where, ".mount");
+        if (!e)
+                return -ENOMEM;
+
+        u = manager_get_unit(m, e);
+        if (!u) {
+                delete = true;
+
+                u = unit_new(m, sizeof(Mount));
+                if (!u) {
+                        free(e);
+                        return -ENOMEM;
+                }
+
+                r = unit_add_name(u, e);
+                free(e);
+
+                if (r < 0)
+                        goto fail;
+
+                MOUNT(u)->where = strdup(where);
+                if (!MOUNT(u)->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;
+
+        p->passno = passno;
+
+        unit_add_to_dbus_queue(u);
+
+        return 0;
+
+fail:
+        free(w);
+        free(o);
+        free(f);
+
+        if (delete && u)
+                unit_free(u);
+
+        return r;
+}
+
+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 = 0;
+        struct mntent* me;
+
+        assert(m);
+
+        errno = 0;
+        if (!(f = setmntent("/etc/fstab", "r")))
+                return -errno;
+
+        while ((me = getmntent(f))) {
+                char *where, *what;
+                int k;
+
+                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)
+                                k = pri;
+                        else
+                                k = swap_add_one(m,
+                                                 what,
+                                                 NULL,
+                                                 pri,
+                                                 !!mount_test_option(me->mnt_opts, "noauto"),
+                                                 !!mount_test_option(me->mnt_opts, "nofail"),
+                                                 !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"),
+                                                 false);
+                } else
+                        k = mount_add_one(m, what, where, me->mnt_opts, me->mnt_type, me->mnt_passno, false, false);
+
+                free(what);
+                free(where);
+
+                if (k < 0)
+                        r = k;
+        }
+
+finish:
+
+        endmntent(f);
+        return r;
+}
+
+static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
+        int r = 0;
+        unsigned i;
+        char *device, *path, *options, *options2, *fstype, *d, *p, *o;
+
+        assert(m);
+
+        rewind(m->proc_self_mountinfo);
+
+        for (i = 1;; i++) {
+                int k;
+
+                device = path = options = options2 = fstype = d = p = o = 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) separator */
+                                "%ms "       /* (9) file system type */
+                                "%ms"        /* (10) mount source */
+                                "%ms"        /* (11) mount options 2 */
+                                "%*[^\n]",   /* some rubbish at the end */
+                                &path,
+                                &options,
+                                &fstype,
+                                &device,
+                                &options2)) != 5) {
+
+                        if (k == EOF)
+                                break;
+
+                        log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
+                        goto clean_up;
+                }
+
+                if (asprintf(&o, "%s,%s", options, options2) < 0) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(d = cunescape(device)) ||
+                    !(p = cunescape(path))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if ((k = mount_add_one(m, d, p, o, fstype, 0, true, set_flags)) < 0)
+                        r = k;
+
+clean_up:
+                free(device);
+                free(path);
+                free(options);
+                free(options2);
+                free(fstype);
+                free(d);
+                free(p);
+                free(o);
+        }
+
+finish:
+        free(device);
+        free(path);
+        free(options);
+        free(options2);
+        free(fstype);
+        free(d);
+        free(p);
+        free(o);
+
+        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 = EPOLLPRI;
+                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) {
+        Unit *u;
+        int r;
+
+        assert(m);
+        assert(events & EPOLLPRI);
+
+        /* 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(-r));
+
+                /* Reset flags, just in case, for later calls */
+                LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
+                        Mount *mount = MOUNT(u);
+
+                        mount->is_mounted = mount->just_mounted = mount->just_changed = false;
+                }
+
+                return;
+        }
+
+        manager_dispatch_load_queue(m);
+
+        LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
+                Mount *mount = MOUNT(u);
+
+                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, MOUNT_SUCCESS);
+                                break;
+
+                        default:
+                                mount_set_state(mount, mount->state);
+                                break;
+
+                        }
+
+                } else if (mount->just_mounted || mount->just_changed) {
+
+                        /* New or changed mount entry */
+
+                        switch (mount->state) {
+
+                        case MOUNT_DEAD:
+                        case MOUNT_FAILED:
+                                mount_enter_mounted(mount, MOUNT_SUCCESS);
+                                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;
+        }
+}
+
+static void mount_reset_failed(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        if (m->state == MOUNT_FAILED)
+                mount_set_state(m, MOUNT_DEAD);
+
+        m->result = MOUNT_SUCCESS;
+        m->reload_result = MOUNT_SUCCESS;
+}
+
+static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Mount *m = MOUNT(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(m);
+
+        if (who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes");
+                return -ESRCH;
+        }
+
+        if (m->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ESRCH;
+        }
+
+        if (who == KILL_CONTROL || who == KILL_ALL)
+                if (m->control_pid > 0)
+                        if (kill(m->control_pid, signo) < 0)
+                                r = -errno;
+
+        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control pid from being killed via the cgroup */
+                if (m->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, signo, false, pid_set)) < 0)
+                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        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_FAILED] = "failed"
+};
+
+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);
+
+static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
+        [MOUNT_SUCCESS] = "success",
+        [MOUNT_FAILURE_RESOURCES] = "resources",
+        [MOUNT_FAILURE_TIMEOUT] = "timeout",
+        [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
+        [MOUNT_FAILURE_SIGNAL] = "signal",
+        [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
+
+const UnitVTable mount_vtable = {
+        .suffix = ".mount",
+        .object_size = sizeof(Mount),
+        .sections =
+                "Unit\0"
+                "Mount\0"
+                "Install\0",
+
+        .no_alias = true,
+        .no_instances = true,
+        .show_status = 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,
+
+        .kill = mount_kill,
+
+        .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,
+
+        .reset_failed = mount_reset_failed,
+
+        .bus_interface = "org.freedesktop.systemd1.Mount",
+        .bus_message_handler = bus_mount_message_handler,
+        .bus_invalidating_properties =  bus_mount_invalidating_properties,
+
+        .enumerate = mount_enumerate,
+        .shutdown = mount_shutdown
+};
diff --git a/src/core/mount.h b/src/core/mount.h
new file mode 100644
index 0000000..9318444
--- /dev/null
+++ b/src/core/mount.h
@@ -0,0 +1,124 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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_FAILED,
+        _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;
+        int passno;
+} MountParameters;
+
+typedef enum MountResult {
+        MOUNT_SUCCESS,
+        MOUNT_FAILURE_RESOURCES,
+        MOUNT_FAILURE_TIMEOUT,
+        MOUNT_FAILURE_EXIT_CODE,
+        MOUNT_FAILURE_SIGNAL,
+        MOUNT_FAILURE_CORE_DUMP,
+        _MOUNT_RESULT_MAX,
+        _MOUNT_RESULT_INVALID = -1
+} MountResult;
+
+struct Mount {
+        Unit 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;
+
+        MountResult result;
+        MountResult reload_result;
+
+        mode_t directory_mode;
+
+        usec_t timeout_usec;
+
+        ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        MountState state, deserialized_state;
+
+        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);
+
+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);
+
+const char* mount_result_to_string(MountResult i);
+MountResult mount_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/namespace.c b/src/core/namespace.c
new file mode 100644
index 0000000..09bc829
--- /dev/null
+++ b/src/core/namespace.c
@@ -0,0 +1,346 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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;
+
+        default:
+                assert_not_reached("Unknown mode");
+        }
+
+        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 independent step. */
+                if (flags)
+                        r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_REC|flags, NULL);
+
+                /* Avoid exponential 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) {
+                mode_t u;
+
+                memcpy(private_dir, tmp_dir, sizeof(tmp_dir)-1);
+
+                u = umask(0000);
+                if (mkdir(private_dir, 0777 + S_ISVTX) < 0) {
+                        umask(u);
+
+                        r = -errno;
+                        goto fail;
+                }
+
+                umask(u);
+                remove_private = true;
+        }
+
+        if (unshare(CLONE_NEWNS) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* Remount / as SLAVE so that nothing mounted in the namespace
+           shows up in the parent */
+        if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        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/core/namespace.h b/src/core/namespace.h
new file mode 100644
index 0000000..7cf1ded
--- /dev/null
+++ b/src/core/namespace.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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/core/path.c b/src/core/path.c
new file mode 100644
index 0000000..1d50885
--- /dev/null
+++ b/src/core/path.c
@@ -0,0 +1,771 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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/inotify.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "unit.h"
+#include "unit-name.h"
+#include "path.h"
+#include "mkdir.h"
+#include "dbus-path.h"
+#include "special.h"
+#include "bus-errors.h"
+
+static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
+        [PATH_DEAD] = UNIT_INACTIVE,
+        [PATH_WAITING] = UNIT_ACTIVE,
+        [PATH_RUNNING] = UNIT_ACTIVE,
+        [PATH_FAILED] = UNIT_FAILED
+};
+
+int path_spec_watch(PathSpec *s, Unit *u) {
+
+        static const int flags_table[_PATH_TYPE_MAX] = {
+                [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
+                [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
+                [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
+                [PATH_MODIFIED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO|IN_MODIFY,
+                [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
+        };
+
+        bool exists = false;
+        char *k, *slash;
+        int r;
+
+        assert(u);
+        assert(s);
+
+        path_spec_unwatch(s, u);
+
+        if (!(k = strdup(s->path)))
+                return -ENOMEM;
+
+        if ((s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if (unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if ((s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type])) >= 0)
+                exists = true;
+
+        do {
+                int flags;
+
+                /* This assumes the path was passed through path_kill_slashes()! */
+                if (!(slash = strrchr(k, '/')))
+                        break;
+
+                /* Trim the path at the last slash. Keep the slash if it's the root dir. */
+                slash[slash == k] = 0;
+
+                flags = IN_MOVE_SELF;
+                if (!exists)
+                        flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
+
+                if (inotify_add_watch(s->inotify_fd, k, flags) >= 0)
+                        exists = true;
+        } while (slash != k);
+
+        return 0;
+
+fail:
+        free(k);
+
+        path_spec_unwatch(s, u);
+        return r;
+}
+
+void path_spec_unwatch(PathSpec *s, Unit *u) {
+
+        if (s->inotify_fd < 0)
+                return;
+
+        unit_unwatch_fd(u, &s->watch);
+
+        close_nointr_nofail(s->inotify_fd);
+        s->inotify_fd = -1;
+}
+
+int path_spec_fd_event(PathSpec *s, uint32_t events) {
+        uint8_t *buf = NULL;
+        struct inotify_event *e;
+        ssize_t k;
+        int l;
+        int r = 0;
+
+        if (events != EPOLLIN) {
+                log_error("Got Invalid poll event on inotify.");
+                r = -EINVAL;
+                goto out;
+        }
+
+        if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) {
+                log_error("FIONREAD failed: %m");
+                r = -errno;
+                goto out;
+        }
+
+        assert(l > 0);
+
+        if (!(buf = malloc(l))) {
+                log_error("Failed to allocate buffer: %m");
+                r = -errno;
+                goto out;
+        }
+
+        if ((k = read(s->inotify_fd, buf, l)) < 0) {
+                log_error("Failed to read inotify event: %m");
+                r = -errno;
+                goto out;
+        }
+
+        e = (struct inotify_event*) buf;
+
+        while (k > 0) {
+                size_t step;
+
+                if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
+                    s->primary_wd == e->wd)
+                        r = 1;
+
+                step = sizeof(struct inotify_event) + e->len;
+                assert(step <= (size_t) k);
+
+                e = (struct inotify_event*) ((uint8_t*) e + step);
+                k -= step;
+        }
+out:
+        free(buf);
+        return r;
+}
+
+static bool path_spec_check_good(PathSpec *s, bool initial) {
+        bool good = false;
+
+        switch (s->type) {
+
+        case PATH_EXISTS:
+                good = access(s->path, F_OK) >= 0;
+                break;
+
+        case PATH_EXISTS_GLOB:
+                good = glob_exists(s->path) > 0;
+                break;
+
+        case PATH_DIRECTORY_NOT_EMPTY: {
+                int k;
+
+                k = dir_is_empty(s->path);
+                good = !(k == -ENOENT || k > 0);
+                break;
+        }
+
+        case PATH_CHANGED:
+        case PATH_MODIFIED: {
+                bool b;
+
+                b = access(s->path, F_OK) >= 0;
+                good = !initial && b != s->previous_exists;
+                s->previous_exists = b;
+                break;
+        }
+
+        default:
+                ;
+        }
+
+        return good;
+}
+
+static bool path_spec_startswith(PathSpec *s, const char *what) {
+        return path_startswith(s->path, what);
+}
+
+static void path_spec_mkdir(PathSpec *s, mode_t mode) {
+        int r;
+
+        if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
+                return;
+
+        if ((r = mkdir_p(s->path, mode)) < 0)
+                log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
+}
+
+static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
+        fprintf(f,
+                "%s%s: %s\n",
+                prefix,
+                path_type_to_string(s->type),
+                s->path);
+}
+
+void path_spec_done(PathSpec *s) {
+        assert(s);
+        assert(s->inotify_fd == -1);
+
+        free(s->path);
+}
+
+static void path_init(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        p->directory_mode = 0755;
+}
+
+static void path_done(Unit *u) {
+        Path *p = PATH(u);
+        PathSpec *s;
+
+        assert(p);
+
+        unit_ref_unset(&p->unit);
+
+        while ((s = p->specs)) {
+                path_spec_unwatch(s, u);
+                LIST_REMOVE(PathSpec, spec, p->specs, s);
+                path_spec_done(s);
+                free(s);
+        }
+}
+
+int path_add_one_mount_link(Path *p, Mount *m) {
+        PathSpec *s;
+        int r;
+
+        assert(p);
+        assert(m);
+
+        if (UNIT(p)->load_state != UNIT_LOADED ||
+            UNIT(m)->load_state != UNIT_LOADED)
+                return 0;
+
+        LIST_FOREACH(spec, s, p->specs) {
+
+                if (!path_spec_startswith(s, m->where))
+                        continue;
+
+                if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int path_add_mount_links(Path *p) {
+        Unit *other;
+        int r;
+
+        assert(p);
+
+        LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT])
+                if ((r = path_add_one_mount_link(p, MOUNT(other))) < 0)
+                        return r;
+
+        return 0;
+}
+
+static int path_verify(Path *p) {
+        assert(p);
+
+        if (UNIT(p)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!p->specs) {
+                log_error("%s lacks path setting. Refusing.", UNIT(p)->id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int path_add_default_dependencies(Path *p) {
+        int r;
+
+        assert(p);
+
+        if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
+                if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
+                        return r;
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+                        return r;
+        }
+
+        return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
+static int path_load(Unit *u) {
+        Path *p = PATH(u);
+        int r;
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        if ((r = unit_load_fragment_and_dropin(u)) < 0)
+                return r;
+
+        if (u->load_state == UNIT_LOADED) {
+
+                if (!UNIT_DEREF(p->unit)) {
+                        Unit *x;
+
+                        r = unit_load_related_unit(u, ".service", &x);
+                        if (r < 0)
+                                return r;
+
+                        unit_ref_set(&p->unit, x);
+                }
+
+                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
+                if (r < 0)
+                        return r;
+
+                if ((r = path_add_mount_links(p)) < 0)
+                        return r;
+
+                if (UNIT(p)->default_dependencies)
+                        if ((r = path_add_default_dependencies(p)) < 0)
+                                return r;
+        }
+
+        return path_verify(p);
+}
+
+static void path_dump(Unit *u, FILE *f, const char *prefix) {
+        Path *p = PATH(u);
+        PathSpec *s;
+
+        assert(p);
+        assert(f);
+
+        fprintf(f,
+                "%sPath State: %s\n"
+                "%sResult: %s\n"
+                "%sUnit: %s\n"
+                "%sMakeDirectory: %s\n"
+                "%sDirectoryMode: %04o\n",
+                prefix, path_state_to_string(p->state),
+                prefix, path_result_to_string(p->result),
+                prefix, UNIT_DEREF(p->unit)->id,
+                prefix, yes_no(p->make_directory),
+                prefix, p->directory_mode);
+
+        LIST_FOREACH(spec, s, p->specs)
+                path_spec_dump(s, f, prefix);
+}
+
+static void path_unwatch(Path *p) {
+        PathSpec *s;
+
+        assert(p);
+
+        LIST_FOREACH(spec, s, p->specs)
+                path_spec_unwatch(s, UNIT(p));
+}
+
+static int path_watch(Path *p) {
+        int r;
+        PathSpec *s;
+
+        assert(p);
+
+        LIST_FOREACH(spec, s, p->specs)
+                if ((r = path_spec_watch(s, UNIT(p))) < 0)
+                        return r;
+
+        return 0;
+}
+
+static void path_set_state(Path *p, PathState state) {
+        PathState old_state;
+        assert(p);
+
+        old_state = p->state;
+        p->state = state;
+
+        if (state != PATH_WAITING &&
+            (state != PATH_RUNNING || p->inotify_triggered))
+                path_unwatch(p);
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(p)->id,
+                          path_state_to_string(old_state),
+                          path_state_to_string(state));
+
+        unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
+}
+
+static void path_enter_waiting(Path *p, bool initial, bool recheck);
+
+static int path_coldplug(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(p);
+        assert(p->state == PATH_DEAD);
+
+        if (p->deserialized_state != p->state) {
+
+                if (p->deserialized_state == PATH_WAITING ||
+                    p->deserialized_state == PATH_RUNNING)
+                        path_enter_waiting(p, true, true);
+                else
+                        path_set_state(p, p->deserialized_state);
+        }
+
+        return 0;
+}
+
+static void path_enter_dead(Path *p, PathResult f) {
+        assert(p);
+
+        if (f != PATH_SUCCESS)
+                p->result = f;
+
+        path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
+}
+
+static void path_enter_running(Path *p) {
+        int r;
+        DBusError error;
+
+        assert(p);
+        dbus_error_init(&error);
+
+        /* Don't start job if we are supposed to go down */
+        if (UNIT(p)->job && UNIT(p)->job->type == JOB_STOP)
+                return;
+
+        if ((r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
+                goto fail;
+
+        p->inotify_triggered = false;
+
+        if ((r = path_watch(p)) < 0)
+                goto fail;
+
+        path_set_state(p, PATH_RUNNING);
+        return;
+
+fail:
+        log_warning("%s failed to queue unit startup job: %s", UNIT(p)->id, bus_error(&error, r));
+        path_enter_dead(p, PATH_FAILURE_RESOURCES);
+
+        dbus_error_free(&error);
+}
+
+static bool path_check_good(Path *p, bool initial) {
+        PathSpec *s;
+        bool good = false;
+
+        assert(p);
+
+        LIST_FOREACH(spec, s, p->specs) {
+                good = path_spec_check_good(s, initial);
+
+                if (good)
+                        break;
+        }
+
+        return good;
+}
+
+static void path_enter_waiting(Path *p, bool initial, bool recheck) {
+        int r;
+
+        if (recheck)
+                if (path_check_good(p, initial)) {
+                        log_debug("%s got triggered.", UNIT(p)->id);
+                        path_enter_running(p);
+                        return;
+                }
+
+        if ((r = path_watch(p)) < 0)
+                goto fail;
+
+        /* Hmm, so now we have created inotify watches, but the file
+         * might have appeared/been removed by now, so we must
+         * recheck */
+
+        if (recheck)
+                if (path_check_good(p, false)) {
+                        log_debug("%s got triggered.", UNIT(p)->id);
+                        path_enter_running(p);
+                        return;
+                }
+
+        path_set_state(p, PATH_WAITING);
+        return;
+
+fail:
+        log_warning("%s failed to enter waiting state: %s", UNIT(p)->id, strerror(-r));
+        path_enter_dead(p, PATH_FAILURE_RESOURCES);
+}
+
+static void path_mkdir(Path *p) {
+        PathSpec *s;
+
+        assert(p);
+
+        if (!p->make_directory)
+                return;
+
+        LIST_FOREACH(spec, s, p->specs)
+                path_spec_mkdir(s, p->directory_mode);
+}
+
+static int path_start(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(p);
+        assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
+
+        if (UNIT_DEREF(p->unit)->load_state != UNIT_LOADED)
+                return -ENOENT;
+
+        path_mkdir(p);
+
+        p->result = PATH_SUCCESS;
+        path_enter_waiting(p, true, true);
+
+        return 0;
+}
+
+static int path_stop(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(p);
+        assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
+
+        path_enter_dead(p, PATH_SUCCESS);
+        return 0;
+}
+
+static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Path *p = PATH(u);
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", path_state_to_string(p->state));
+        unit_serialize_item(u, f, "result", path_result_to_string(p->result));
+
+        return 0;
+}
+
+static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Path *p = PATH(u);
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                PathState state;
+
+                if ((state = path_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        p->deserialized_state = state;
+
+        } else if (streq(key, "result")) {
+                PathResult f;
+
+                f = path_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != PATH_SUCCESS)
+                        p->result = f;
+
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState path_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[PATH(u)->state];
+}
+
+static const char *path_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return path_state_to_string(PATH(u)->state);
+}
+
+static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
+        Path *p = PATH(u);
+        PathSpec *s;
+        int changed;
+
+        assert(p);
+        assert(fd >= 0);
+
+        if (p->state != PATH_WAITING &&
+            p->state != PATH_RUNNING)
+                return;
+
+        /* log_debug("inotify wakeup on %s.", u->id); */
+
+        LIST_FOREACH(spec, s, p->specs)
+                if (path_spec_owns_inotify_fd(s, fd))
+                        break;
+
+        if (!s) {
+                log_error("Got event on unknown fd.");
+                goto fail;
+        }
+
+        changed = path_spec_fd_event(s, events);
+        if (changed < 0)
+                goto fail;
+
+        /* If we are already running, then remember that one event was
+         * dispatched so that we restart the service only if something
+         * actually changed on disk */
+        p->inotify_triggered = true;
+
+        if (changed)
+                path_enter_running(p);
+        else
+                path_enter_waiting(p, false, true);
+
+        return;
+
+fail:
+        path_enter_dead(p, PATH_FAILURE_RESOURCES);
+}
+
+void path_unit_notify(Unit *u, UnitActiveState new_state) {
+        Iterator i;
+        Unit *k;
+
+        if (u->type == UNIT_PATH)
+                return;
+
+        SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
+                Path *p;
+
+                if (k->type != UNIT_PATH)
+                        continue;
+
+                if (k->load_state != UNIT_LOADED)
+                        continue;
+
+                p = PATH(k);
+
+                if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
+                        log_debug("%s got notified about unit deactivation.", UNIT(p)->id);
+
+                        /* Hmm, so inotify was triggered since the
+                         * last activation, so I guess we need to
+                         * recheck what is going on. */
+                        path_enter_waiting(p, false, p->inotify_triggered);
+                }
+        }
+}
+
+static void path_reset_failed(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(p);
+
+        if (p->state == PATH_FAILED)
+                path_set_state(p, PATH_DEAD);
+
+        p->result = PATH_SUCCESS;
+}
+
+static const char* const path_state_table[_PATH_STATE_MAX] = {
+        [PATH_DEAD] = "dead",
+        [PATH_WAITING] = "waiting",
+        [PATH_RUNNING] = "running",
+        [PATH_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
+
+static const char* const path_type_table[_PATH_TYPE_MAX] = {
+        [PATH_EXISTS] = "PathExists",
+        [PATH_EXISTS_GLOB] = "PathExistsGlob",
+        [PATH_CHANGED] = "PathChanged",
+        [PATH_MODIFIED] = "PathModified",
+        [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
+
+static const char* const path_result_table[_PATH_RESULT_MAX] = {
+        [PATH_SUCCESS] = "success",
+        [PATH_FAILURE_RESOURCES] = "resources"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
+
+const UnitVTable path_vtable = {
+        .suffix = ".path",
+        .object_size = sizeof(Path),
+        .sections =
+                "Unit\0"
+                "Path\0"
+                "Install\0",
+
+        .init = path_init,
+        .done = path_done,
+        .load = path_load,
+
+        .coldplug = path_coldplug,
+
+        .dump = path_dump,
+
+        .start = path_start,
+        .stop = path_stop,
+
+        .serialize = path_serialize,
+        .deserialize_item = path_deserialize_item,
+
+        .active_state = path_active_state,
+        .sub_state_to_string = path_sub_state_to_string,
+
+        .fd_event = path_fd_event,
+
+        .reset_failed = path_reset_failed,
+
+        .bus_interface = "org.freedesktop.systemd1.Path",
+        .bus_message_handler = bus_path_message_handler,
+        .bus_invalidating_properties = bus_path_invalidating_properties
+};
diff --git a/src/core/path.h b/src/core/path.h
new file mode 100644
index 0000000..efb6b5e
--- /dev/null
+++ b/src/core/path.h
@@ -0,0 +1,113 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foopathhfoo
+#define foopathhfoo
+
+/***
+  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 Path Path;
+
+#include "unit.h"
+#include "mount.h"
+
+typedef enum PathState {
+        PATH_DEAD,
+        PATH_WAITING,
+        PATH_RUNNING,
+        PATH_FAILED,
+        _PATH_STATE_MAX,
+        _PATH_STATE_INVALID = -1
+} PathState;
+
+typedef enum PathType {
+        PATH_EXISTS,
+        PATH_EXISTS_GLOB,
+        PATH_DIRECTORY_NOT_EMPTY,
+        PATH_CHANGED,
+        PATH_MODIFIED,
+        _PATH_TYPE_MAX,
+        _PATH_TYPE_INVALID = -1
+} PathType;
+
+typedef struct PathSpec {
+        char *path;
+
+        Watch watch;
+
+        LIST_FIELDS(struct PathSpec, spec);
+
+        PathType type;
+        int inotify_fd;
+        int primary_wd;
+
+        bool previous_exists;
+} PathSpec;
+
+int path_spec_watch(PathSpec *s, Unit *u);
+void path_spec_unwatch(PathSpec *s, Unit *u);
+int path_spec_fd_event(PathSpec *s, uint32_t events);
+void path_spec_done(PathSpec *s);
+
+static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
+        return s->inotify_fd == fd;
+}
+
+typedef enum PathResult {
+        PATH_SUCCESS,
+        PATH_FAILURE_RESOURCES,
+        _PATH_RESULT_MAX,
+        _PATH_RESULT_INVALID = -1
+} PathResult;
+
+struct Path {
+        Unit meta;
+
+        LIST_HEAD(PathSpec, specs);
+
+        UnitRef unit;
+
+        PathState state, deserialized_state;
+
+        bool inotify_triggered;
+
+        bool make_directory;
+        mode_t directory_mode;
+
+        PathResult result;
+};
+
+void path_unit_notify(Unit *u, UnitActiveState new_state);
+
+/* Called from the mount code figure out if a mount is a dependency of
+ * any of the paths of this path object */
+int path_add_one_mount_link(Path *p, Mount *m);
+
+extern const UnitVTable path_vtable;
+
+const char* path_state_to_string(PathState i);
+PathState path_state_from_string(const char *s);
+
+const char* path_type_to_string(PathType i);
+PathType path_type_from_string(const char *s);
+
+const char* path_result_to_string(PathResult i);
+PathResult path_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/polkit.h b/src/core/polkit.h
new file mode 100644
index 0000000..0d08194
--- /dev/null
+++ b/src/core/polkit.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foopolkithfoo
+#define foopolkithfoo
+
+/***
+  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 <dbus/dbus.h>
+
+int verify_polkit(
+                DBusConnection *c,
+                DBusMessage *request,
+                const char *action,
+                bool interactive,
+                bool *challenge,
+                DBusError *error);
+
+#endif
diff --git a/src/core/securebits.h b/src/core/securebits.h
new file mode 100644
index 0000000..ba0bba5
--- /dev/null
+++ b/src/core/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 compatibility 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/core/selinux-setup.c b/src/core/selinux-setup.c
new file mode 100644
index 0000000..a7e1fa4
--- /dev/null
+++ b/src/core/selinux-setup.c
@@ -0,0 +1,112 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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>
+
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include "selinux-setup.h"
+#include "mount-setup.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+#include "label.h"
+
+int selinux_setup(bool *loaded_policy) {
+
+#ifdef HAVE_SELINUX
+       int enforce = 0;
+       usec_t before_load, after_load;
+       security_context_t con;
+       int r;
+
+       assert(loaded_policy);
+
+       /* Make sure getcon() works, which needs /proc and /sys */
+       mount_setup_early();
+
+       /* Already initialized by somebody else? */
+       r = getcon_raw(&con);
+       if (r == 0) {
+               bool initialized;
+
+               initialized = !streq(con, "kernel");
+               freecon(con);
+
+               if (initialized)
+                       return 0;
+       }
+
+       /* Make sure we have no fds open while loading the policy and
+        * transitioning */
+       log_close();
+
+       /* Now load the policy */
+       before_load = now(CLOCK_MONOTONIC);
+       r = selinux_init_load_policy(&enforce);
+
+       if (r == 0) {
+               char timespan[FORMAT_TIMESPAN_MAX];
+               char *label;
+
+               label_retest_selinux();
+
+               /* Transition to the new context */
+               r = label_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
+               if (r < 0 || label == NULL) {
+                       log_open();
+                       log_error("Failed to compute init label, ignoring.");
+               } else {
+                       r = setcon(label);
+
+                       log_open();
+                       if (r < 0)
+                               log_error("Failed to transition into init label '%s', ignoring.", label);
+
+                       label_free(label);
+               }
+
+               after_load = now(CLOCK_MONOTONIC);
+
+               log_info("Successfully loaded SELinux policy in %s.",
+                         format_timespan(timespan, sizeof(timespan), after_load - before_load));
+
+               *loaded_policy = true;
+
+       } else {
+               log_open();
+
+               if (enforce > 0) {
+                       log_error("Failed to load SELinux policy. Freezing.");
+                       return -EIO;
+               } else
+                       log_debug("Unable to load SELinux policy. Ignoring.");
+       }
+#endif
+
+       return 0;
+}
diff --git a/src/core/selinux-setup.h b/src/core/selinux-setup.h
new file mode 100644
index 0000000..6b8fe00
--- /dev/null
+++ b/src/core/selinux-setup.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooselinuxsetuphfoo
+#define fooselinuxsetuphfoo
+
+/***
+  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 selinux_setup(bool *loaded_policy);
+
+#endif
diff --git a/src/core/service.c b/src/core/service.c
new file mode 100644
index 0000000..bf2e0a9
--- /dev/null
+++ b/src/core/service.c
@@ -0,0 +1,3797 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <sys/reboot.h>
+
+#include "manager.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"
+#include "special.h"
+#include "bus-errors.h"
+#include "exit-status.h"
+#include "def.h"
+#include "util.h"
+#include "utf8.h"
+
+#ifdef HAVE_SYSV_COMPAT
+
+#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE)
+
+typedef enum RunlevelType {
+        RUNLEVEL_UP,
+        RUNLEVEL_DOWN,
+        RUNLEVEL_SYSINIT
+} RunlevelType;
+
+static const struct {
+        const char *path;
+        const char *target;
+        const RunlevelType type;
+} rcnd_table[] = {
+        /* Standard SysV runlevels for start-up */
+        { "rc1.d",  SPECIAL_RESCUE_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 },
+
+#ifdef TARGET_SUSE
+        /* SUSE style boot.d */
+        { "boot.d", SPECIAL_SYSINIT_TARGET,   RUNLEVEL_SYSINIT },
+#endif
+
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+        /* Debian style rcS.d */
+        { "rcS.d",  SPECIAL_SYSINIT_TARGET,   RUNLEVEL_SYSINIT },
+#endif
+
+        /* Standard SysV runlevels for shutdown */
+        { "rc0.d",  SPECIAL_POWEROFF_TARGET,  RUNLEVEL_DOWN },
+        { "rc6.d",  SPECIAL_REBOOT_TARGET,    RUNLEVEL_DOWN }
+
+        /* Note that the order here matters, as we read the
+           directories in this order, and we want to make sure that
+           sysv_start_priority is known when we first load the
+           unit. And that value we only know from S links. Hence
+           UP/SYSINIT must be read before DOWN */
+};
+
+#define RUNLEVELS_UP "12345"
+/* #define RUNLEVELS_DOWN "06" */
+#define RUNLEVELS_BOOT "bBsS"
+#endif
+
+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_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_FAILED] = UNIT_FAILED,
+        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
+};
+
+static void service_init(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        s->restart_usec = DEFAULT_RESTART_USEC;
+
+        s->watchdog_watch.type = WATCH_INVALID;
+
+        s->timer_watch.type = WATCH_INVALID;
+#ifdef HAVE_SYSV_COMPAT
+        s->sysv_start_priority = -1;
+        s->sysv_start_priority_from_rcnd = -1;
+#endif
+        s->socket_fd = -1;
+        s->guess_main_pid = true;
+
+        exec_context_init(&s->exec_context);
+
+        RATELIMIT_INIT(s->start_limit, 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_unwatch_pid_file(Service *s) {
+        if (!s->pid_file_pathspec)
+                return;
+
+        log_debug("Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
+        path_spec_unwatch(s->pid_file_pathspec, UNIT(s));
+        path_spec_done(s->pid_file_pathspec);
+        free(s->pid_file_pathspec);
+        s->pid_file_pathspec = NULL;
+}
+
+static int service_set_main_pid(Service *s, pid_t pid) {
+        pid_t ppid;
+
+        assert(s);
+
+        if (pid <= 1)
+                return -EINVAL;
+
+        if (pid == getpid())
+                return -EINVAL;
+
+        s->main_pid = pid;
+        s->main_pid_known = true;
+
+        if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
+                log_warning("%s: Supervising process %lu which is not our child. We'll most likely not notice when it exits.",
+                            UNIT(s)->id, (unsigned long) pid);
+
+                s->main_pid_alien = true;
+        } else
+                s->main_pid_alien = false;
+
+        exec_status_start(&s->main_exec_status, pid);
+
+        return 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_connection_unref(Service *s) {
+        assert(s);
+
+        if (!UNIT_DEREF(s->accept_socket))
+                return;
+
+        socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
+        unit_ref_unset(&s->accept_socket);
+}
+
+static void service_stop_watchdog(Service *s) {
+        assert(s);
+
+        unit_unwatch_timer(UNIT(s), &s->watchdog_watch);
+        s->watchdog_timestamp.realtime = 0;
+        s->watchdog_timestamp.monotonic = 0;
+}
+
+static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart);
+
+static void service_handle_watchdog(Service *s) {
+        usec_t offset;
+        int r;
+
+        assert(s);
+
+        if (s->watchdog_usec == 0)
+                return;
+
+        offset = now(CLOCK_MONOTONIC) - s->watchdog_timestamp.monotonic;
+        if (offset >= s->watchdog_usec) {
+                log_error("%s watchdog timeout!", UNIT(s)->id);
+                service_enter_dead(s, SERVICE_FAILURE_WATCHDOG, true);
+                return;
+        }
+
+        r = unit_watch_timer(UNIT(s), s->watchdog_usec - offset, &s->watchdog_watch);
+        if (r < 0)
+                log_warning("%s failed to install watchdog timer: %s", UNIT(s)->id, strerror(-r));
+}
+
+static void service_reset_watchdog(Service *s) {
+        assert(s);
+
+        dual_timestamp_get(&s->watchdog_timestamp);
+        service_handle_watchdog(s);
+}
+
+static void service_done(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        free(s->pid_file);
+        s->pid_file = NULL;
+
+#ifdef HAVE_SYSV_COMPAT
+        free(s->sysv_path);
+        s->sysv_path = NULL;
+
+        free(s->sysv_runlevels);
+        s->sysv_runlevels = NULL;
+#endif
+
+        free(s->status_text);
+        s->status_text = NULL;
+
+        exec_context_done(&s->exec_context);
+        exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
+        s->control_command = NULL;
+        s->main_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);
+        service_unwatch_pid_file(s);
+
+        if (s->bus_name)  {
+                unit_unwatch_bus_name(u, s->bus_name);
+                free(s->bus_name);
+                s->bus_name = NULL;
+        }
+
+        service_close_socket_fd(s);
+        service_connection_unref(s);
+
+        unit_ref_unset(&s->accept_socket);
+
+        service_stop_watchdog(s);
+
+        unit_unwatch_timer(u, &s->timer_watch);
+}
+
+#ifdef HAVE_SYSV_COMPAT
+static char *sysv_translate_name(const char *name) {
+        char *r;
+
+        if (!(r = new(char, strlen(name) + sizeof(".service"))))
+                return NULL;
+
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+        if (endswith(name, ".sh"))
+                /* Drop Debian-style .sh suffix */
+                strcpy(stpcpy(r, name) - 3, ".service");
+#endif
+#ifdef TARGET_SUSE
+        if (startswith(name, "boot."))
+                /* Drop SuSE-style boot. prefix */
+                strcpy(stpcpy(r, name + 5), ".service");
+#endif
+#ifdef TARGET_FRUGALWARE
+        if (startswith(name, "rc."))
+                /* Drop Frugalware-style rc. prefix */
+                strcpy(stpcpy(r, name + 3), ".service");
+#endif
+        else
+                /* Normal init scripts */
+                strcpy(stpcpy(r, name), ".service");
+
+        return r;
+}
+
+static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
+
+        /* We silently ignore the $ prefix here. According to the LSB
+         * spec it simply indicates whether something is a
+         * standardized name or a distribution-specific one. Since we
+         * just follow what already exists and do not introduce new
+         * uses or names we don't care who introduced a new name. */
+
+        static const char * const table[] = {
+                /* LSB defined facilities */
+                "local_fs",             SPECIAL_LOCAL_FS_TARGET,
+#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
+#else
+                /* Due to unfortunate name selection in Mandriva,
+                 * $network is provided by network-up which is ordered
+                 * after network which actually starts interfaces.
+                 * To break the loop, just ignore it */
+                "network",              SPECIAL_NETWORK_TARGET,
+#endif
+                "named",                SPECIAL_NSS_LOOKUP_TARGET,
+                "portmap",              SPECIAL_RPCBIND_TARGET,
+                "remote_fs",            SPECIAL_REMOTE_FS_TARGET,
+                "syslog",               SPECIAL_SYSLOG_TARGET,
+                "time",                 SPECIAL_TIME_SYNC_TARGET,
+
+                /* common extensions */
+                "mail-transfer-agent",  SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
+                "x-display-manager",    SPECIAL_DISPLAY_MANAGER_SERVICE,
+                "null",                 NULL,
+
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+                "mail-transport-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
+#endif
+
+#ifdef TARGET_FEDORA
+                "MTA",                  SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
+                "smtpdaemon",           SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
+                "httpd",                SPECIAL_HTTP_DAEMON_TARGET,
+#endif
+
+#ifdef TARGET_SUSE
+                "smtp",                 SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
+#endif
+        };
+
+        unsigned i;
+        char *r;
+        const char *n;
+
+        assert(name);
+        assert(_r);
+
+        n = *name == '$' ? name + 1 : name;
+
+        for (i = 0; i < ELEMENTSOF(table); i += 2) {
+
+                if (!streq(table[i], n))
+                        continue;
+
+                if (!table[i+1])
+                        return 0;
+
+                if (!(r = strdup(table[i+1])))
+                        return -ENOMEM;
+
+                goto finish;
+        }
+
+        /* If we don't know this name, fallback heuristics to figure
+         * out whether something is a target or a service alias. */
+
+        if (*name == '$') {
+                if (!unit_prefix_is_valid(n))
+                        return -EINVAL;
+
+                /* Facilities starting with $ are most likely targets */
+                r = unit_name_build(n, NULL, ".target");
+        } else if (filename && streq(name, filename))
+                /* Names equaling the file name of the services are redundant */
+                return 0;
+        else
+                /* Everything else we assume to be normal service names */
+                r = sysv_translate_name(n);
+
+        if (!r)
+                return -ENOMEM;
+
+finish:
+        *_r = r;
+
+        return 1;
+}
+
+static int sysv_fix_order(Service *s) {
+        Unit *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_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) {
+                Service *t;
+                UnitDependency d;
+                bool special_s, special_t;
+
+                t = SERVICE(other);
+
+                if (s == t)
+                        continue;
+
+                if (UNIT(t)->load_state != UNIT_LOADED)
+                        continue;
+
+                if (t->sysv_start_priority < 0)
+                        continue;
+
+                /* If both units have modern headers we don't care
+                 * about the priorities */
+                if ((UNIT(s)->fragment_path || s->sysv_has_lsb) &&
+                    (UNIT(t)->fragment_path || t->sysv_has_lsb))
+                        continue;
+
+                special_s = s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels);
+                special_t = t->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, t->sysv_runlevels);
+
+                if (special_t && !special_s)
+                        d = UNIT_AFTER;
+                else if (special_s && !special_t)
+                        d = UNIT_BEFORE;
+                else 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;
+        char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description;
+        struct stat st;
+
+        assert(s);
+        assert(path);
+
+        u = UNIT(s);
+
+        if (!(f = fopen(path, "re"))) {
+                r = errno == ENOENT ? 0 : -errno;
+                goto finish;
+        }
+
+        zero(st);
+        if (fstat(fileno(f), &st) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        free(s->sysv_path);
+        if (!(s->sysv_path = strdup(path))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        s->sysv_mtime = timespec_load(&st.st_mtim);
+
+        if (null_or_empty(&st)) {
+                u->load_state = UNIT_MASKED;
+                r = 0;
+                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_no_case(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
+                                        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_no_case(t, "description:")) {
+
+                                size_t k = strlen(t);
+                                char *d;
+                                const char *j;
+
+                                if (t[k-1] == '\\') {
+                                        state = DESCRIPTION;
+                                        t[k-1] = 0;
+                                }
+
+                                if ((j = strstrip(t+12)) && *j) {
+                                        if (!(d = strdup(j))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+                                } else
+                                        d = NULL;
+
+                                free(chkconfig_description);
+                                chkconfig_description = d;
+
+                        } else if (startswith_no_case(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 *j;
+
+                        if (t[k-1] == '\\')
+                                t[k-1] = 0;
+                        else
+                                state = NORMAL;
+
+                        if ((j = strstrip(t)) && *j) {
+                                char *d = NULL;
+
+                                if (chkconfig_description)
+                                        d = join(chkconfig_description, " ", j, NULL);
+                                else
+                                        d = strdup(j);
+
+                                if (!d) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                free(chkconfig_description);
+                                chkconfig_description = d;
+                        }
+
+                } else if (state == LSB || state == LSB_DESCRIPTION) {
+
+                        if (startswith_no_case(t, "Provides:")) {
+                                char *i, *w;
+                                size_t z;
+
+                                state = LSB;
+
+                                FOREACH_WORD_QUOTED(w, z, t+9, i) {
+                                        char *n, *m;
+
+                                        if (!(n = strndup(w, z))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        r = sysv_translate_facility(n, file_name_from_path(path), &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
+                                                /* NB: SysV targets
+                                                 * which are provided
+                                                 * by a service are
+                                                 * pulled in by the
+                                                 * services, as an
+                                                 * indication that the
+                                                 * generic service is
+                                                 * now available. This
+                                                 * is strictly
+                                                 * one-way. The
+                                                 * targets do NOT pull
+                                                 * in the SysV
+                                                 * services! */
+                                                r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true);
+
+                                        if (r < 0)
+                                                log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r));
+
+                                        free(m);
+                                }
+
+                        } else if (startswith_no_case(t, "Required-Start:") ||
+                                   startswith_no_case(t, "Should-Start:") ||
+                                   startswith_no_case(t, "X-Start-Before:") ||
+                                   startswith_no_case(t, "X-Start-After:")) {
+                                char *i, *w;
+                                size_t z;
+
+                                state = LSB;
+
+                                FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) {
+                                        char *n, *m;
+
+                                        if (!(n = strndup(w, z))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+
+                                        r = sysv_translate_facility(n, file_name_from_path(path), &m);
+
+                                        if (r < 0) {
+                                                log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
+                                                free(n);
+                                                continue;
+                                        }
+
+                                        free(n);
+
+                                        if (r == 0)
+                                                continue;
+
+                                        r = unit_add_dependency_by_name(u, startswith_no_case(t, "X-Start-Before:") ? UNIT_BEFORE : UNIT_AFTER, m, NULL, true);
+
+                                        if (r < 0)
+                                                log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", path, line, m, strerror(-r));
+
+                                        free(m);
+                                }
+                        } else if (startswith_no_case(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_no_case(t, "Description:")) {
+                                char *d, *j;
+
+                                state = LSB_DESCRIPTION;
+
+                                if ((j = strstrip(t+12)) && *j) {
+                                        if (!(d = strdup(j))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+                                } else
+                                        d = NULL;
+
+                                free(long_description);
+                                long_description = d;
+
+                        } else if (startswith_no_case(t, "Short-Description:")) {
+                                char *d, *j;
+
+                                state = LSB;
+
+                                if ((j = strstrip(t+18)) && *j) {
+                                        if (!(d = strdup(j))) {
+                                                r = -ENOMEM;
+                                                goto finish;
+                                        }
+                                } else
+                                        d = NULL;
+
+                                free(short_description);
+                                short_description = d;
+
+                        } else if (state == LSB_DESCRIPTION) {
+
+                                if (startswith(l, "#\t") || startswith(l, "#  ")) {
+                                        char *j;
+
+                                        if ((j = strstrip(t)) && *j) {
+                                                char *d = NULL;
+
+                                                if (long_description)
+                                                        d = join(long_description, " ", t, NULL);
+                                                else
+                                                        d = strdup(j);
+
+                                                if (!d) {
+                                                        r = -ENOMEM;
+                                                        goto finish;
+                                                }
+
+                                                free(long_description);
+                                                long_description = d;
+                                        }
+
+                                } else
+                                        state = LSB;
+                        }
+                }
+        }
+
+        if ((r = sysv_exec_commands(s)) < 0)
+                goto finish;
+        if (s->sysv_runlevels &&
+            chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) &&
+            chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
+                /* Service has both boot and "up" runlevels
+                   configured.  Kill the "up" ones. */
+                delete_chars(s->sysv_runlevels, RUNLEVELS_UP);
+        }
+
+        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. */
+
+                UNIT(s)->default_dependencies = false;
+
+                /* Don't timeout special services during boot (like fsck) */
+                s->timeout_usec = 0;
+        } else
+                s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC;
+
+        /* Special setting for all SysV services */
+        s->type = SERVICE_FORKING;
+        s->remain_after_exit = !s->pid_file;
+        s->guess_main_pid = false;
+        s->restart = SERVICE_RESTART_NO;
+        s->exec_context.ignore_sigpipe = false;
+
+        if (UNIT(s)->manager->sysv_console)
+                s->exec_context.std_output = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+
+        s->exec_context.kill_mode = KILL_PROCESS;
+
+        /* We use the long description only if
+         * no short description is set. */
+
+        if (short_description)
+                description = short_description;
+        else if (chkconfig_description)
+                description = chkconfig_description;
+        else if (long_description)
+                description = long_description;
+        else
+                description = NULL;
+
+        if (description) {
+                char *d;
+
+                if (!(d = strappend(s->sysv_has_lsb ? "LSB: " : "SYSV: ", description))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                u->description = d;
+        }
+
+        /* The priority that has been set in /etc/rcN.d/ hierarchies
+         * takes precedence over what is stored as default in the LSB
+         * header */
+        if (s->sysv_start_priority_from_rcnd >= 0)
+                s->sysv_start_priority = s->sysv_start_priority_from_rcnd;
+
+        u->load_state = UNIT_LOADED;
+        r = 0;
+
+finish:
+
+        if (f)
+                fclose(f);
+
+        free(short_description);
+        free(long_description);
+        free(chkconfig_description);
+
+        return r;
+}
+
+static int service_load_sysv_name(Service *s, const char *name) {
+        char **p;
+
+        assert(s);
+        assert(name);
+
+        /* For SysV services we strip the boot.*, rc.* and *.sh
+         * prefixes/suffixes. */
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+        if (endswith(name, ".sh.service"))
+                return -ENOENT;
+#endif
+
+#ifdef TARGET_SUSE
+        if (startswith(name, "boot."))
+                return -ENOENT;
+#endif
+
+#ifdef TARGET_FRUGALWARE
+        if (startswith(name, "rc."))
+                return -ENOENT;
+#endif
+
+        STRV_FOREACH(p, UNIT(s)->manager->lookup_paths.sysvinit_path) {
+                char *path;
+                int r;
+
+                path = join(*p, "/", name, NULL);
+                if (!path)
+                        return -ENOMEM;
+
+                assert(endswith(path, ".service"));
+                path[strlen(path)-8] = 0;
+
+                r = service_load_sysv_path(s, path);
+
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
+                        /* Try Debian style *.sh source'able init scripts */
+                        strcat(path, ".sh");
+                        r = service_load_sysv_path(s, path);
+                }
+#endif
+                free(path);
+
+#ifdef TARGET_SUSE
+                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
+                        /* Try SUSE style boot.* init scripts */
+
+                        path = join(*p, "/boot.", name, NULL);
+                        if (!path)
+                                return -ENOMEM;
+
+                        /* Drop .service suffix */
+                        path[strlen(path)-8] = 0;
+                        r = service_load_sysv_path(s, path);
+                        free(path);
+                }
+#endif
+
+#ifdef TARGET_FRUGALWARE
+                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
+                        /* Try Frugalware style rc.* init scripts */
+
+                        path = join(*p, "/rc.", name, NULL);
+                        if (!path)
+                                return -ENOMEM;
+
+                        /* Drop .service suffix */
+                        path[strlen(path)-8] = 0;
+                        r = service_load_sysv_path(s, path);
+                        free(path);
+                }
+#endif
+
+                if (r < 0)
+                        return r;
+
+                if ((UNIT(s)->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)->manager->lookup_paths.sysvinit_path))
+                return 0;
+
+        if ((t = UNIT(s)->id))
+                if ((r = service_load_sysv_name(s, t)) < 0)
+                        return r;
+
+        if (UNIT(s)->load_state == UNIT_STUB)
+                SET_FOREACH(t, UNIT(s)->names, i) {
+                        if (t == UNIT(s)->id)
+                                continue;
+
+                        if ((r = service_load_sysv_name(s, t)) < 0)
+                                return r;
+
+                        if (UNIT(s)->load_state != UNIT_STUB)
+                                break;
+                }
+
+        return 0;
+}
+#endif
+
+static int fsck_fix_order(Service *s) {
+        Unit *other;
+        int r;
+
+        assert(s);
+
+        if (s->fsck_passno <= 0)
+                return 0;
+
+        /* For each pair of services where both have an fsck priority
+         * we order things based on it. */
+
+        LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) {
+                Service *t;
+                UnitDependency d;
+
+                t = SERVICE(other);
+
+                if (s == t)
+                        continue;
+
+                if (UNIT(t)->load_state != UNIT_LOADED)
+                        continue;
+
+                if (t->fsck_passno <= 0)
+                        continue;
+
+                if (t->fsck_passno < s->fsck_passno)
+                        d = UNIT_AFTER;
+                else if (t->fsck_passno > s->fsck_passno)
+                        d = UNIT_BEFORE;
+                else
+                        continue;
+
+                if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int service_verify(Service *s) {
+        assert(s);
+
+        if (UNIT(s)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!s->exec_command[SERVICE_EXEC_START]) {
+                log_error("%s lacks ExecStart setting. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        if (s->type != SERVICE_ONESHOT &&
+            s->exec_command[SERVICE_EXEC_START]->command_next) {
+                log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        if (s->type == SERVICE_ONESHOT &&
+            s->exec_command[SERVICE_EXEC_RELOAD]) {
+                log_error("%s has an ExecReload setting, which is not allowed for Type=oneshot services. Refusing.", UNIT(s)->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)->id);
+                return -EINVAL;
+        }
+
+        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int service_add_default_dependencies(Service *s) {
+        int r;
+
+        assert(s);
+
+        /* Add a number of automatic dependencies useful for the
+         * majority of services. */
+
+        /* First, pull in base system */
+        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
+                        return r;
+
+        } else if (UNIT(s)->manager->running_as == MANAGER_USER) {
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
+                        return r;
+        }
+
+        /* Second, activate normal shutdown */
+        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
+static void service_fix_output(Service *s) {
+        assert(s);
+
+        /* If nothing has been explicitly configured, patch default
+         * output in. If input is socket/tty we avoid this however,
+         * since in that case we want output to default to the same
+         * place as we read input from. */
+
+        if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
+            s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
+            s->exec_context.std_input == EXEC_INPUT_NULL)
+                s->exec_context.std_error = UNIT(s)->manager->default_std_error;
+
+        if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
+            s->exec_context.std_input == EXEC_INPUT_NULL)
+                s->exec_context.std_output = UNIT(s)->manager->default_std_output;
+}
+
+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;
+
+#ifdef HAVE_SYSV_COMPAT
+        /* Load a classic init script as a fallback, if we couldn't find anything */
+        if (u->load_state == UNIT_STUB)
+                if ((r = service_load_sysv(s)) < 0)
+                        return r;
+#endif
+
+        /* Still nothing found? Then let's give up */
+        if (u->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->load_state == UNIT_LOADED) {
+                service_fix_output(s);
+
+                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
+                        return r;
+
+                if ((r = unit_add_default_cgroups(u)) < 0)
+                        return r;
+
+#ifdef HAVE_SYSV_COMPAT
+                if ((r = sysv_fix_order(s)) < 0)
+                        return r;
+#endif
+
+                if ((r = fsck_fix_order(s)) < 0)
+                        return r;
+
+                if (s->bus_name)
+                        if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
+                                return r;
+
+                if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
+                        s->notify_access = NOTIFY_MAIN;
+
+                if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
+                        s->notify_access = NOTIFY_MAIN;
+
+                if (s->type == SERVICE_DBUS || s->bus_name)
+                        if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
+                                return r;
+
+                if (UNIT(s)->default_dependencies)
+                        if ((r = service_add_default_dependencies(s)) < 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"
+                "%sResult: %s\n"
+                "%sReload Result: %s\n"
+                "%sPermissionsStartOnly: %s\n"
+                "%sRootDirectoryStartOnly: %s\n"
+                "%sRemainAfterExit: %s\n"
+                "%sGuessMainPID: %s\n"
+                "%sType: %s\n"
+                "%sRestart: %s\n"
+                "%sNotifyAccess: %s\n",
+                prefix, service_state_to_string(s->state),
+                prefix, service_result_to_string(s->result),
+                prefix, service_result_to_string(s->reload_result),
+                prefix, yes_no(s->permissions_start_only),
+                prefix, yes_no(s->root_directory_start_only),
+                prefix, yes_no(s->remain_after_exit),
+                prefix, yes_no(s->guess_main_pid),
+                prefix, service_type_to_string(s->type),
+                prefix, service_restart_to_string(s->restart),
+                prefix, notify_access_to_string(s->notify_access));
+
+        if (s->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %lu\n",
+                        prefix, (unsigned long) s->control_pid);
+
+        if (s->main_pid > 0)
+                fprintf(f,
+                        "%sMain PID: %lu\n"
+                        "%sMain PID Known: %s\n"
+                        "%sMain PID Alien: %s\n",
+                        prefix, (unsigned long) s->main_pid,
+                        prefix, yes_no(s->main_pid_known),
+                        prefix, yes_no(s->main_pid_alien));
+
+        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);
+        }
+
+#ifdef HAVE_SYSV_COMPAT
+        if (s->sysv_path)
+                fprintf(f,
+                        "%sSysV Init Script Path: %s\n"
+                        "%sSysV Init Script has LSB Header: %s\n"
+                        "%sSysVEnabled: %s\n",
+                        prefix, s->sysv_path,
+                        prefix, yes_no(s->sysv_has_lsb),
+                        prefix, yes_no(s->sysv_enabled));
+
+        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);
+#endif
+
+        if (s->fsck_passno > 0)
+                fprintf(f,
+                        "%sFsckPassNo: %i\n",
+                        prefix, s->fsck_passno);
+
+        if (s->status_text)
+                fprintf(f, "%sStatus Text: %s\n",
+                        prefix, s->status_text);
+
+        free(p2);
+}
+
+static int service_load_pid_file(Service *s, bool may_warn) {
+        char *k;
+        int r;
+        pid_t pid;
+
+        assert(s);
+
+        if (!s->pid_file)
+                return -ENOENT;
+
+        if ((r = read_one_line_file(s->pid_file, &k)) < 0) {
+                if (may_warn)
+                        log_info("PID file %s not readable (yet?) after %s.",
+                                 s->pid_file, service_state_to_string(s->state));
+                return r;
+        }
+
+        r = parse_pid(k, &pid);
+        free(k);
+
+        if (r < 0)
+                return r;
+
+        if (kill(pid, 0) < 0 && errno != EPERM) {
+                if (may_warn)
+                        log_info("PID %lu read from file %s does not exist.",
+                                 (unsigned long) pid, s->pid_file);
+                return -ESRCH;
+        }
+
+        if (s->main_pid_known) {
+                if (pid == s->main_pid)
+                        return 0;
+
+                log_debug("Main PID changing: %lu -> %lu",
+                          (unsigned long) s->main_pid, (unsigned long) pid);
+                service_unwatch_main_pid(s);
+                s->main_pid_known = false;
+        } else
+                log_debug("Main PID loaded: %lu", (unsigned long) pid);
+
+        if ((r = service_set_main_pid(s, pid)) < 0)
+                return r;
+
+        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
+                /* FIXME: we need to do something here */
+                return r;
+
+        return 0;
+}
+
+static int service_search_main_pid(Service *s) {
+        pid_t pid;
+        int r;
+
+        assert(s);
+
+        /* If we know it anyway, don't ever fallback to unreliable
+         * heuristics */
+        if (s->main_pid_known)
+                return 0;
+
+        if (!s->guess_main_pid)
+                return 0;
+
+        assert(s->main_pid <= 0);
+
+        if ((pid = cgroup_bonding_search_main_pid_list(UNIT(s)->cgroup_bondings)) <= 0)
+                return -ENOENT;
+
+        log_debug("Main PID guessed: %lu", (unsigned long) pid);
+        if ((r = service_set_main_pid(s, pid)) < 0)
+                return r;
+
+        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
+                /* FIXME: we need to do something here */
+                return r;
+
+        return 0;
+}
+
+static void service_notify_sockets_dead(Service *s, bool failed_permanent) {
+        Iterator i;
+        Unit *u;
+
+        assert(s);
+
+        /* Notifies all our sockets when we die */
+
+        if (s->socket_fd >= 0)
+                return;
+
+        SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i)
+                if (u->type == UNIT_SOCKET)
+                        socket_notify_service_dead(SOCKET(u), failed_permanent);
+
+        return;
+}
+
+static void service_set_state(Service *s, ServiceState state) {
+        ServiceState old_state;
+        assert(s);
+
+        old_state = s->state;
+        s->state = state;
+
+        service_unwatch_pid_file(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 &&
+            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);
+                s->main_command = NULL;
+        }
+
+        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_FAILED ||
+            state == SERVICE_AUTO_RESTART)
+                service_notify_sockets_dead(s, false);
+
+        if (state != SERVICE_START_PRE &&
+            state != SERVICE_START &&
+            state != SERVICE_START_POST &&
+            state != SERVICE_RUNNING &&
+            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_DEAD && UNIT(s)->job)) {
+                service_close_socket_fd(s);
+                service_connection_unref(s);
+        }
+
+        if (state == SERVICE_STOP)
+                service_stop_watchdog(s);
+
+        /* For the inactive states unit_notify() will trim the cgroup,
+         * but for exit we have to do that ourselves... */
+        if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
+                cgroup_bonding_trim_list(UNIT(s)->cgroup_bondings, true);
+
+        if (old_state != state)
+                log_debug("%s changed %s -> %s", UNIT(s)->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], s->reload_result == SERVICE_SUCCESS);
+        s->reload_result = SERVICE_SUCCESS;
+}
+
+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->type == SERVICE_ONESHOT ||
+                      s->type == SERVICE_NOTIFY)) ||
+                    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;
+
+                if (s->deserialized_state == SERVICE_START_POST ||
+                    s->deserialized_state == SERVICE_RUNNING)
+                        service_handle_watchdog(s);
+
+                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;
+        Unit *u;
+
+        assert(s);
+        assert(fds);
+        assert(n_fds);
+
+        if (s->socket_fd >= 0)
+                return 0;
+
+        SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+                int *cfds;
+                unsigned cn_fds;
+                Socket *sock;
+
+                if (u->type != UNIT_SOCKET)
+                        continue;
+
+                sock = SOCKET(u);
+
+                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 * sizeof(int));
+                        memcpy(t+rn_fds, cfds, cn_fds * sizeof(int));
+                        free(rfds);
+                        free(cfds);
+
+                        rfds = t;
+                        rn_fds = rn_fds+cn_fds;
+                }
+        }
+
+        *fds = rfds;
+        *n_fds = rn_fds;
+
+        return 0;
+
+fail:
+        free(rfds);
+
+        return r;
+}
+
+static int service_spawn(
+                Service *s,
+                ExecCommand *c,
+                bool timeout,
+                bool pass_fds,
+                bool apply_permissions,
+                bool apply_chroot,
+                bool apply_tty_stdin,
+                bool set_notify_socket,
+                pid_t *_pid) {
+
+        pid_t pid;
+        int r;
+        int *fds = NULL, *fdsbuf = NULL;
+        unsigned n_fds = 0, n_env = 0;
+        char **argv = NULL, **final_env = NULL, **our_env = NULL;
+
+        assert(s);
+        assert(c);
+        assert(_pid);
+
+        if (pass_fds ||
+            s->exec_context.std_input == EXEC_INPUT_SOCKET ||
+            s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
+            s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
+
+                if (s->socket_fd >= 0) {
+                        fds = &s->socket_fd;
+                        n_fds = 1;
+                } else {
+                        if ((r = service_collect_fds(s, &fdsbuf, &n_fds)) < 0)
+                                goto fail;
+
+                        fds = fdsbuf;
+                }
+        }
+
+        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;
+        }
+
+        if (!(our_env = new0(char*, 4))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (set_notify_socket)
+                if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+        if (s->main_pid > 0)
+                if (asprintf(our_env + n_env++, "MAINPID=%lu", (unsigned long) s->main_pid) < 0) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+        if (s->watchdog_usec > 0)
+                if (asprintf(our_env + n_env++, "WATCHDOG_USEC=%llu", (unsigned long long) s->watchdog_usec) < 0) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+        if (!(final_env = strv_env_merge(2,
+                                         UNIT(s)->manager->environment,
+                                         our_env,
+                                         NULL))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = exec_spawn(c,
+                       argv,
+                       &s->exec_context,
+                       fds, n_fds,
+                       final_env,
+                       apply_permissions,
+                       apply_chroot,
+                       apply_tty_stdin,
+                       UNIT(s)->manager->confirm_spawn,
+                       UNIT(s)->cgroup_bondings,
+                       UNIT(s)->cgroup_attributes,
+                       &pid);
+
+        if (r < 0)
+                goto fail;
+
+
+        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
+                /* FIXME: we need to do something here */
+                goto fail;
+
+        free(fdsbuf);
+        strv_free(argv);
+        strv_free(our_env);
+        strv_free(final_env);
+
+        *_pid = pid;
+
+        return 0;
+
+fail:
+        free(fdsbuf);
+        strv_free(argv);
+        strv_free(our_env);
+        strv_free(final_env);
+
+        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) {
+
+                /* If it's an alien child let's check if it is still
+                 * alive ... */
+                if (s->main_pid_alien)
+                        return kill(s->main_pid, 0) >= 0 || errno != ESRCH;
+
+                /* .. otherwise assume we'll get a SIGCHLD for it,
+                 * which we really should wait for to collect exit
+                 * status and code */
+                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 ((r = cgroup_bonding_is_empty_list(UNIT(s)->cgroup_bondings)) < 0)
+                return r;
+
+        return !r;
+}
+
+static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
+        int r;
+        assert(s);
+
+        if (f != SERVICE_SUCCESS)
+                s->result = f;
+
+        if (allow_restart &&
+            !s->forbid_restart &&
+            (s->restart == SERVICE_RESTART_ALWAYS ||
+             (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
+             (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
+             (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL ||
+                                                         s->result == SERVICE_FAILURE_CORE_DUMP)))) {
+
+                r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
+                if (r < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_AUTO_RESTART);
+        } else
+                service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
+
+        s->forbid_restart = false;
+
+        return;
+
+fail:
+        log_warning("%s failed to run install restart timer: %s", UNIT(s)->id, strerror(-r));
+        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
+}
+
+static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
+
+static void service_enter_stop_post(Service *s, ServiceResult f) {
+        int r;
+        assert(s);
+
+        if (f != SERVICE_SUCCESS)
+                s->result = f;
+
+        service_unwatch_control_pid(s);
+
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
+                s->control_command_id = SERVICE_EXEC_STOP_POST;
+
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       true,
+                                       false,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+
+                service_set_state(s, SERVICE_STOP_POST);
+        } else
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
+        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+}
+
+static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
+        int r;
+        Set *pid_set = NULL;
+        bool wait_for_exit = false;
+
+        assert(s);
+
+        if (f != SERVICE_SUCCESS)
+                s->result = f;
+
+        if (s->exec_context.kill_mode != KILL_NONE) {
+                int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
+
+                if (s->main_pid > 0) {
+                        if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH)
+                                log_warning("Failed to kill main process %li: %m", (long) s->main_pid);
+                        else
+                                wait_for_exit = !s->main_pid_alien;
+                }
+
+                if (s->control_pid > 0) {
+                        if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
+                                log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
+                        else
+                                wait_for_exit = true;
+                }
+
+                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+
+                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        /* Exclude the main/control pids from being killed via the cgroup */
+                        if (s->main_pid > 0)
+                                if ((r = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0)
+                                        goto fail;
+
+                        if (s->control_pid > 0)
+                                if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
+                                        goto fail;
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                        log_warning("Failed to kill control group: %s", strerror(-r));
+                        } else if (r > 0)
+                                wait_for_exit = true;
+
+                        set_free(pid_set);
+                        pid_set = NULL;
+                }
+        }
+
+        if (wait_for_exit) {
+                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, SERVICE_SUCCESS);
+        else
+                service_enter_dead(s, SERVICE_SUCCESS, true);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
+
+        if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
+                service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
+        else
+                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+
+        if (pid_set)
+                set_free(pid_set);
+}
+
+static void service_enter_stop(Service *s, ServiceResult f) {
+        int r;
+
+        assert(s);
+
+        if (f != SERVICE_SUCCESS)
+                s->result = f;
+
+        service_unwatch_control_pid(s);
+
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
+                s->control_command_id = SERVICE_EXEC_STOP;
+
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       false,
+                                       false,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_STOP);
+        } else
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r));
+        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+}
+
+static void service_enter_running(Service *s, ServiceResult f) {
+        int main_pid_ok, cgroup_ok;
+        assert(s);
+
+        if (f != SERVICE_SUCCESS)
+                s->result = f;
+
+        main_pid_ok = main_pid_good(s);
+        cgroup_ok = cgroup_good(s);
+
+        if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) &&
+            (s->bus_name_good || s->type != SERVICE_DBUS))
+                service_set_state(s, SERVICE_RUNNING);
+        else if (s->remain_after_exit)
+                service_set_state(s, SERVICE_EXITED);
+        else
+                service_enter_stop(s, SERVICE_SUCCESS);
+}
+
+static void service_enter_start_post(Service *s) {
+        int r;
+        assert(s);
+
+        service_unwatch_control_pid(s);
+
+        if (s->watchdog_usec > 0)
+                service_reset_watchdog(s);
+
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
+                s->control_command_id = SERVICE_EXEC_START_POST;
+
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       false,
+                                       false,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_START_POST);
+        } else
+                service_enter_running(s, SERVICE_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
+        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+}
+
+static void service_enter_start(Service *s) {
+        pid_t pid;
+        int r;
+        ExecCommand *c;
+
+        assert(s);
+
+        assert(s->exec_command[SERVICE_EXEC_START]);
+        assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
+
+        if (s->type == SERVICE_FORKING)
+                service_unwatch_control_pid(s);
+        else
+                service_unwatch_main_pid(s);
+
+        /* We want to ensure that nobody leaks processes from
+         * START_PRE here, so let's go on a killing spree, People
+         * should not spawn long running processes from START_PRE. */
+        cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
+
+        if (s->type == SERVICE_FORKING) {
+                s->control_command_id = SERVICE_EXEC_START;
+                c = s->control_command = s->exec_command[SERVICE_EXEC_START];
+
+                s->main_command = NULL;
+        } else {
+                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+                s->control_command = NULL;
+
+                c = s->main_command = s->exec_command[SERVICE_EXEC_START];
+        }
+
+        if ((r = service_spawn(s,
+                               c,
+                               s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
+                               true,
+                               true,
+                               true,
+                               true,
+                               s->notify_access != NOTIFY_NONE,
+                               &pid)) < 0)
+                goto fail;
+
+        if (s->type == SERVICE_SIMPLE) {
+                /* For simple services we immediately start
+                 * the START_POST binaries. */
+
+                service_set_main_pid(s, pid);
+                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;
+                service_set_state(s, SERVICE_START);
+
+        } else if (s->type == SERVICE_ONESHOT ||
+                   s->type == SERVICE_DBUS ||
+                   s->type == SERVICE_NOTIFY) {
+
+                /* For oneshot 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. Notify services are similar. */
+
+                service_set_main_pid(s, pid);
+                service_set_state(s, SERVICE_START);
+        } else
+                assert_not_reached("Unknown service type");
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r));
+        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+}
+
+static void service_enter_start_pre(Service *s) {
+        int r;
+
+        assert(s);
+
+        service_unwatch_control_pid(s);
+
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
+
+                /* Before we start anything, let's clear up what might
+                 * be left from previous runs. */
+                cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
+
+                s->control_command_id = SERVICE_EXEC_START_PRE;
+
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       true,
+                                       false,
+                                       &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' task: %s", UNIT(s)->id, strerror(-r));
+        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+}
+
+static void service_enter_restart(Service *s) {
+        int r;
+        DBusError error;
+
+        assert(s);
+        dbus_error_init(&error);
+
+        if (UNIT(s)->job) {
+                log_info("Job pending for unit, delaying automatic restart.");
+
+                if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0)
+                        goto fail;
+        }
+
+        /* Any units that are bound to this service must also be
+         * restarted. We use JOB_RESTART (instead of the more obvious
+         * JOB_START) here so that those dependency jobs will be added
+         * as well. */
+        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, false, &error, NULL);
+        if (r < 0)
+                goto fail;
+
+        log_debug("%s scheduled restart job.", UNIT(s)->id);
+        return;
+
+fail:
+        log_warning("%s failed to schedule restart job: %s", UNIT(s)->id, bus_error(&error, -r));
+        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
+
+        dbus_error_free(&error);
+}
+
+static void service_enter_reload(Service *s) {
+        int r;
+
+        assert(s);
+
+        service_unwatch_control_pid(s);
+
+        if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
+                s->control_command_id = SERVICE_EXEC_RELOAD;
+
+                if ((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       false,
+                                       false,
+                                       &s->control_pid)) < 0)
+                        goto fail;
+
+                service_set_state(s, SERVICE_RELOAD);
+        } else
+                service_enter_running(s, SERVICE_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'reload' task: %s", UNIT(s)->id, strerror(-r));
+        s->reload_result = SERVICE_FAILURE_RESOURCES;
+        service_enter_running(s, SERVICE_SUCCESS);
+}
+
+static void service_run_next_control(Service *s) {
+        int r;
+
+        assert(s);
+        assert(s->control_command);
+        assert(s->control_command->command_next);
+
+        assert(s->control_command_id != SERVICE_EXEC_START);
+
+        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_command_id == SERVICE_EXEC_START_PRE ||
+                               s->control_command_id == SERVICE_EXEC_STOP_POST,
+                               false,
+                               &s->control_pid)) < 0)
+                goto fail;
+
+        return;
+
+fail:
+        log_warning("%s failed to run next control task: %s", UNIT(s)->id, strerror(-r));
+
+        if (s->state == SERVICE_START_PRE)
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+        else if (s->state == SERVICE_STOP)
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+        else if (s->state == SERVICE_STOP_POST)
+                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+        else if (s->state == SERVICE_RELOAD) {
+                s->reload_result = SERVICE_FAILURE_RESOURCES;
+                service_enter_running(s, SERVICE_SUCCESS);
+        } else
+                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+}
+
+static void service_run_next_main(Service *s) {
+        pid_t pid;
+        int r;
+
+        assert(s);
+        assert(s->main_command);
+        assert(s->main_command->command_next);
+        assert(s->type == SERVICE_ONESHOT);
+
+        s->main_command = s->main_command->command_next;
+        service_unwatch_main_pid(s);
+
+        if ((r = service_spawn(s,
+                               s->main_command,
+                               false,
+                               true,
+                               true,
+                               true,
+                               true,
+                               s->notify_access != NOTIFY_NONE,
+                               &pid)) < 0)
+                goto fail;
+
+        service_set_main_pid(s, pid);
+
+        return;
+
+fail:
+        log_warning("%s failed to run next main task: %s", UNIT(s)->id, strerror(-r));
+        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+}
+
+static int service_start_limit_test(Service *s) {
+        assert(s);
+
+        if (ratelimit_test(&s->start_limit))
+                return 0;
+
+        switch (s->start_limit_action) {
+
+        case SERVICE_START_LIMIT_NONE:
+                log_warning("%s start request repeated too quickly, refusing to start.", UNIT(s)->id);
+                break;
+
+        case SERVICE_START_LIMIT_REBOOT: {
+                DBusError error;
+                int r;
+
+                dbus_error_init(&error);
+
+                log_warning("%s start request repeated too quickly, rebooting.", UNIT(s)->id);
+
+                r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
+                if (r < 0) {
+                        log_error("Failed to reboot: %s.", bus_error(&error, r));
+                        dbus_error_free(&error);
+                }
+
+                break;
+        }
+
+        case SERVICE_START_LIMIT_REBOOT_FORCE:
+                log_warning("%s start request repeated too quickly, forcibly rebooting.", UNIT(s)->id);
+                UNIT(s)->manager->exit_code = MANAGER_REBOOT;
+                break;
+
+        case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
+                log_warning("%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
+                reboot(RB_AUTOBOOT);
+                break;
+
+        default:
+                log_error("start limit action=%i", s->start_limit_action);
+                assert_not_reached("Unknown StartLimitAction.");
+        }
+
+        return -ECANCELED;
+}
+
+static int service_start(Unit *u) {
+        Service *s = SERVICE(u);
+        int r;
+
+        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_FAILED || s->state == SERVICE_AUTO_RESTART);
+
+        /* Make sure we don't enter a busy loop of some kind. */
+        r = service_start_limit_test(s);
+        if (r < 0) {
+                service_notify_sockets_dead(s, true);
+                return r;
+        }
+
+        s->result = SERVICE_SUCCESS;
+        s->reload_result = SERVICE_SUCCESS;
+        s->main_pid_known = false;
+        s->main_pid_alien = false;
+        s->forbid_restart = false;
+
+        service_enter_start_pre(s);
+        return 0;
+}
+
+static int service_stop(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        /* This is a user request, so don't do restarts on this
+         * shutdown. */
+        s->forbid_restart = true;
+
+        /* 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;
+
+        /* Don't allow a restart */
+        if (s->state == SERVICE_AUTO_RESTART) {
+                service_set_state(s, SERVICE_DEAD);
+                return 0;
+        }
+
+        /* If there's already something running we go directly into
+         * kill mode. */
+        if (s->state == SERVICE_START_PRE ||
+            s->state == SERVICE_START ||
+            s->state == SERVICE_START_POST ||
+            s->state == SERVICE_RELOAD) {
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
+                return 0;
+        }
+
+        assert(s->state == SERVICE_RUNNING ||
+               s->state == SERVICE_EXITED);
+
+        service_enter_stop(s, SERVICE_SUCCESS);
+        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, "result", service_result_to_string(s->result));
+        unit_serialize_item(u, f, "reload-result", service_result_to_string(s->reload_result));
+
+        if (s->control_pid > 0)
+                unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid);
+
+        if (s->main_pid_known && s->main_pid > 0)
+                unit_serialize_item_format(u, f, "main-pid", "%lu", (unsigned long) s->main_pid);
+
+        unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
+
+        if (s->status_text)
+                unit_serialize_item(u, f, "status-text", s->status_text);
+
+        /* FIXME: 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);
+        }
+
+        if (s->main_exec_status.pid > 0) {
+                unit_serialize_item_format(u, f, "main-exec-status-pid", "%lu", (unsigned long) s->main_exec_status.pid);
+                dual_timestamp_serialize(f, "main-exec-status-start", &s->main_exec_status.start_timestamp);
+                dual_timestamp_serialize(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp);
+
+                if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
+                        unit_serialize_item_format(u, f, "main-exec-status-code", "%i", s->main_exec_status.code);
+                        unit_serialize_item_format(u, f, "main-exec-status-status", "%i", s->main_exec_status.status);
+                }
+        }
+        if (dual_timestamp_is_set(&s->watchdog_timestamp))
+                dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
+
+        return 0;
+}
+
+static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Service *s = SERVICE(u);
+
+        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, "result")) {
+                ServiceResult f;
+
+                f = service_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != SERVICE_SUCCESS)
+                        s->result = f;
+
+        } else if (streq(key, "reload-result")) {
+                ServiceResult f;
+
+                f = service_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse reload result value %s", value);
+                else if (f != SERVICE_SUCCESS)
+                        s->reload_result = f;
+
+        } else if (streq(key, "control-pid")) {
+                pid_t pid;
+
+                if (parse_pid(value, &pid) < 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        s->control_pid = pid;
+        } else if (streq(key, "main-pid")) {
+                pid_t pid;
+
+                if (parse_pid(value, &pid) < 0)
+                        log_debug("Failed to parse main-pid value %s", value);
+                else
+                        service_set_main_pid(s, (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, "status-text")) {
+                char *t;
+
+                if ((t = strdup(value))) {
+                        free(s->status_text);
+                        s->status_text = t;
+                }
+
+        } 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 if (streq(key, "main-exec-status-pid")) {
+                pid_t pid;
+
+                if (parse_pid(value, &pid) < 0)
+                        log_debug("Failed to parse main-exec-status-pid value %s", value);
+                else
+                        s->main_exec_status.pid = pid;
+        } else if (streq(key, "main-exec-status-code")) {
+                int i;
+
+                if (safe_atoi(value, &i) < 0)
+                        log_debug("Failed to parse main-exec-status-code value %s", value);
+                else
+                        s->main_exec_status.code = i;
+        } else if (streq(key, "main-exec-status-status")) {
+                int i;
+
+                if (safe_atoi(value, &i) < 0)
+                        log_debug("Failed to parse main-exec-status-status value %s", value);
+                else
+                        s->main_exec_status.status = i;
+        } else if (streq(key, "main-exec-status-start"))
+                dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp);
+        else if (streq(key, "main-exec-status-exit"))
+                dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp);
+        else if (streq(key, "watchdog-timestamp"))
+                dual_timestamp_deserialize(value, &s->watchdog_timestamp);
+        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);
+
+        /* Never clean up services that still have a process around,
+         * even if the service is formally dead. */
+        if (cgroup_good(s) > 0 ||
+            main_pid_good(s) > 0 ||
+            control_pid_good(s) > 0)
+                return true;
+
+#ifdef HAVE_SYSV_COMPAT
+        if (s->sysv_path)
+                return true;
+#endif
+
+        return false;
+}
+
+static bool service_check_snapshot(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        return !s->got_socket_fd;
+}
+
+static int service_retry_pid_file(Service *s) {
+        int r;
+
+        assert(s->pid_file);
+        assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
+
+        r = service_load_pid_file(s, false);
+        if (r < 0)
+                return r;
+
+        service_unwatch_pid_file(s);
+
+        service_enter_running(s, SERVICE_SUCCESS);
+        return 0;
+}
+
+static int service_watch_pid_file(Service *s) {
+        int r;
+
+        log_debug("Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
+        r = path_spec_watch(s->pid_file_pathspec, UNIT(s));
+        if (r < 0)
+                goto fail;
+
+        /* the pidfile might have appeared just before we set the watch */
+        service_retry_pid_file(s);
+
+        return 0;
+fail:
+        log_error("Failed to set a watch for %s's PID file %s: %s",
+                  UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r));
+        service_unwatch_pid_file(s);
+        return r;
+}
+
+static int service_demand_pid_file(Service *s) {
+        PathSpec *ps;
+
+        assert(s->pid_file);
+        assert(!s->pid_file_pathspec);
+
+        ps = new0(PathSpec, 1);
+        if (!ps)
+                return -ENOMEM;
+
+        ps->path = strdup(s->pid_file);
+        if (!ps->path) {
+                free(ps);
+                return -ENOMEM;
+        }
+
+        path_kill_slashes(ps->path);
+
+        /* PATH_CHANGED would not be enough. There are daemons (sendmail) that
+         * keep their PID file open all the time. */
+        ps->type = PATH_MODIFIED;
+        ps->inotify_fd = -1;
+
+        s->pid_file_pathspec = ps;
+
+        return service_watch_pid_file(s);
+}
+
+static void service_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+        assert(fd >= 0);
+        assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
+        assert(s->pid_file_pathspec);
+        assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
+
+        log_debug("inotify event for %s", u->id);
+
+        if (path_spec_fd_event(s->pid_file_pathspec, events) < 0)
+                goto fail;
+
+        if (service_retry_pid_file(s) == 0)
+                return;
+
+        if (service_watch_pid_file(s) < 0)
+                goto fail;
+
+        return;
+fail:
+        service_unwatch_pid_file(s);
+        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+}
+
+static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+        Service *s = SERVICE(u);
+        ServiceResult f;
+
+        assert(s);
+        assert(pid >= 0);
+
+        if (UNIT(s)->fragment_path ? is_clean_exit(code, status) : is_clean_exit_lsb(code, status))
+                f = SERVICE_SUCCESS;
+        else if (code == CLD_EXITED)
+                f = SERVICE_FAILURE_EXIT_CODE;
+        else if (code == CLD_KILLED)
+                f = SERVICE_FAILURE_SIGNAL;
+        else if (code == CLD_DUMPED)
+                f = SERVICE_FAILURE_CORE_DUMP;
+        else
+                assert_not_reached("Unknown code");
+
+        if (s->main_pid == pid) {
+                /* Forking services may occasionally move to a new PID.
+                 * As long as they update the PID file before exiting the old
+                 * PID, they're fine. */
+                if (service_load_pid_file(s, false) == 0)
+                        return;
+
+                s->main_pid = 0;
+                exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
+
+                /* If this is not a forking service than the main
+                 * process got started and hence we copy the exit
+                 * status so that it is recorded both as main and as
+                 * control process exit status */
+                if (s->main_command) {
+                        s->main_command->exec_status = s->main_exec_status;
+
+                        if (s->main_command->ignore)
+                                f = SERVICE_SUCCESS;
+                }
+
+                log_full(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+                         "%s: main process exited, code=%s, status=%i", u->id, sigchld_code_to_string(code), status);
+
+                if (f != SERVICE_SUCCESS)
+                        s->result = f;
+
+                if (s->main_command &&
+                    s->main_command->command_next &&
+                    f == SERVICE_SUCCESS) {
+
+                        /* There is another command to *
+                         * execute, so let's do that. */
+
+                        log_debug("%s running next main command for state %s", u->id, service_state_to_string(s->state));
+                        service_run_next_main(s);
+
+                } else {
+
+                        /* The service exited, so the service is officially
+                         * gone. */
+                        s->main_command = NULL;
+
+                        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:
+                                if (s->type == SERVICE_ONESHOT) {
+                                        /* This was our main goal, so let's go on */
+                                        if (f == SERVICE_SUCCESS)
+                                                service_enter_start_post(s);
+                                        else
+                                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+                                        break;
+                                } else {
+                                        assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
+
+                                        /* Fall through */
+                                }
+
+                        case SERVICE_RUNNING:
+                                service_enter_running(s, f);
+                                break;
+
+                        case SERVICE_STOP_SIGTERM:
+                        case SERVICE_STOP_SIGKILL:
+
+                                if (!control_pid_good(s))
+                                        service_enter_stop_post(s, f);
+
+                                /* 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) {
+
+                s->control_pid = 0;
+
+                if (s->control_command) {
+                        exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
+
+                        if (s->control_command->ignore)
+                                f = SERVICE_SUCCESS;
+                }
+
+                log_full(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+                         "%s: control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
+
+                if (f != SERVICE_SUCCESS)
+                        s->result = f;
+
+                if (s->control_command &&
+                    s->control_command->command_next &&
+                    f == SERVICE_SUCCESS) {
+
+                        /* There is another command to *
+                         * execute, so let's do that. */
+
+                        log_debug("%s running next control command for state %s", u->id, service_state_to_string(s->state));
+                        service_run_next_control(s);
+
+                } 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->id, service_state_to_string(s->state));
+
+                        switch (s->state) {
+
+                        case SERVICE_START_PRE:
+                                if (f == SERVICE_SUCCESS)
+                                        service_enter_start(s);
+                                else
+                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+                                break;
+
+                        case SERVICE_START:
+                                assert(s->type == SERVICE_FORKING);
+
+                                if (f != SERVICE_SUCCESS) {
+                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+                                        break;
+                                }
+
+                                if (s->pid_file) {
+                                        bool has_start_post;
+                                        int r;
+
+                                        /* Let's try to load the pid file here if we can.
+                                         * The PID file might actually be created by a START_POST
+                                         * script. In that case don't worry if the loading fails. */
+
+                                        has_start_post = !!s->exec_command[SERVICE_EXEC_START_POST];
+                                        r = service_load_pid_file(s, !has_start_post);
+                                        if (!has_start_post && r < 0) {
+                                                r = service_demand_pid_file(s);
+                                                if (r < 0 || !cgroup_good(s))
+                                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+                                                break;
+                                        }
+                                } else
+                                        service_search_main_pid(s);
+
+                                service_enter_start_post(s);
+                                break;
+
+                        case SERVICE_START_POST:
+                                if (f != SERVICE_SUCCESS) {
+                                        service_enter_stop(s, f);
+                                        break;
+                                }
+
+                                if (s->pid_file) {
+                                        int r;
+
+                                        r = service_load_pid_file(s, true);
+                                        if (r < 0) {
+                                                r = service_demand_pid_file(s);
+                                                if (r < 0 || !cgroup_good(s))
+                                                        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+                                                break;
+                                        }
+                                } else
+                                        service_search_main_pid(s);
+
+                                service_enter_running(s, SERVICE_SUCCESS);
+                                break;
+
+                        case SERVICE_RELOAD:
+                                if (f == SERVICE_SUCCESS) {
+                                        service_load_pid_file(s, true);
+                                        service_search_main_pid(s);
+                                }
+
+                                s->reload_result = f;
+                                service_enter_running(s, SERVICE_SUCCESS);
+                                break;
+
+                        case SERVICE_STOP:
+                                service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
+                                break;
+
+                        case SERVICE_STOP_SIGTERM:
+                        case SERVICE_STOP_SIGKILL:
+                                if (main_pid_good(s) <= 0)
+                                        service_enter_stop_post(s, f);
+
+                                /* 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, f, true);
+                                break;
+
+                        default:
+                                assert_not_reached("Uh, control process died at wrong time.");
+                        }
+                }
+        }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
+}
+
+static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+        assert(elapsed == 1);
+
+        if (w == &s->watchdog_watch) {
+                service_handle_watchdog(s);
+                return;
+        }
+
+        assert(w == &s->timer_watch);
+
+        switch (s->state) {
+
+        case SERVICE_START_PRE:
+        case SERVICE_START:
+                log_warning("%s operation timed out. Terminating.", u->id);
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                break;
+
+        case SERVICE_START_POST:
+                log_warning("%s operation timed out. Stopping.", u->id);
+                service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
+                break;
+
+        case SERVICE_RELOAD:
+                log_warning("%s operation timed out. Stopping.", u->id);
+                s->reload_result = SERVICE_FAILURE_TIMEOUT;
+                service_enter_running(s, SERVICE_SUCCESS);
+                break;
+
+        case SERVICE_STOP:
+                log_warning("%s stopping timed out. Terminating.", u->id);
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                break;
+
+        case SERVICE_STOP_SIGTERM:
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s stopping timed out. Killing.", u->id);
+                        service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s stopping timed out. Skipping SIGKILL.", u->id);
+                        service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                }
+
+                break;
+
+        case SERVICE_STOP_SIGKILL:
+                /* Uh, we 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->id);
+                service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                break;
+
+        case SERVICE_STOP_POST:
+                log_warning("%s stopping timed out (2). Terminating.", u->id);
+                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                break;
+
+        case SERVICE_FINAL_SIGTERM:
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s stopping timed out (2). Killing.", u->id);
+                        service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->id);
+                        service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+                }
+
+                break;
+
+        case SERVICE_FINAL_SIGKILL:
+                log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id);
+                service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
+                break;
+
+        case SERVICE_AUTO_RESTART:
+                log_info("%s holdoff time over, scheduling restart.", u->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->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_START:
+        case SERVICE_START_POST:
+                /* If we were hoping for the daemon to write its PID file,
+                 * we can give up now. */
+                if (s->pid_file_pathspec) {
+                        log_warning("%s never wrote its PID file. Failing.", UNIT(s)->id);
+                        service_unwatch_pid_file(s);
+                        if (s->state == SERVICE_START)
+                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+                        else
+                                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+                }
+                break;
+
+        case SERVICE_RUNNING:
+                /* service_enter_running() will figure out what to do */
+                service_enter_running(s, SERVICE_SUCCESS);
+                break;
+
+        case SERVICE_STOP_SIGTERM:
+        case SERVICE_STOP_SIGKILL:
+
+                if (main_pid_good(s) <= 0 && !control_pid_good(s))
+                        service_enter_stop_post(s, SERVICE_SUCCESS);
+
+                break;
+
+        case SERVICE_FINAL_SIGTERM:
+        case SERVICE_FINAL_SIGKILL:
+                if (main_pid_good(s) <= 0 && !control_pid_good(s))
+                        service_enter_dead(s, SERVICE_SUCCESS, SERVICE_SUCCESS);
+
+                break;
+
+        default:
+                ;
+        }
+}
+
+static void service_notify_message(Unit *u, pid_t pid, char **tags) {
+        Service *s = SERVICE(u);
+        const char *e;
+
+        assert(u);
+
+        if (s->notify_access == NOTIFY_NONE) {
+                log_warning("%s: Got notification message from PID %lu, but reception is disabled.",
+                            u->id, (unsigned long) pid);
+                return;
+        }
+
+        if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
+                log_warning("%s: Got notification message from PID %lu, but reception only permitted for PID %lu",
+                            u->id, (unsigned long) pid, (unsigned long) s->main_pid);
+                return;
+        }
+
+        log_debug("%s: Got message", u->id);
+
+        /* Interpret MAINPID= */
+        if ((e = strv_find_prefix(tags, "MAINPID=")) &&
+            (s->state == SERVICE_START ||
+             s->state == SERVICE_START_POST ||
+             s->state == SERVICE_RUNNING ||
+             s->state == SERVICE_RELOAD)) {
+
+                if (parse_pid(e + 8, &pid) < 0)
+                        log_warning("Failed to parse notification message %s", e);
+                else {
+                        log_debug("%s: got %s", u->id, e);
+                        service_set_main_pid(s, pid);
+                }
+        }
+
+        /* Interpret READY= */
+        if (s->type == SERVICE_NOTIFY &&
+            s->state == SERVICE_START &&
+            strv_find(tags, "READY=1")) {
+                log_debug("%s: got READY=1", u->id);
+
+                service_enter_start_post(s);
+        }
+
+        /* Interpret STATUS= */
+        e = strv_find_prefix(tags, "STATUS=");
+        if (e) {
+                char *t;
+
+                if (e[7]) {
+
+                        if (!utf8_is_valid(e+7)) {
+                                log_warning("Status message in notification is not UTF-8 clean.");
+                                return;
+                        }
+
+                        t = strdup(e+7);
+                        if (!t) {
+                                log_error("Failed to allocate string.");
+                                return;
+                        }
+
+                        log_debug("%s: got %s", u->id, e);
+
+                        free(s->status_text);
+                        s->status_text = t;
+                } else {
+                        free(s->status_text);
+                        s->status_text = NULL;
+                }
+
+        }
+        if (strv_find(tags, "WATCHDOG=1")) {
+                log_debug("%s: got WATCHDOG=1", u->id);
+                service_reset_watchdog(s);
+        }
+
+        /* Notify clients about changed status or main pid */
+        unit_add_to_dbus_queue(u);
+}
+
+#ifdef HAVE_SYSV_COMPAT
+
+#ifdef TARGET_SUSE
+static void sysv_facility_in_insserv_conf(Manager *mgr) {
+        FILE *f=NULL;
+        int r;
+
+        if (!(f = fopen("/etc/insserv.conf", "re"))) {
+                r = errno == ENOENT ? 0 : -errno;
+                goto finish;
+        }
+
+        while (!feof(f)) {
+                char l[LINE_MAX], *t;
+                char **parsed = NULL;
+
+                if (!fgets(l, sizeof(l), f)) {
+                        if (feof(f))
+                                break;
+
+                        r = -errno;
+                        log_error("Failed to read configuration file '/etc/insserv.conf': %s", strerror(-r));
+                        goto finish;
+                }
+
+                t = strstrip(l);
+                if (*t != '$' && *t != '<')
+                        continue;
+
+                parsed = strv_split(t,WHITESPACE);
+                /* we ignore <interactive>, not used, equivalent to X-Interactive */
+                if (parsed && !startswith_no_case (parsed[0], "<interactive>")) {
+                        char *facility;
+                        Unit *u;
+                        if (sysv_translate_facility(parsed[0], NULL, &facility) < 0)
+                                continue;
+                        if ((u = manager_get_unit(mgr, facility)) && (u->type == UNIT_TARGET)) {
+                                UnitDependency e;
+                                char *dep = NULL, *name, **j;
+
+                                STRV_FOREACH (j, parsed+1) {
+                                        if (*j[0]=='+') {
+                                                e = UNIT_WANTS;
+                                                name = *j+1;
+                                        }
+                                        else {
+                                                e = UNIT_REQUIRES;
+                                                name = *j;
+                                        }
+                                        if (sysv_translate_facility(name, NULL, &dep) < 0)
+                                                continue;
+
+                                        r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, e, dep, NULL, true);
+                                        free(dep);
+                                }
+                        }
+                        free(facility);
+                }
+                strv_free(parsed);
+        }
+finish:
+        if (f)
+                fclose(f);
+
+}
+#endif
+
+static int service_enumerate(Manager *m) {
+        char **p;
+        unsigned i;
+        DIR *d = NULL;
+        char *path = NULL, *fpath = NULL, *name = NULL;
+        Set *runlevel_services[ELEMENTSOF(rcnd_table)], *shutdown_services = NULL;
+        Unit *service;
+        Iterator j;
+        int r;
+
+        assert(m);
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return 0;
+
+        zero(runlevel_services);
+
+        STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path)
+                for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
+                        struct dirent *de;
+
+                        free(path);
+                        path = join(*p, "/", rcnd_table[i].path, NULL);
+                        if (!path) {
+                                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))) {
+                                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 = join(path, "/", de->d_name, NULL);
+                                if (!fpath) {
+                                        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 = sysv_translate_name(de->d_name + 3))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                if ((r = manager_load_unit_prepare(m, name, NULL, NULL, &service)) < 0) {
+                                        log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
+                                        continue;
+                                }
+
+                                if (de->d_name[0] == 'S')  {
+
+                                        if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) {
+                                                SERVICE(service)->sysv_start_priority_from_rcnd =
+                                                        MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd);
+
+                                                SERVICE(service)->sysv_enabled = true;
+                                        }
+
+                                        if ((r = set_ensure_allocated(&runlevel_services[i], trivial_hash_func, trivial_compare_func)) < 0)
+                                                goto finish;
+
+                                        if ((r = set_put(runlevel_services[i], service)) < 0)
+                                                goto finish;
+
+                                } else if (de->d_name[0] == 'K' &&
+                                           (rcnd_table[i].type == RUNLEVEL_DOWN ||
+                                            rcnd_table[i].type == RUNLEVEL_SYSINIT)) {
+
+                                        if ((r = set_ensure_allocated(&shutdown_services, trivial_hash_func, trivial_compare_func)) < 0)
+                                                goto finish;
+
+                                        if ((r = set_put(shutdown_services, service)) < 0)
+                                                goto finish;
+                                }
+                        }
+                }
+
+        /* Now we loaded all stubs and are aware of the lowest
+        start-up priority for all services, not let's actually load
+        the services, this will also tell us which services are
+        actually native now */
+        manager_dispatch_load_queue(m);
+
+        /* If this is a native service, rely on native ways to pull in
+         * a service, don't pull it in via sysv rcN.d links. */
+        for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
+                SET_FOREACH(service, runlevel_services[i], j) {
+                        service = unit_follow_merge(service);
+
+                        if (service->fragment_path)
+                                continue;
+
+                        if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0)
+                                goto finish;
+                }
+
+        /* 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 distinguish here
+         * between the runlevels 0 and 6 and just add them to the
+         * special shutdown target. On SUSE the boot.d/ runlevel is
+         * also used for shutdown, so we add links for that too to the
+         * shutdown target.*/
+        SET_FOREACH(service, shutdown_services, j) {
+                service = unit_follow_merge(service);
+
+                if (service->fragment_path)
+                        continue;
+
+                if ((r = unit_add_two_dependencies_by_name(service, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+#ifdef TARGET_SUSE
+        sysv_facility_in_insserv_conf (m);
+#endif
+
+finish:
+        free(path);
+        free(fpath);
+        free(name);
+
+        for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
+                set_free(runlevel_services[i]);
+        set_free(shutdown_services);
+
+        if (d)
+                closedir(d);
+
+        return r;
+}
+#endif
+
+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->id, name, old_owner, new_owner);
+        else if (old_owner)
+                log_debug("%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
+        else
+                log_debug("%s's D-Bus name %s now registered by %s", u->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, SERVICE_SUCCESS);
+                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->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->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))
+                service_set_main_pid(s, pid);
+}
+
+int service_set_socket_fd(Service *s, int fd, Socket *sock) {
+
+        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)->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;
+
+        unit_ref_set(&s->accept_socket, UNIT(sock));
+
+        return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+}
+
+static void service_reset_failed(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        if (s->state == SERVICE_FAILED)
+                service_set_state(s, SERVICE_DEAD);
+
+        s->result = SERVICE_SUCCESS;
+        s->reload_result = SERVICE_SUCCESS;
+}
+
+static bool service_need_daemon_reload(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+#ifdef HAVE_SYSV_COMPAT
+        if (s->sysv_path) {
+                struct stat st;
+
+                zero(st);
+                if (stat(s->sysv_path, &st) < 0)
+                        /* What, cannot access this anymore? */
+                        return true;
+
+                if (s->sysv_mtime > 0 &&
+                    timespec_load(&st.st_mtim) != s->sysv_mtime)
+                        return true;
+        }
+#endif
+
+        return false;
+}
+
+static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Service *s = SERVICE(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (s->main_pid <= 0 && who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
+                return -ESRCH;
+        }
+
+        if (s->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ESRCH;
+        }
+
+        if (who == KILL_CONTROL || who == KILL_ALL)
+                if (s->control_pid > 0)
+                        if (kill(s->control_pid, signo) < 0)
+                                r = -errno;
+
+        if (who == KILL_MAIN || who == KILL_ALL)
+                if (s->main_pid > 0)
+                        if (kill(s->main_pid, signo) < 0)
+                                r = -errno;
+
+        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control/main pid from being killed via the cgroup */
+                if (s->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if (s->main_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
+                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
+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_FAILED] = "failed",
+        [SERVICE_AUTO_RESTART] = "auto-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
+
+static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
+        [SERVICE_RESTART_NO] = "no",
+        [SERVICE_RESTART_ON_SUCCESS] = "on-success",
+        [SERVICE_RESTART_ON_FAILURE] = "on-failure",
+        [SERVICE_RESTART_ON_ABORT] = "on-abort",
+        [SERVICE_RESTART_ALWAYS] = "always"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
+
+static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
+        [SERVICE_SIMPLE] = "simple",
+        [SERVICE_FORKING] = "forking",
+        [SERVICE_ONESHOT] = "oneshot",
+        [SERVICE_DBUS] = "dbus",
+        [SERVICE_NOTIFY] = "notify"
+};
+
+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);
+
+static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
+        [NOTIFY_NONE] = "none",
+        [NOTIFY_MAIN] = "main",
+        [NOTIFY_ALL] = "all"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
+
+static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
+        [SERVICE_SUCCESS] = "success",
+        [SERVICE_FAILURE_RESOURCES] = "resources",
+        [SERVICE_FAILURE_TIMEOUT] = "timeout",
+        [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
+        [SERVICE_FAILURE_SIGNAL] = "signal",
+        [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
+        [SERVICE_FAILURE_WATCHDOG] = "watchdog"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
+
+static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = {
+        [SERVICE_START_LIMIT_NONE] = "none",
+        [SERVICE_START_LIMIT_REBOOT] = "reboot",
+        [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force",
+        [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate"
+};
+DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
+
+const UnitVTable service_vtable = {
+        .suffix = ".service",
+        .object_size = sizeof(Service),
+        .sections =
+                "Unit\0"
+                "Service\0"
+                "Install\0",
+        .show_status = true,
+
+        .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,
+
+        .kill = service_kill,
+
+        .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,
+        .fd_event = service_fd_event,
+
+        .reset_failed = service_reset_failed,
+
+        .need_daemon_reload = service_need_daemon_reload,
+
+        .cgroup_notify_empty = service_cgroup_notify_event,
+        .notify_message = service_notify_message,
+
+        .bus_name_owner_change = service_bus_name_owner_change,
+        .bus_query_pid_done = service_bus_query_pid_done,
+
+        .bus_interface = "org.freedesktop.systemd1.Service",
+        .bus_message_handler = bus_service_message_handler,
+        .bus_invalidating_properties =  bus_service_invalidating_properties,
+
+#ifdef HAVE_SYSV_COMPAT
+        .enumerate = service_enumerate
+#endif
+};
diff --git a/src/core/service.h b/src/core/service.h
new file mode 100644
index 0000000..60b1051
--- /dev/null
+++ b/src/core/service.h
@@ -0,0 +1,220 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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 "path.h"
+#include "ratelimit.h"
+#include "service.h"
+
+typedef enum ServiceState {
+        SERVICE_DEAD,
+        SERVICE_START_PRE,
+        SERVICE_START,
+        SERVICE_START_POST,
+        SERVICE_RUNNING,
+        SERVICE_EXITED,            /* Nothing is running anymore, but RemainAfterExit is true hence 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_FAILED,
+        SERVICE_AUTO_RESTART,
+        _SERVICE_STATE_MAX,
+        _SERVICE_STATE_INVALID = -1
+} ServiceState;
+
+typedef enum ServiceRestart {
+        SERVICE_RESTART_NO,
+        SERVICE_RESTART_ON_SUCCESS,
+        SERVICE_RESTART_ON_FAILURE,
+        SERVICE_RESTART_ON_ABORT,
+        SERVICE_RESTART_ALWAYS,
+        _SERVICE_RESTART_MAX,
+        _SERVICE_RESTART_INVALID = -1
+} ServiceRestart;
+
+typedef enum ServiceType {
+        SERVICE_SIMPLE,   /* we fork and go on right-away (i.e. modern socket activated daemons) */
+        SERVICE_FORKING,  /* forks by itself (i.e. traditional daemons) */
+        SERVICE_ONESHOT,  /* 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_NOTIFY,   /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+        _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;
+
+typedef enum NotifyAccess {
+        NOTIFY_NONE,
+        NOTIFY_ALL,
+        NOTIFY_MAIN,
+        _NOTIFY_ACCESS_MAX,
+        _NOTIFY_ACCESS_INVALID = -1
+} NotifyAccess;
+
+typedef enum ServiceResult {
+        SERVICE_SUCCESS,
+        SERVICE_FAILURE_RESOURCES,
+        SERVICE_FAILURE_TIMEOUT,
+        SERVICE_FAILURE_EXIT_CODE,
+        SERVICE_FAILURE_SIGNAL,
+        SERVICE_FAILURE_CORE_DUMP,
+        SERVICE_FAILURE_WATCHDOG,
+        _SERVICE_RESULT_MAX,
+        _SERVICE_RESULT_INVALID = -1
+} ServiceResult;
+
+typedef enum StartLimitAction {
+        SERVICE_START_LIMIT_NONE,
+        SERVICE_START_LIMIT_REBOOT,
+        SERVICE_START_LIMIT_REBOOT_FORCE,
+        SERVICE_START_LIMIT_REBOOT_IMMEDIATE,
+        _SERVICE_START_LIMIT_MAX,
+        _SERVICE_START_LIMIT_INVALID = -1
+} StartLimitAction;
+
+struct Service {
+        Unit 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;
+
+        dual_timestamp watchdog_timestamp;
+        usec_t watchdog_usec;
+        Watch watchdog_watch;
+
+        ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        ServiceState state, deserialized_state;
+
+        /* The exit status of the real main process */
+        ExecStatus main_exec_status;
+
+        /* The currently executed control process */
+        ExecCommand *control_command;
+
+        /* The currently executed main process, which may be NULL if
+         * the main process got started via forking mode and not by
+         * us */
+        ExecCommand *main_command;
+
+        /* The ID of the control command currently being executed */
+        ServiceExecCommand control_command_id;
+
+        pid_t main_pid, control_pid;
+        int socket_fd;
+
+        int fsck_passno;
+
+        bool permissions_start_only;
+        bool root_directory_start_only;
+        bool remain_after_exit;
+        bool guess_main_pid;
+
+        /* If we shut down, remember why */
+        ServiceResult result;
+        ServiceResult reload_result;
+
+        bool main_pid_known:1;
+        bool main_pid_alien:1;
+        bool bus_name_good:1;
+        bool forbid_restart:1;
+        bool got_socket_fd:1;
+#ifdef HAVE_SYSV_COMPAT
+        bool sysv_has_lsb:1;
+        bool sysv_enabled:1;
+        int sysv_start_priority_from_rcnd;
+        int sysv_start_priority;
+
+        char *sysv_path;
+        char *sysv_runlevels;
+        usec_t sysv_mtime;
+#endif
+
+        char *bus_name;
+
+        char *status_text;
+
+        RateLimit start_limit;
+        StartLimitAction start_limit_action;
+
+
+        UnitRef accept_socket;
+
+        Watch timer_watch;
+        PathSpec *pid_file_pathspec;
+
+        NotifyAccess notify_access;
+};
+
+extern const UnitVTable service_vtable;
+
+struct Socket;
+
+int service_set_socket_fd(Service *s, int fd, struct Socket *socket);
+
+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);
+
+const char* notify_access_to_string(NotifyAccess i);
+NotifyAccess notify_access_from_string(const char *s);
+
+const char* service_result_to_string(ServiceResult i);
+ServiceResult service_result_from_string(const char *s);
+
+const char* start_limit_action_to_string(StartLimitAction i);
+StartLimitAction start_limit_action_from_string(const char *s);
+
+#endif
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
new file mode 100644
index 0000000..82ec510
--- /dev/null
+++ b/src/core/snapshot.c
@@ -0,0 +1,309 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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"
+#include "bus-errors.h"
+
+static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
+        [SNAPSHOT_DEAD] = UNIT_INACTIVE,
+        [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
+};
+
+static void snapshot_init(Unit *u) {
+        Snapshot *s = SNAPSHOT(u);
+
+        assert(s);
+        assert(UNIT(s)->load_state == UNIT_STUB);
+
+        UNIT(s)->ignore_on_isolate = true;
+        UNIT(s)->ignore_on_snapshot = true;
+}
+
+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)->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], true);
+}
+
+static int snapshot_load(Unit *u) {
+        Snapshot *s = SNAPSHOT(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        /* Make sure that only snapshots created via snapshot_create()
+         * can be loaded */
+        if (!s->by_snapshot_create && UNIT(s)->manager->n_reloading <= 0)
+                return -ENOENT;
+
+        u->load_state = UNIT_LOADED;
+        return 0;
+}
+
+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->dependencies[UNIT_WANTS], i)
+                unit_serialize_item(u, f, "wants", other->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, "wants")) {
+
+                if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, 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, DBusError *e, 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, false)) {
+                        dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
+                        return -EINVAL;
+                }
+
+                if (unit_name_to_type(name) != UNIT_SNAPSHOT) {
+                        dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name);
+                        return -EINVAL;
+                }
+
+                if (manager_get_unit(m, name)) {
+                        dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", 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_prepare(m, name, NULL, e, &u);
+        free(n);
+
+        if (r < 0)
+                goto fail;
+
+        SNAPSHOT(u)->by_snapshot_create = true;
+        manager_dispatch_load_queue(m);
+        assert(u->load_state == UNIT_LOADED);
+
+        HASHMAP_FOREACH_KEY(other, k, m->units, i) {
+
+                if (other->ignore_on_snapshot)
+                        continue;
+
+                if (k != other->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_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, 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",
+        .object_size = sizeof(Snapshot),
+
+        .no_alias = true,
+        .no_instances = true,
+        .no_gc = true,
+
+        .init = snapshot_init,
+
+        .load = snapshot_load,
+        .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_interface = "org.freedesktop.systemd1.Snapshot",
+        .bus_message_handler = bus_snapshot_message_handler
+};
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
new file mode 100644
index 0000000..bf92e99
--- /dev/null
+++ b/src/core/snapshot.h
@@ -0,0 +1,53 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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 {
+        Unit meta;
+
+        SnapshotState state, deserialized_state;
+
+        bool cleanup;
+        bool by_snapshot_create:1;
+};
+
+extern const UnitVTable snapshot_vtable;
+
+int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, 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/core/socket.c b/src/core/socket.c
new file mode 100644
index 0000000..5b24b34
--- /dev/null
+++ b/src/core/socket.c
@@ -0,0 +1,2218 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <mqueue.h>
+
+#include "unit.h"
+#include "socket.h"
+#include "netinet/tcp.h"
+#include "log.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "strv.h"
+#include "mkdir.h"
+#include "unit-name.h"
+#include "dbus-socket.h"
+#include "missing.h"
+#include "special.h"
+#include "bus-errors.h"
+#include "label.h"
+#include "exit-status.h"
+#include "def.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_FAILED] = UNIT_FAILED
+};
+
+static void socket_init(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        s->backlog = SOMAXCONN;
+        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        s->directory_mode = 0755;
+        s->socket_mode = 0666;
+
+        s->max_connections = 64;
+
+        s->priority = -1;
+        s->ip_tos = -1;
+        s->ip_ttl = -1;
+        s->mark = -1;
+
+        exec_context_init(&s->exec_context);
+        s->exec_context.std_output = u->manager->default_std_output;
+        s->exec_context.std_error = u->manager->default_std_error;
+
+        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);
+
+        unit_ref_unset(&s->service);
+
+        free(s->tcp_congestion);
+        s->tcp_congestion = NULL;
+
+        free(s->bind_to_device);
+        s->bind_to_device = NULL;
+
+        unit_unwatch_timer(u, &s->timer_watch);
+}
+
+static int socket_instantiate_service(Socket *s) {
+        char *prefix, *name;
+        int r;
+        Unit *u;
+
+        assert(s);
+
+        /* This fills in s->service if it isn't filled in yet. For
+         * Accept=yes sockets we create the next connection service
+         * here. For Accept=no this is mostly a NOP since the service
+         * is figured out at load time anyway. */
+
+        if (UNIT_DEREF(s->service))
+                return 0;
+
+        assert(s->accept);
+
+        if (!(prefix = unit_name_to_prefix(UNIT(s)->id)))
+                return -ENOMEM;
+
+        r = asprintf(&name, "%s@%u.service", prefix, s->n_accepted);
+        free(prefix);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        r = manager_load_unit(UNIT(s)->manager, name, NULL, NULL, &u);
+        free(name);
+
+        if (r < 0)
+                return r;
+
+#ifdef HAVE_SYSV_COMPAT
+        if (SERVICE(u)->sysv_path) {
+                log_error("Using SysV services for socket activation is not supported. Refusing.");
+                return -ENOENT;
+        }
+#endif
+
+        u->no_gc = true;
+        unit_ref_set(&s->service, u);
+
+        return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
+}
+
+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)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!s->ports) {
+                log_error("%s lacks Listen setting. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        if (s->accept && have_non_accept_socket(s)) {
+                log_error("%s configured for accepting sockets, but sockets are non-accepting. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        if (s->accept && s->max_connections <= 0) {
+                log_error("%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        if (s->accept && UNIT_DEREF(s->service)) {
+                log_error("Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->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 if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) {
+                        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 (UNIT(s)->load_state != UNIT_LOADED ||
+            UNIT(m)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!socket_needs_mount(s, m->where))
+                return 0;
+
+        if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
+                return r;
+
+        return 0;
+}
+
+static int socket_add_mount_links(Socket *s) {
+        Unit *other;
+        int r;
+
+        assert(s);
+
+        LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_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_add_default_dependencies(Socket *s) {
+        int r;
+        assert(s);
+
+        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+                if ((r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
+                        return r;
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+                        return r;
+        }
+
+        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
+static bool socket_has_exec(Socket *s) {
+        unsigned i;
+        assert(s);
+
+        for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++)
+                if (s->exec_command[i])
+                        return true;
+
+        return false;
+}
+
+static int socket_load(Unit *u) {
+        Socket *s = SOCKET(u);
+        int r;
+
+        assert(u);
+        assert(u->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->load_state == UNIT_LOADED) {
+
+                if (have_non_accept_socket(s)) {
+
+                        if (!UNIT_DEREF(s->service)) {
+                                Unit *x;
+
+                                r = unit_load_related_unit(u, ".service", &x);
+                                if (r < 0)
+                                        return r;
+
+                                unit_ref_set(&s->service, x);
+                        }
+
+                        r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true);
+                        if (r < 0)
+                                return r;
+                }
+
+                if ((r = socket_add_mount_links(s)) < 0)
+                        return r;
+
+                if ((r = socket_add_device_link(s)) < 0)
+                        return r;
+
+                if (socket_has_exec(s))
+                        if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
+                                return r;
+
+                if ((r = unit_add_default_cgroups(u)) < 0)
+                        return r;
+
+                if (UNIT(s)->default_dependencies)
+                        if ((r = socket_add_default_dependencies(s)) < 0)
+                                return r;
+        }
+
+        return socket_verify(s);
+}
+
+static const char* listen_lookup(int family, int type) {
+
+        if (family == AF_NETLINK)
+                return "ListenNetlink";
+
+        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"
+                "%sResult: %s\n"
+                "%sBindIPv6Only: %s\n"
+                "%sBacklog: %u\n"
+                "%sSocketMode: %04o\n"
+                "%sDirectoryMode: %04o\n"
+                "%sKeepAlive: %s\n"
+                "%sFreeBind: %s\n"
+                "%sTransparent: %s\n"
+                "%sBroadcast: %s\n"
+                "%sPassCredentials: %s\n"
+                "%sPassSecurity: %s\n"
+                "%sTCPCongestion: %s\n",
+                prefix, socket_state_to_string(s->state),
+                prefix, socket_result_to_string(s->result),
+                prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only),
+                prefix, s->backlog,
+                prefix, s->socket_mode,
+                prefix, s->directory_mode,
+                prefix, yes_no(s->keep_alive),
+                prefix, yes_no(s->free_bind),
+                prefix, yes_no(s->transparent),
+                prefix, yes_no(s->broadcast),
+                prefix, yes_no(s->pass_cred),
+                prefix, yes_no(s->pass_sec),
+                prefix, strna(s->tcp_congestion));
+
+        if (s->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %lu\n",
+                        prefix, (unsigned 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"
+                        "%sNConnections: %u\n"
+                        "%sMaxConnections: %u\n",
+                        prefix, s->n_accepted,
+                        prefix, s->n_connections,
+                        prefix, s->max_connections);
+
+        if (s->priority >= 0)
+                fprintf(f,
+                        "%sPriority: %i\n",
+                        prefix, s->priority);
+
+        if (s->receive_buffer > 0)
+                fprintf(f,
+                        "%sReceiveBuffer: %zu\n",
+                        prefix, s->receive_buffer);
+
+        if (s->send_buffer > 0)
+                fprintf(f,
+                        "%sSendBuffer: %zu\n",
+                        prefix, s->send_buffer);
+
+        if (s->ip_tos >= 0)
+                fprintf(f,
+                        "%sIPTOS: %i\n",
+                        prefix, s->ip_tos);
+
+        if (s->ip_ttl >= 0)
+                fprintf(f,
+                        "%sIPTTL: %i\n",
+                        prefix, s->ip_ttl);
+
+        if (s->pipe_size > 0)
+                fprintf(f,
+                        "%sPipeSize: %zu\n",
+                        prefix, s->pipe_size);
+
+        if (s->mark >= 0)
+                fprintf(f,
+                        "%sMark: %i\n",
+                        prefix, s->mark);
+
+        if (s->mq_maxmsg > 0)
+                fprintf(f,
+                        "%sMessageQueueMaxMessages: %li\n",
+                        prefix, s->mq_maxmsg);
+
+        if (s->mq_msgsize > 0)
+                fprintf(f,
+                        "%sMessageQueueMessageSize: %li\n",
+                        prefix, s->mq_msgsize);
+
+        LIST_FOREACH(port, p, s->ports) {
+
+                if (p->type == SOCKET_SOCKET) {
+                        const char *t;
+                        int r;
+                        char *k = NULL;
+
+                        if ((r = socket_address_print(&p->address, &k)) < 0)
+                                t = strerror(-r);
+                        else
+                                t = k;
+
+                        fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t);
+                        free(k);
+                } else if (p->type == SOCKET_SPECIAL)
+                        fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
+                else if (p->type == SOCKET_MQUEUE)
+                        fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
+                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: {
+                static const char ipv4_prefix[] = {
+                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
+                };
+
+                if (memcmp(&local.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0 &&
+                    memcmp(&remote.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
+                        const uint8_t
+                                *a = local.in6.sin6_addr.s6_addr+12,
+                                *b = remote.in6.sin6_addr.s6_addr+12;
+
+                        if (asprintf(&r,
+                                     "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
+                                     nr,
+                                     a[0], a[1], a[2], a[3],
+                                     ntohs(local.in6.sin6_port),
+                                     b[0], b[1], b[2], b[3],
+                                     ntohs(remote.in6.sin6_port)) < 0)
+                                return -ENOMEM;
+                } else {
+                        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-%lu-%lu",
+                             nr,
+                             (unsigned long) ucred.pid,
+                             (unsigned 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 void socket_apply_socket_options(Socket *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        if (s->keep_alive) {
+                int b = s->keep_alive;
+                if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
+                        log_warning("SO_KEEPALIVE failed: %m");
+        }
+
+        if (s->broadcast) {
+                int one = 1;
+                if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
+                        log_warning("SO_BROADCAST failed: %m");
+        }
+
+        if (s->pass_cred) {
+                int one = 1;
+                if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
+                        log_warning("SO_PASSCRED failed: %m");
+        }
+
+        if (s->pass_sec) {
+                int one = 1;
+                if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0)
+                        log_warning("SO_PASSSEC failed: %m");
+        }
+
+        if (s->priority >= 0)
+                if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
+                        log_warning("SO_PRIORITY failed: %m");
+
+        if (s->receive_buffer > 0) {
+                int value = (int) s->receive_buffer;
+
+                /* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
+
+                if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
+                        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
+                                log_warning("SO_RCVBUF failed: %m");
+        }
+
+        if (s->send_buffer > 0) {
+                int value = (int) s->send_buffer;
+                if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
+                        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+                                log_warning("SO_SNDBUF failed: %m");
+        }
+
+        if (s->mark >= 0)
+                if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
+                        log_warning("SO_MARK failed: %m");
+
+        if (s->ip_tos >= 0)
+                if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
+                        log_warning("IP_TOS failed: %m");
+
+        if (s->ip_ttl >= 0) {
+                int r, x;
+
+                r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
+
+                if (socket_ipv6_is_supported())
+                        x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
+                else {
+                        x = -1;
+                        errno = EAFNOSUPPORT;
+                }
+
+                if (r < 0 && x < 0)
+                        log_warning("IP_TTL/IPV6_UNICAST_HOPS failed: %m");
+        }
+
+        if (s->tcp_congestion)
+                if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0)
+                        log_warning("TCP_CONGESTION failed: %m");
+}
+
+static void socket_apply_fifo_options(Socket *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        if (s->pipe_size > 0)
+                if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
+                        log_warning("F_SETPIPE_SZ: %m");
+}
+
+static int fifo_address_create(
+                const char *path,
+                mode_t directory_mode,
+                mode_t socket_mode,
+                int *_fd) {
+
+        int fd = -1, r = 0;
+        struct stat st;
+        mode_t old_mask;
+
+        assert(path);
+        assert(_fd);
+
+        mkdir_parents(path, directory_mode);
+
+        if ((r = label_fifofile_set(path)) < 0)
+                goto fail;
+
+        /* Enforce the right access mode for the fifo */
+        old_mask = umask(~ socket_mode);
+
+        /* Include the original umask in our mask */
+        umask(~socket_mode | old_mask);
+
+        r = mkfifo(path, socket_mode);
+        umask(old_mask);
+
+        if (r < 0 && errno != EEXIST) {
+                r = -errno;
+                goto fail;
+        }
+
+        if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        label_file_clear();
+
+        if (fstat(fd, &st) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if (!S_ISFIFO(st.st_mode) ||
+            (st.st_mode & 0777) != (socket_mode & ~old_mask) ||
+            st.st_uid != getuid() ||
+            st.st_gid != getgid()) {
+
+                r = -EEXIST;
+                goto fail;
+        }
+
+        *_fd = fd;
+        return 0;
+
+fail:
+        label_file_clear();
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
+
+static int special_address_create(
+                const char *path,
+                int *_fd) {
+
+        int fd = -1, r = 0;
+        struct stat st;
+
+        assert(path);
+        assert(_fd);
+
+        if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if (fstat(fd, &st) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* Check whether this is a /proc, /sys or /dev file or char device */
+        if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
+                r = -EEXIST;
+                goto fail;
+        }
+
+        *_fd = fd;
+        return 0;
+
+fail:
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
+
+static int mq_address_create(
+                const char *path,
+                mode_t mq_mode,
+                long maxmsg,
+                long msgsize,
+                int *_fd) {
+
+        int fd = -1, r = 0;
+        struct stat st;
+        mode_t old_mask;
+        struct mq_attr _attr, *attr = NULL;
+
+        assert(path);
+        assert(_fd);
+
+        if (maxmsg > 0 && msgsize > 0) {
+                zero(_attr);
+                _attr.mq_flags = O_NONBLOCK;
+                _attr.mq_maxmsg = maxmsg;
+                _attr.mq_msgsize = msgsize;
+                attr = &_attr;
+        }
+
+        /* Enforce the right access mode for the mq */
+        old_mask = umask(~ mq_mode);
+
+        /* Include the original umask in our mask */
+        umask(~mq_mode | old_mask);
+
+        fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
+        umask(old_mask);
+
+        if (fd < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if (fstat(fd, &st) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
+            st.st_uid != getuid() ||
+            st.st_gid != getgid()) {
+
+                r = -EEXIST;
+                goto fail;
+        }
+
+        *_fd = fd;
+        return 0;
+
+fail:
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
+
+static int socket_open_fds(Socket *s) {
+        SocketPort *p;
+        int r;
+        char *label = NULL;
+        bool know_label = false;
+
+        assert(s);
+
+        LIST_FOREACH(port, p, s->ports) {
+
+                if (p->fd >= 0)
+                        continue;
+
+                if (p->type == SOCKET_SOCKET) {
+
+                        if (!know_label) {
+
+                                if ((r = socket_instantiate_service(s)) < 0)
+                                        return r;
+
+                                if (UNIT_DEREF(s->service) &&
+                                    SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
+                                        r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
+
+                                        if (r < 0) {
+                                                if (r != -EPERM)
+                                                        return r;
+                                        }
+                                }
+
+                                know_label = true;
+                        }
+
+                        if ((r = socket_address_listen(
+                                             &p->address,
+                                             s->backlog,
+                                             s->bind_ipv6_only,
+                                             s->bind_to_device,
+                                             s->free_bind,
+                                             s->transparent,
+                                             s->directory_mode,
+                                             s->socket_mode,
+                                             label,
+                                             &p->fd)) < 0)
+                                goto rollback;
+
+                        socket_apply_socket_options(s, p->fd);
+
+                } else  if (p->type == SOCKET_SPECIAL) {
+
+                        if ((r = special_address_create(
+                                             p->path,
+                                             &p->fd)) < 0)
+                                goto rollback;
+
+                } else  if (p->type == SOCKET_FIFO) {
+
+                        if ((r = fifo_address_create(
+                                             p->path,
+                                             s->directory_mode,
+                                             s->socket_mode,
+                                             &p->fd)) < 0)
+                                goto rollback;
+
+                        socket_apply_fifo_options(s, p->fd);
+                } else if (p->type == SOCKET_MQUEUE) {
+
+                        if ((r = mq_address_create(
+                                             p->path,
+                                             s->socket_mode,
+                                             s->mq_maxmsg,
+                                             s->mq_msgsize,
+                                             &p->fd)) < 0)
+                                goto rollback;
+                } else
+                        assert_not_reached("Unknown port type");
+        }
+
+        label_free(label);
+        return 0;
+
+rollback:
+        socket_close_fds(s);
+        label_free(label);
+        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",
+                          UNIT(s)->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], true);
+}
+
+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,
+                       UNIT(s)->manager->environment,
+                       true,
+                       true,
+                       true,
+                       UNIT(s)->manager->confirm_spawn,
+                       UNIT(s)->cgroup_bondings,
+                       UNIT(s)->cgroup_attributes,
+                       &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, SocketResult f) {
+        assert(s);
+
+        if (f != SOCKET_SUCCESS)
+                s->result = f;
+
+        socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
+}
+
+static void socket_enter_signal(Socket *s, SocketState state, SocketResult f);
+
+static void socket_enter_stop_post(Socket *s, SocketResult f) {
+        int r;
+        assert(s);
+
+        if (f != SOCKET_SUCCESS)
+                s->result = f;
+
+        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, SOCKET_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
+        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
+}
+
+static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
+        int r;
+        Set *pid_set = NULL;
+        bool wait_for_exit = false;
+
+        assert(s);
+
+        if (f != SOCKET_SUCCESS)
+                s->result = f;
+
+        if (s->exec_context.kill_mode != KILL_NONE) {
+                int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
+
+                if (s->control_pid > 0) {
+                        if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
+
+                                log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
+                        else
+                                wait_for_exit = true;
+                }
+
+                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+
+                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        /* Exclude the control pid from being killed via the cgroup */
+                        if (s->control_pid > 0)
+                                if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
+                                        goto fail;
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                        log_warning("Failed to kill control group: %s", strerror(-r));
+                        } else if (r > 0)
+                                wait_for_exit = true;
+
+                        set_free(pid_set);
+                        pid_set = NULL;
+                }
+        }
+
+        if (wait_for_exit) {
+                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, SOCKET_SUCCESS);
+        else
+                socket_enter_dead(s, SOCKET_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
+
+        if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
+                socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
+        else
+                socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
+
+        if (pid_set)
+                set_free(pid_set);
+}
+
+static void socket_enter_stop_pre(Socket *s, SocketResult f) {
+        int r;
+        assert(s);
+
+        if (f != SOCKET_SUCCESS)
+                s->result = f;
+
+        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, SOCKET_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'stop-pre' task: %s", UNIT(s)->id, strerror(-r));
+        socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
+}
+
+static void socket_enter_listening(Socket *s) {
+        int r;
+        assert(s);
+
+        r = socket_watch_fds(s);
+        if (r < 0) {
+                log_warning("%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
+                goto fail;
+        }
+
+        socket_set_state(s, SOCKET_LISTENING);
+        return;
+
+fail:
+        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+}
+
+static void socket_enter_start_post(Socket *s) {
+        int r;
+        assert(s);
+
+        r = socket_open_fds(s);
+        if (r < 0) {
+                log_warning("%s failed to listen on sockets: %s", UNIT(s)->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])) {
+                r = socket_spawn(s, s->control_command, &s->control_pid);
+                if (r < 0) {
+                        log_warning("%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
+                        goto fail;
+                }
+
+                socket_set_state(s, SOCKET_START_POST);
+        } else
+                socket_enter_listening(s);
+
+        return;
+
+fail:
+        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+}
+
+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' task: %s", UNIT(s)->id, strerror(-r));
+        socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
+}
+
+static void socket_enter_running(Socket *s, int cfd) {
+        int r;
+        DBusError error;
+
+        assert(s);
+        dbus_error_init(&error);
+
+        /* We don't take connections anymore if we are supposed to
+         * shut down anyway */
+        if (unit_pending_inactive(UNIT(s))) {
+                log_debug("Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
+
+                if (cfd >= 0)
+                        close_nointr_nofail(cfd);
+                else  {
+                        /* Flush all sockets by closing and reopening them */
+                        socket_close_fds(s);
+
+                        r = socket_watch_fds(s);
+                        if (r < 0) {
+                                log_warning("%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
+                                socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+                        }
+                }
+
+                return;
+        }
+
+        if (cfd < 0) {
+                Iterator i;
+                Unit *u;
+                bool pending = false;
+
+                /* If there's already a start pending don't bother to
+                 * do anything */
+                SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
+                        if (unit_pending_active(u)) {
+                                pending = true;
+                                break;
+                        }
+
+                if (!pending) {
+                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
+                        if (r < 0)
+                                goto fail;
+                }
+
+                socket_set_state(s, SOCKET_RUNNING);
+        } else {
+                char *prefix, *instance = NULL, *name;
+                Service *service;
+
+                if (s->n_connections >= s->max_connections) {
+                        log_warning("Too many incoming connections (%u)", s->n_connections);
+                        close_nointr_nofail(cfd);
+                        return;
+                }
+
+                r = socket_instantiate_service(s);
+                if (r < 0)
+                        goto fail;
+
+                r = instance_from_socket(cfd, s->n_accepted, &instance);
+                if (r < 0) {
+                        if (r != -ENOTCONN)
+                                goto fail;
+
+                        /* ENOTCONN is legitimate if TCP RST was received.
+                         * This connection is over, but the socket unit lives on. */
+                        close_nointr_nofail(cfd);
+                        return;
+                }
+
+                prefix = unit_name_to_prefix(UNIT(s)->id);
+                if (!prefix) {
+                        free(instance);
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                name = unit_name_build(prefix, instance, ".service");
+                free(prefix);
+                free(instance);
+
+                if (!name) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                r = unit_add_name(UNIT_DEREF(s->service), name);
+                if (r < 0) {
+                        free(name);
+                        goto fail;
+                }
+
+                service = SERVICE(UNIT_DEREF(s->service));
+                unit_ref_unset(&s->service);
+                s->n_accepted ++;
+
+                UNIT(service)->no_gc = false;
+
+                unit_choose_id(UNIT(service), name);
+                free(name);
+
+                r = service_set_socket_fd(service, cfd, s);
+                if (r < 0)
+                        goto fail;
+
+                cfd = -1;
+                s->n_connections ++;
+
+                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
+                if (r < 0)
+                        goto fail;
+
+                /* Notify clients about changed counters */
+                unit_add_to_dbus_queue(UNIT(s));
+        }
+
+        return;
+
+fail:
+        log_warning("%s failed to queue socket startup job: %s", UNIT(s)->id, bus_error(&error, r));
+        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+
+        if (cfd >= 0)
+                close_nointr_nofail(cfd);
+
+        dbus_error_free(&error);
+}
+
+static void socket_run_next(Socket *s) {
+        int r;
+
+        assert(s);
+        assert(s->control_command);
+        assert(s->control_command->command_next);
+
+        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 next task: %s", UNIT(s)->id, strerror(-r));
+
+        if (s->state == SOCKET_START_POST)
+                socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+        else if (s->state == SOCKET_STOP_POST)
+                socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
+        else
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
+}
+
+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 (UNIT_DEREF(s->service)) {
+                Service *service;
+
+                service = SERVICE(UNIT_DEREF(s->service));
+
+                if (UNIT(service)->load_state != UNIT_LOADED) {
+                        log_error("Socket service %s not loaded, refusing.", UNIT(service)->id);
+                        return -ENOENT;
+                }
+
+                /* If the service is already active we cannot start the
+                 * socket */
+                if (service->state != SERVICE_DEAD &&
+                    service->state != SERVICE_FAILED &&
+                    service->state != SERVICE_AUTO_RESTART) {
+                        log_error("Socket service %s already active, refusing.", UNIT(service)->id);
+                        return -EBUSY;
+                }
+
+#ifdef HAVE_SYSV_COMPAT
+                if (service->sysv_path) {
+                        log_error("Using SysV services for socket activation is not supported. Refusing.");
+                        return -ENOENT;
+                }
+#endif
+        }
+
+        assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
+
+        s->result = SOCKET_SUCCESS;
+        socket_enter_start_pre(s);
+        return 0;
+}
+
+static int socket_stop(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+
+        /* 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_SIGKILL)
+                return 0;
+
+        /* If there's already something running we go directly into
+         * kill mode. */
+        if (s->state == SOCKET_START_PRE ||
+            s->state == SOCKET_START_POST) {
+                socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_SUCCESS);
+                return -EAGAIN;
+        }
+
+        assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
+
+        socket_enter_stop_pre(s, SOCKET_SUCCESS);
+        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, "result", socket_result_to_string(s->result));
+        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", "%lu", (unsigned long) 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;
+
+                        if (socket_address_family(&p->address) == AF_NETLINK)
+                                unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t);
+                        else
+                                unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t);
+                        free(t);
+                } else if (p->type == SOCKET_SPECIAL)
+                        unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path);
+                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);
+
+        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, "result")) {
+                SocketResult f;
+
+                f = socket_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != SOCKET_SUCCESS)
+                        s->result = f;
+
+        } else if (streq(key, "n-accepted")) {
+                unsigned k;
+
+                if (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")) {
+                pid_t pid;
+
+                if (parse_pid(value, &pid) < 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        s->control_pid = 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 (p->type == SOCKET_FIFO &&
+                                    streq_ptr(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, "special")) {
+                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 special value %s", value);
+                else {
+
+                        LIST_FOREACH(port, p, s->ports)
+                                if (p->type == SOCKET_SPECIAL &&
+                                    streq_ptr(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, type, skip = 0;
+                SocketPort *p;
+
+                if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 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, type))
+                                        break;
+
+                        if (p) {
+                                if (p->fd >= 0)
+                                        close_nointr_nofail(p->fd);
+                                p->fd = fdset_remove(fds, fd);
+                        }
+                }
+
+        } else if (streq(key, "netlink")) {
+                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_netlink(&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 bool socket_check_gc(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(u);
+
+        return s->n_connections > 0;
+}
+
+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);
+
+        if (s->state != SOCKET_LISTENING)
+                return;
+
+        log_debug("Incoming traffic on %s", u->id);
+
+        if (events != EPOLLIN) {
+
+                if (events & EPOLLHUP)
+                        log_error("%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.", u->id);
+                else
+                        log_error("%s: Got unexpected poll event (0x%x) on socket.", u->id, events);
+
+                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_apply_socket_options(s, cfd);
+        }
+
+        socket_enter_running(s, cfd);
+        return;
+
+fail:
+        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+}
+
+static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+        Socket *s = SOCKET(u);
+        SocketResult f;
+
+        assert(s);
+        assert(pid >= 0);
+
+        if (pid != s->control_pid)
+                return;
+
+        s->control_pid = 0;
+
+        if (is_clean_exit(code, status))
+                f = SOCKET_SUCCESS;
+        else if (code == CLD_EXITED)
+                f = SOCKET_FAILURE_EXIT_CODE;
+        else if (code == CLD_KILLED)
+                f = SOCKET_FAILURE_SIGNAL;
+        else if (code == CLD_DUMPED)
+                f = SOCKET_FAILURE_CORE_DUMP;
+        else
+                assert_not_reached("Unknown code");
+
+        if (s->control_command) {
+                exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
+
+                if (s->control_command->ignore)
+                        f = SOCKET_SUCCESS;
+        }
+
+        log_full(f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+                 "%s control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
+
+        if (f != SOCKET_SUCCESS)
+                s->result = f;
+
+        if (s->control_command &&
+            s->control_command->command_next &&
+            f == SOCKET_SUCCESS) {
+
+                log_debug("%s running next command for state %s", u->id, socket_state_to_string(s->state));
+                socket_run_next(s);
+        } 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->id, socket_state_to_string(s->state));
+
+                switch (s->state) {
+
+                case SOCKET_START_PRE:
+                        if (f == SOCKET_SUCCESS)
+                                socket_enter_start_post(s);
+                        else
+                                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, f);
+                        break;
+
+                case SOCKET_START_POST:
+                        if (f == SOCKET_SUCCESS)
+                                socket_enter_listening(s);
+                        else
+                                socket_enter_stop_pre(s, f);
+                        break;
+
+                case SOCKET_STOP_PRE:
+                case SOCKET_STOP_PRE_SIGTERM:
+                case SOCKET_STOP_PRE_SIGKILL:
+                        socket_enter_stop_post(s, f);
+                        break;
+
+                case SOCKET_STOP_POST:
+                case SOCKET_FINAL_SIGTERM:
+                case SOCKET_FINAL_SIGKILL:
+                        socket_enter_dead(s, f);
+                        break;
+
+                default:
+                        assert_not_reached("Uh, control process died at wrong time.");
+                }
+        }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
+}
+
+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->id);
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
+                break;
+
+        case SOCKET_START_POST:
+                log_warning("%s starting timed out. Stopping.", u->id);
+                socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
+                break;
+
+        case SOCKET_STOP_PRE:
+                log_warning("%s stopping timed out. Terminating.", u->id);
+                socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT);
+                break;
+
+        case SOCKET_STOP_PRE_SIGTERM:
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s stopping timed out. Killing.", u->id);
+                        socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s stopping timed out. Skipping SIGKILL. Ignoring.", u->id);
+                        socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case SOCKET_STOP_PRE_SIGKILL:
+                log_warning("%s still around after SIGKILL. Ignoring.", u->id);
+                socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
+                break;
+
+        case SOCKET_STOP_POST:
+                log_warning("%s stopping timed out (2). Terminating.", u->id);
+                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
+                break;
+
+        case SOCKET_FINAL_SIGTERM:
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s stopping timed out (2). Killing.", u->id);
+                        socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s stopping timed out (2). Skipping SIGKILL. Ignoring.", u->id);
+                        socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case SOCKET_FINAL_SIGKILL:
+                log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id);
+                socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
+                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 (rn_fds <= 0) {
+                *fds = NULL;
+                *n_fds = 0;
+                return 0;
+        }
+
+        if (!(rfds = new(int, rn_fds)))
+                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, bool failed_permanent) {
+        assert(s);
+
+        /* The service is dead. Dang!
+         *
+         * This is strictly for one-instance-for-all-connections
+         * services. */
+
+        if (s->state == SOCKET_RUNNING) {
+                log_debug("%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
+                if (failed_permanent)
+                        socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
+                else
+                        socket_enter_listening(s);
+        }
+}
+
+void socket_connection_unref(Socket *s) {
+        assert(s);
+
+        /* The service is dead. Yay!
+         *
+         * This is strictly for one-instance-per-connection
+         * services. */
+
+        assert(s->n_connections > 0);
+        s->n_connections--;
+
+        log_debug("%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
+}
+
+static void socket_reset_failed(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+
+        if (s->state == SOCKET_FAILED)
+                socket_set_state(s, SOCKET_DEAD);
+
+        s->result = SOCKET_SUCCESS;
+}
+
+static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Socket *s = SOCKET(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Socket units have no main processes");
+                return -ESRCH;
+        }
+
+        if (s->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ESRCH;
+        }
+
+        if (who == KILL_CONTROL || who == KILL_ALL)
+                if (s->control_pid > 0)
+                        if (kill(s->control_pid, signo) < 0)
+                                r = -errno;
+
+        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control pid from being killed via the cgroup */
+                if (s->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
+                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
+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_FAILED] = "failed"
+};
+
+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);
+
+static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
+        [SOCKET_SUCCESS] = "success",
+        [SOCKET_FAILURE_RESOURCES] = "resources",
+        [SOCKET_FAILURE_TIMEOUT] = "timeout",
+        [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
+        [SOCKET_FAILURE_SIGNAL] = "signal",
+        [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+        [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
+
+const UnitVTable socket_vtable = {
+        .suffix = ".socket",
+        .object_size = sizeof(Socket),
+        .sections =
+                "Unit\0"
+                "Socket\0"
+                "Install\0",
+
+        .init = socket_init,
+        .done = socket_done,
+        .load = socket_load,
+
+        .kill = socket_kill,
+
+        .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,
+
+        .check_gc = socket_check_gc,
+
+        .fd_event = socket_fd_event,
+        .sigchld_event = socket_sigchld_event,
+        .timer_event = socket_timer_event,
+
+        .reset_failed = socket_reset_failed,
+
+        .bus_interface = "org.freedesktop.systemd1.Socket",
+        .bus_message_handler = bus_socket_message_handler,
+        .bus_invalidating_properties =  bus_socket_invalidating_properties
+};
diff --git a/src/core/socket.h b/src/core/socket.h
new file mode 100644
index 0000000..6470d8b
--- /dev/null
+++ b/src/core/socket.h
@@ -0,0 +1,173 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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"
+#include "service.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_FAILED,
+        _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_SPECIAL,
+        SOCKET_MQUEUE,
+        _SOCKET_FIFO_MAX,
+        _SOCKET_FIFO_INVALID = -1
+} SocketType;
+
+typedef enum SocketResult {
+        SOCKET_SUCCESS,
+        SOCKET_FAILURE_RESOURCES,
+        SOCKET_FAILURE_TIMEOUT,
+        SOCKET_FAILURE_EXIT_CODE,
+        SOCKET_FAILURE_SIGNAL,
+        SOCKET_FAILURE_CORE_DUMP,
+        SOCKET_FAILURE_SERVICE_FAILED_PERMANENT,
+        _SOCKET_RESULT_MAX,
+        _SOCKET_RESULT_INVALID = -1
+} SocketResult;
+
+typedef struct SocketPort {
+        SocketType type;
+        int fd;
+
+        SocketAddress address;
+        char *path;
+        Watch fd_watch;
+
+        LIST_FIELDS(struct SocketPort, port);
+} SocketPort;
+
+struct Socket {
+        Unit meta;
+
+        LIST_HEAD(SocketPort, ports);
+
+        unsigned n_accepted;
+        unsigned n_connections;
+        unsigned max_connections;
+
+        unsigned backlog;
+        usec_t timeout_usec;
+
+        ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        /* For Accept=no sockets refers to the one service we'll
+        activate. For Accept=yes sockets is either NULL, or filled
+        when the next service we spawn. */
+        UnitRef service;
+
+        SocketState state, deserialized_state;
+
+        Watch timer_watch;
+
+        ExecCommand* control_command;
+        SocketExecCommand control_command_id;
+        pid_t control_pid;
+
+        mode_t directory_mode;
+        mode_t socket_mode;
+
+        SocketResult result;
+
+        bool accept;
+
+        /* Socket options */
+        bool keep_alive;
+        bool free_bind;
+        bool transparent;
+        bool broadcast;
+        bool pass_cred;
+        bool pass_sec;
+        int priority;
+        int mark;
+        size_t receive_buffer;
+        size_t send_buffer;
+        int ip_tos;
+        int ip_ttl;
+        size_t pipe_size;
+        char *bind_to_device;
+        char *tcp_congestion;
+        long mq_maxmsg;
+        long mq_msgsize;
+
+        /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
+        SocketAddressBindIPv6Only bind_ipv6_only;
+};
+
+/* 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, bool failed_permanent);
+
+/* 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);
+
+/* Called from the service code when a per-connection service ended */
+void socket_connection_unref(Socket *s);
+
+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);
+
+const char* socket_result_to_string(SocketResult i);
+SocketResult socket_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/spawn-agent.h b/src/core/spawn-agent.h
new file mode 100644
index 0000000..fd0a910
--- /dev/null
+++ b/src/core/spawn-agent.h
@@ -0,0 +1,28 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foospawnagenthfoo
+#define foospawnagenthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 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/>.
+***/
+
+void agent_open(void);
+void agent_close(void);
+
+#endif
diff --git a/src/core/special.h b/src/core/special.h
new file mode 100644
index 0000000..43e2e6f
--- /dev/null
+++ b/src/core/special.h
@@ -0,0 +1,88 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foospecialhfoo
+#define foospecialhfoo
+
+/***
+  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/>.
+***/
+
+#define SPECIAL_DEFAULT_TARGET "default.target"
+
+/* Shutdown targets */
+#define SPECIAL_UMOUNT_TARGET "umount.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_HALT_TARGET "halt.target"
+#define SPECIAL_POWEROFF_TARGET "poweroff.target"
+#define SPECIAL_REBOOT_TARGET "reboot.target"
+#define SPECIAL_KEXEC_TARGET "kexec.target"
+#define SPECIAL_EXIT_TARGET "exit.target"
+
+/* Special boot targets */
+#define SPECIAL_RESCUE_TARGET "rescue.target"
+#define SPECIAL_EMERGENCY_TARGET "emergency.target"
+
+/* Early boot targets */
+#define SPECIAL_SYSINIT_TARGET "sysinit.target"
+#define SPECIAL_SOCKETS_TARGET "sockets.target"
+#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"         /* LSB's $local_fs */
+#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
+#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target"       /* LSB's $remote_fs */
+#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
+#define SPECIAL_SWAP_TARGET "swap.target"
+#define SPECIAL_BASIC_TARGET "basic.target"
+
+/* LSB compatibility */
+#define SPECIAL_NETWORK_TARGET "network.target"           /* LSB's $network */
+#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"             /* LSB's $syslog */
+#define SPECIAL_TIME_SYNC_TARGET "time-sync.target"       /* LSB's $time */
+#define SPECIAL_DISPLAY_MANAGER_SERVICE "display-manager.service"       /* Debian's $x-display-manager */
+#define SPECIAL_MAIL_TRANSFER_AGENT_TARGET "mail-transfer-agent.target" /* Debian's $mail-{transport|transfer-agent */
+#define SPECIAL_HTTP_DAEMON_TARGET "http-daemon.target"
+
+/* Magic early boot services */
+#define SPECIAL_FSCK_SERVICE "fsck at .service"
+#define SPECIAL_QUOTACHECK_SERVICE "quotacheck.service"
+#define SPECIAL_QUOTAON_SERVICE "quotaon.service"
+#define SPECIAL_REMOUNT_ROOTFS_SERVICE "remount-rootfs.service"
+
+/* Services systemd relies on */
+#define SPECIAL_DBUS_SERVICE "dbus.service"
+#define SPECIAL_DBUS_SOCKET "dbus.socket"
+#define SPECIAL_JOURNALD_SOCKET "systemd-journald.socket"
+#define SPECIAL_JOURNALD_SERVICE "systemd-journald.service"
+
+/* Magic init signals */
+#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
+#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
+#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
+
+/* For SysV compatibility. Usually an alias for a saner target. On
+ * SysV-free systems this doesn't exist. */
+#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target"
+#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
+#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
+#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
+
+#endif
diff --git a/src/core/swap.c b/src/core/swap.c
new file mode 100644
index 0000000..9c72732
--- /dev/null
+++ b/src/core/swap.c
@@ -0,0 +1,1415 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <libudev.h>
+
+#include "unit.h"
+#include "swap.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "unit-name.h"
+#include "dbus-swap.h"
+#include "special.h"
+#include "bus-errors.h"
+#include "exit-status.h"
+#include "def.h"
+
+static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
+        [SWAP_DEAD] = UNIT_INACTIVE,
+        [SWAP_ACTIVATING] = UNIT_ACTIVATING,
+        [SWAP_ACTIVE] = UNIT_ACTIVE,
+        [SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
+        [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
+        [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
+        [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
+        [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
+        [SWAP_FAILED] = UNIT_FAILED
+};
+
+static void swap_unset_proc_swaps(Swap *s) {
+        Swap *first;
+
+        assert(s);
+
+        if (!s->parameters_proc_swaps.what)
+                return;
+
+        /* Remove this unit from the chain of swaps which share the
+         * same kernel swap device. */
+
+        first = hashmap_get(UNIT(s)->manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what);
+        LIST_REMOVE(Swap, same_proc_swaps, first, s);
+
+        if (first)
+                hashmap_remove_and_replace(UNIT(s)->manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what, first->parameters_proc_swaps.what, first);
+        else
+                hashmap_remove(UNIT(s)->manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what);
+
+        free(s->parameters_proc_swaps.what);
+        s->parameters_proc_swaps.what = NULL;
+}
+
+static void swap_init(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(UNIT(s)->load_state == UNIT_STUB);
+
+        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+
+        exec_context_init(&s->exec_context);
+        s->exec_context.std_output = u->manager->default_std_output;
+        s->exec_context.std_error = u->manager->default_std_error;
+
+        s->parameters_etc_fstab.priority = s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
+
+        s->timer_watch.type = WATCH_INVALID;
+
+        s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
+
+        UNIT(s)->ignore_on_isolate = true;
+}
+
+static void swap_unwatch_control_pid(Swap *s) {
+        assert(s);
+
+        if (s->control_pid <= 0)
+                return;
+
+        unit_unwatch_pid(UNIT(s), s->control_pid);
+        s->control_pid = 0;
+}
+
+static void swap_done(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        swap_unset_proc_swaps(s);
+
+        free(s->what);
+        s->what = NULL;
+
+        free(s->parameters_etc_fstab.what);
+        free(s->parameters_fragment.what);
+        s->parameters_etc_fstab.what = s->parameters_fragment.what = NULL;
+
+        exec_context_done(&s->exec_context);
+        exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
+        s->control_command = NULL;
+
+        swap_unwatch_control_pid(s);
+
+        unit_unwatch_timer(u, &s->timer_watch);
+}
+
+int swap_add_one_mount_link(Swap *s, Mount *m) {
+         int r;
+
+        assert(s);
+        assert(m);
+
+        if (UNIT(s)->load_state != UNIT_LOADED ||
+            UNIT(m)->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_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
+                return r;
+
+        return 0;
+}
+
+static int swap_add_mount_links(Swap *s) {
+        Unit *other;
+        int r;
+
+        assert(s);
+
+        LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_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(UNIT(s)->manager, SPECIAL_SWAP_TARGET, NULL, NULL, &tu)) < 0)
+                return r;
+
+        if (!p->noauto &&
+            !p->nofail &&
+            (p->handle || UNIT(s)->manager->swap_auto) &&
+            s->from_etc_fstab &&
+            UNIT(s)->manager->running_as == MANAGER_SYSTEM)
+                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_add_device_links(Swap *s) {
+        SwapParameters *p;
+
+        assert(s);
+
+        if (!s->what)
+                return 0;
+
+        if (s->from_fragment)
+                p = &s->parameters_fragment;
+        else if (s->from_etc_fstab)
+                p = &s->parameters_etc_fstab;
+        else
+                return 0;
+
+        if (is_device_path(s->what))
+                return unit_add_node_link(UNIT(s), s->what,
+                                          !p->noauto && p->nofail &&
+                                          UNIT(s)->manager->running_as == MANAGER_SYSTEM);
+        else
+                /* File based swap devices need to be ordered after
+                 * remount-rootfs.service, since they might need a
+                 * writable file system. */
+                return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_ROOTFS_SERVICE, NULL, true);
+}
+
+static int swap_add_default_dependencies(Swap *s) {
+        int r;
+
+        assert(s);
+
+        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int swap_verify(Swap *s) {
+        bool b;
+        char *e;
+
+        if (UNIT(s)->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)->id);
+                return -EINVAL;
+        }
+
+        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int swap_load(Unit *u) {
+        int r;
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(u->load_state == UNIT_STUB);
+
+        /* Load a .swap file */
+        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
+                return r;
+
+        if (u->load_state == UNIT_LOADED) {
+                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
+                        return r;
+
+                if (UNIT(s)->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->id);
+
+                        if (!s->what)
+                                return -ENOMEM;
+                }
+
+                path_kill_slashes(s->what);
+
+                if (!UNIT(s)->description)
+                        if ((r = unit_set_description(u, s->what)) < 0)
+                                return r;
+
+                if ((r = swap_add_device_links(s)) < 0)
+                        return r;
+
+                if ((r = swap_add_mount_links(s)) < 0)
+                        return r;
+
+                if ((r = swap_add_target_links(s)) < 0)
+                        return r;
+
+                if ((r = unit_add_default_cgroups(u)) < 0)
+                        return r;
+
+                if (UNIT(s)->default_dependencies)
+                        if ((r = swap_add_default_dependencies(s)) < 0)
+                                return r;
+        }
+
+        return swap_verify(s);
+}
+
+int swap_add_one(
+                Manager *m,
+                const char *what,
+                const char *what_proc_swaps,
+                int priority,
+                bool noauto,
+                bool nofail,
+                bool handle,
+                bool set_flags) {
+
+        Unit *u = NULL;
+        char *e = NULL, *wp = NULL;
+        bool delete = false;
+        int r;
+        SwapParameters *p;
+
+        assert(m);
+        assert(what);
+
+        e = unit_name_from_path(what, ".swap");
+        if (!e)
+                return -ENOMEM;
+
+        u = manager_get_unit(m, e);
+
+        if (what_proc_swaps &&
+            u &&
+            SWAP(u)->from_proc_swaps &&
+            !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
+                return -EEXIST;
+
+        if (!u) {
+                delete = true;
+
+                u = unit_new(m, sizeof(Swap));
+                if (!u) {
+                        free(e);
+                        return -ENOMEM;
+                }
+
+                r = unit_add_name(u, e);
+                if (r < 0)
+                        goto fail;
+
+                SWAP(u)->what = strdup(what);
+                if (!SWAP(u)->what) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                unit_add_to_load_queue(u);
+        } else
+                delete = false;
+
+        if (what_proc_swaps) {
+                Swap *first;
+
+                p = &SWAP(u)->parameters_proc_swaps;
+
+                if (!p->what) {
+                        if (!(wp = strdup(what_proc_swaps))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        if (!m->swaps_by_proc_swaps)
+                                if (!(m->swaps_by_proc_swaps = hashmap_new(string_hash_func, string_compare_func))) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                        free(p->what);
+                        p->what = wp;
+
+                        first = hashmap_get(m->swaps_by_proc_swaps, wp);
+                        LIST_PREPEND(Swap, same_proc_swaps, first, SWAP(u));
+
+                        if ((r = hashmap_replace(m->swaps_by_proc_swaps, wp, first)) < 0)
+                                goto fail;
+                }
+
+                if (set_flags) {
+                        SWAP(u)->is_active = true;
+                        SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
+                }
+
+                SWAP(u)->from_proc_swaps = true;
+
+        } else {
+                p = &SWAP(u)->parameters_etc_fstab;
+
+                if (!(wp = strdup(what))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                free(p->what);
+                p->what = wp;
+
+                SWAP(u)->from_etc_fstab = true;
+        }
+
+        p->priority = priority;
+        p->noauto = noauto;
+        p->nofail = nofail;
+        p->handle = handle;
+
+        unit_add_to_dbus_queue(u);
+
+        free(e);
+
+        return 0;
+
+fail:
+        log_warning("Failed to load swap unit: %s", strerror(-r));
+
+        free(wp);
+        free(e);
+
+        if (delete && u)
+                unit_free(u);
+
+        return r;
+}
+
+static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) {
+        struct stat st;
+        int r = 0, k;
+
+        assert(m);
+
+        if (stat(device, &st) >= 0 && S_ISBLK(st.st_mode)) {
+                struct udev_device *d;
+                const char *dn;
+                struct udev_list_entry *item = NULL, *first = NULL;
+
+                /* So this is a proper swap device. Create swap units
+                 * for all names this swap device is known under */
+
+                if (!(d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev)))
+                        return -ENOMEM;
+
+                if ((dn = udev_device_get_devnode(d)))
+                        r = swap_add_one(m, dn, device, prio, false, false, false, set_flags);
+
+                /* Add additional units for all symlinks */
+                first = udev_device_get_devlinks_list_entry(d);
+                udev_list_entry_foreach(item, first) {
+                        const char *p;
+
+                        /* Don't bother with the /dev/block links */
+                        p = udev_list_entry_get_name(item);
+
+                        if (path_startswith(p, "/dev/block/"))
+                                continue;
+
+                        if (stat(p, &st) >= 0)
+                                if ((!S_ISBLK(st.st_mode)) || st.st_rdev != udev_device_get_devnum(d))
+                                        continue;
+
+                        if ((k = swap_add_one(m, p, device, prio, false, false, false, set_flags)) < 0)
+                                r = k;
+                }
+
+                udev_device_unref(d);
+        }
+
+        if ((k = swap_add_one(m, device, device, prio, false, false, false, set_flags)) < 0)
+                r = k;
+
+        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 != SWAP_ACTIVATING &&
+            state != SWAP_ACTIVATING_SIGTERM &&
+            state != SWAP_ACTIVATING_SIGKILL &&
+            state != SWAP_DEACTIVATING &&
+            state != SWAP_DEACTIVATING_SIGTERM &&
+            state != SWAP_DEACTIVATING_SIGKILL) {
+                unit_unwatch_timer(UNIT(s), &s->timer_watch);
+                swap_unwatch_control_pid(s);
+                s->control_command = NULL;
+                s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
+        }
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(s)->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], true);
+}
+
+static int swap_coldplug(Unit *u) {
+        Swap *s = SWAP(u);
+        SwapState new_state = SWAP_DEAD;
+        int r;
+
+        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) {
+
+                if (new_state == SWAP_ACTIVATING ||
+                    new_state == SWAP_ACTIVATING_SIGTERM ||
+                    new_state == SWAP_ACTIVATING_SIGKILL ||
+                    new_state == SWAP_DEACTIVATING ||
+                    new_state == SWAP_DEACTIVATING_SIGTERM ||
+                    new_state == SWAP_DEACTIVATING_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;
+                }
+
+                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"
+                "%sResult: %s\n"
+                "%sWhat: %s\n"
+                "%sPriority: %i\n"
+                "%sNoAuto: %s\n"
+                "%sNoFail: %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, swap_result_to_string(s->result),
+                prefix, s->what,
+                prefix, p->priority,
+                prefix, yes_no(p->noauto),
+                prefix, yes_no(p->nofail),
+                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));
+
+        if (s->control_pid > 0)
+                fprintf(f,
+                        "%sControl PID: %lu\n",
+                        prefix, (unsigned long) s->control_pid);
+
+        exec_context_dump(&s->exec_context, f, prefix);
+}
+
+static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
+        pid_t pid;
+        int r;
+
+        assert(s);
+        assert(c);
+        assert(_pid);
+
+        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                goto fail;
+
+        if ((r = exec_spawn(c,
+                            NULL,
+                            &s->exec_context,
+                            NULL, 0,
+                            UNIT(s)->manager->environment,
+                            true,
+                            true,
+                            true,
+                            UNIT(s)->manager->confirm_spawn,
+                            UNIT(s)->cgroup_bondings,
+                            UNIT(s)->cgroup_attributes,
+                            &pid)) < 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 swap_enter_dead(Swap *s, SwapResult f) {
+        assert(s);
+
+        if (f != SWAP_SUCCESS)
+                s->result = f;
+
+        swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
+}
+
+static void swap_enter_active(Swap *s, SwapResult f) {
+        assert(s);
+
+        if (f != SWAP_SUCCESS)
+                s->result = f;
+
+        swap_set_state(s, SWAP_ACTIVE);
+}
+
+static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
+        int r;
+        Set *pid_set = NULL;
+        bool wait_for_exit = false;
+
+        assert(s);
+
+        if (f != SWAP_SUCCESS)
+                s->result = f;
+
+        if (s->exec_context.kill_mode != KILL_NONE) {
+                int sig = (state == SWAP_ACTIVATING_SIGTERM ||
+                           state == SWAP_DEACTIVATING_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
+
+                if (s->control_pid > 0) {
+                        if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
+
+                                log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
+                        else
+                                wait_for_exit = true;
+                }
+
+                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+
+                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        /* Exclude the control pid from being killed via the cgroup */
+                        if (s->control_pid > 0)
+                                if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
+                                        goto fail;
+
+                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
+                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                        log_warning("Failed to kill control group: %s", strerror(-r));
+                        } else if (r > 0)
+                                wait_for_exit = true;
+
+                        set_free(pid_set);
+                        pid_set = NULL;
+                }
+        }
+
+        if (wait_for_exit) {
+                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                        goto fail;
+
+                swap_set_state(s, state);
+        } else
+                swap_enter_dead(s, SWAP_SUCCESS);
+
+        return;
+
+fail:
+        log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
+
+        swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
+
+        if (pid_set)
+                set_free(pid_set);
+}
+
+static void swap_enter_activating(Swap *s) {
+        int r, priority;
+
+        assert(s);
+
+        s->control_command_id = SWAP_EXEC_ACTIVATE;
+        s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
+
+        if (s->from_fragment)
+                priority = s->parameters_fragment.priority;
+        else if (s->from_etc_fstab)
+                priority = s->parameters_etc_fstab.priority;
+        else
+                priority = -1;
+
+        if (priority >= 0) {
+                char p[LINE_MAX];
+
+                snprintf(p, sizeof(p), "%i", priority);
+                char_array_0(p);
+
+                r = exec_command_set(
+                                s->control_command,
+                                "/sbin/swapon",
+                                "-p",
+                                p,
+                                s->what,
+                                NULL);
+        } else
+                r = exec_command_set(
+                                s->control_command,
+                                "/sbin/swapon",
+                                s->what,
+                                NULL);
+
+        if (r < 0)
+                goto fail;
+
+        swap_unwatch_control_pid(s);
+
+        if ((r = swap_spawn(s, s->control_command, &s->control_pid)) < 0)
+                goto fail;
+
+        swap_set_state(s, SWAP_ACTIVATING);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'swapon' task: %s", UNIT(s)->id, strerror(-r));
+        swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
+}
+
+static void swap_enter_deactivating(Swap *s) {
+        int r;
+
+        assert(s);
+
+        s->control_command_id = SWAP_EXEC_DEACTIVATE;
+        s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE;
+
+        if ((r = exec_command_set(
+                             s->control_command,
+                             "/sbin/swapoff",
+                             s->what,
+                             NULL)) < 0)
+                goto fail;
+
+        swap_unwatch_control_pid(s);
+
+        if ((r = swap_spawn(s, s->control_command, &s->control_pid)) < 0)
+                goto fail;
+
+        swap_set_state(s, SWAP_DEACTIVATING);
+
+        return;
+
+fail:
+        log_warning("%s failed to run 'swapoff' task: %s", UNIT(s)->id, strerror(-r));
+        swap_enter_active(s, SWAP_FAILURE_RESOURCES);
+}
+
+static int swap_start(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        /* We cannot fulfill this request right now, try again later
+         * please! */
+
+        if (s->state == SWAP_DEACTIVATING ||
+            s->state == SWAP_DEACTIVATING_SIGTERM ||
+            s->state == SWAP_DEACTIVATING_SIGKILL ||
+            s->state == SWAP_ACTIVATING_SIGTERM ||
+            s->state == SWAP_ACTIVATING_SIGKILL)
+                return -EAGAIN;
+
+        if (s->state == SWAP_ACTIVATING)
+                return 0;
+
+        assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED);
+
+        s->result = SWAP_SUCCESS;
+        swap_enter_activating(s);
+        return 0;
+}
+
+static int swap_stop(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        if (s->state == SWAP_DEACTIVATING ||
+            s->state == SWAP_DEACTIVATING_SIGTERM ||
+            s->state == SWAP_DEACTIVATING_SIGKILL ||
+            s->state == SWAP_ACTIVATING_SIGTERM ||
+            s->state == SWAP_ACTIVATING_SIGKILL)
+                return 0;
+
+        assert(s->state == SWAP_ACTIVATING ||
+               s->state == SWAP_ACTIVE);
+
+        swap_enter_deactivating(s);
+        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));
+        unit_serialize_item(u, f, "result", swap_result_to_string(s->result));
+
+        if (s->control_pid > 0)
+                unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid);
+
+        if (s->control_command_id >= 0)
+                unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id));
+
+        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 if (streq(key, "result")) {
+                SwapResult f;
+
+                f = swap_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != SWAP_SUCCESS)
+                        s->result = f;
+        } else if (streq(key, "control-pid")) {
+                pid_t pid;
+
+                if (parse_pid(value, &pid) < 0)
+                        log_debug("Failed to parse control-pid value %s", value);
+                else
+                        s->control_pid = pid;
+
+        } else if (streq(key, "control-command")) {
+                SwapExecCommand id;
+
+                if ((id = swap_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
+                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 void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+        Swap *s = SWAP(u);
+        SwapResult f;
+
+        assert(s);
+        assert(pid >= 0);
+
+        if (pid != s->control_pid)
+                return;
+
+        s->control_pid = 0;
+
+        if (is_clean_exit(code, status))
+                f = SWAP_SUCCESS;
+        else if (code == CLD_EXITED)
+                f = SWAP_FAILURE_EXIT_CODE;
+        else if (code == CLD_KILLED)
+                f = SWAP_FAILURE_SIGNAL;
+        else if (code == CLD_DUMPED)
+                f = SWAP_FAILURE_CORE_DUMP;
+        else
+                assert_not_reached("Unknown code");
+
+        if (f != SWAP_SUCCESS)
+                s->result = f;
+
+        if (s->control_command) {
+                exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
+
+                s->control_command = NULL;
+                s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
+        }
+
+        log_full(f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+                 "%s swap process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
+
+        switch (s->state) {
+
+        case SWAP_ACTIVATING:
+        case SWAP_ACTIVATING_SIGTERM:
+        case SWAP_ACTIVATING_SIGKILL:
+
+                if (f == SWAP_SUCCESS)
+                        swap_enter_active(s, f);
+                else
+                        swap_enter_dead(s, f);
+                break;
+
+        case SWAP_DEACTIVATING:
+        case SWAP_DEACTIVATING_SIGKILL:
+        case SWAP_DEACTIVATING_SIGTERM:
+
+                if (f == SWAP_SUCCESS)
+                        swap_enter_dead(s, f);
+                else
+                        swap_enter_dead(s, f);
+                break;
+
+        default:
+                assert_not_reached("Uh, control process died at wrong time.");
+        }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
+
+        /* Request a reload of /proc/swaps, so that following units
+         * can follow our state change */
+        u->manager->request_reload = true;
+}
+
+static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+        assert(elapsed == 1);
+        assert(w == &s->timer_watch);
+
+        switch (s->state) {
+
+        case SWAP_ACTIVATING:
+                log_warning("%s activation timed out. Stopping.", u->id);
+                swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
+                break;
+
+        case SWAP_DEACTIVATING:
+                log_warning("%s deactivation timed out. Stopping.", u->id);
+                swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
+                break;
+
+        case SWAP_ACTIVATING_SIGTERM:
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s activation timed out. Killing.", u->id);
+                        swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s activation timed out. Skipping SIGKILL. Ignoring.", u->id);
+                        swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case SWAP_DEACTIVATING_SIGTERM:
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s deactivation timed out. Killing.", u->id);
+                        swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
+                } else {
+                        log_warning("%s deactivation timed out. Skipping SIGKILL. Ignoring.", u->id);
+                        swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
+                }
+                break;
+
+        case SWAP_ACTIVATING_SIGKILL:
+        case SWAP_DEACTIVATING_SIGKILL:
+                log_warning("%s swap process still around after SIGKILL. Ignoring.", u->id);
+                swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
+                break;
+
+        default:
+                assert_not_reached("Timeout at wrong time.");
+        }
+}
+
+static int swap_load_proc_swaps(Manager *m, bool set_flags) {
+        unsigned i;
+        int r = 0;
+
+        assert(m);
+
+        rewind(m->proc_swaps);
+
+        (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
+
+        for (i = 1;; i++) {
+                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;
+
+                        log_warning("Failed to parse /proc/swaps:%u.", i);
+                        free(dev);
+                        continue;
+                }
+
+                d = cunescape(dev);
+                free(dev);
+
+                if (!d)
+                        return -ENOMEM;
+
+                k = swap_process_new_swap(m, d, prio, set_flags);
+                free(d);
+
+                if (k < 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+int swap_dispatch_reload(Manager *m) {
+        /* This function should go as soon as the kernel properly notifies us */
+
+        if (_likely_(!m->request_reload))
+                return 0;
+
+        m->request_reload = false;
+
+        return swap_fd_event(m, EPOLLPRI);
+}
+
+int swap_fd_event(Manager *m, int events) {
+        Unit *u;
+        int r;
+
+        assert(m);
+        assert(events & EPOLLPRI);
+
+        if ((r = swap_load_proc_swaps(m, true)) < 0) {
+                log_error("Failed to reread /proc/swaps: %s", strerror(-r));
+
+                /* Reset flags, just in case, for late calls */
+                LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
+                        Swap *swap = SWAP(u);
+
+                        swap->is_active = swap->just_activated = false;
+                }
+
+                return 0;
+        }
+
+        manager_dispatch_load_queue(m);
+
+        LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
+                Swap *swap = SWAP(u);
+
+                if (!swap->is_active) {
+                        /* This has just been deactivated */
+
+                        swap->from_proc_swaps = false;
+                        swap_unset_proc_swaps(swap);
+
+                        switch (swap->state) {
+
+                        case SWAP_ACTIVE:
+                                swap_enter_dead(swap, SWAP_SUCCESS);
+                                break;
+
+                        default:
+                                swap_set_state(swap, swap->state);
+                                break;
+                        }
+
+                } else if (swap->just_activated) {
+
+                        /* New swap entry */
+
+                        switch (swap->state) {
+
+                        case SWAP_DEAD:
+                        case SWAP_FAILED:
+                                swap_enter_active(swap, SWAP_SUCCESS);
+                                break;
+
+                        default:
+                                /* Nothing really changed, but let's
+                                 * issue an notification call
+                                 * nonetheless, in case somebody is
+                                 * waiting for this. */
+                                swap_set_state(swap, swap->state);
+                                break;
+                        }
+                }
+
+                /* Reset the flags for later calls */
+                swap->is_active = swap->just_activated = false;
+        }
+
+        return 1;
+}
+
+static Unit *swap_following(Unit *u) {
+        Swap *s = SWAP(u);
+        Swap *other, *first = NULL;
+
+        assert(s);
+
+        if (streq_ptr(s->what, s->parameters_proc_swaps.what))
+                return NULL;
+
+        /* Make everybody follow the unit that's named after the swap
+         * device in the kernel */
+
+        LIST_FOREACH_AFTER(same_proc_swaps, other, s)
+                if (streq_ptr(other->what, other->parameters_proc_swaps.what))
+                        return UNIT(other);
+
+        LIST_FOREACH_BEFORE(same_proc_swaps, other, s) {
+                if (streq_ptr(other->what, other->parameters_proc_swaps.what))
+                        return UNIT(other);
+
+                first = other;
+        }
+
+        return UNIT(first);
+}
+
+static int swap_following_set(Unit *u, Set **_set) {
+        Swap *s = SWAP(u);
+        Swap *other;
+        Set *set;
+        int r;
+
+        assert(s);
+        assert(_set);
+
+        if (LIST_JUST_US(same_proc_swaps, s)) {
+                *_set = NULL;
+                return 0;
+        }
+
+        if (!(set = set_new(NULL, NULL)))
+                return -ENOMEM;
+
+        LIST_FOREACH_AFTER(same_proc_swaps, other, s)
+                if ((r = set_put(set, other)) < 0)
+                        goto fail;
+
+        LIST_FOREACH_BEFORE(same_proc_swaps, other, s)
+                if ((r = set_put(set, other)) < 0)
+                        goto fail;
+
+        *_set = set;
+        return 1;
+
+fail:
+        set_free(set);
+        return r;
+}
+
+static void swap_shutdown(Manager *m) {
+        assert(m);
+
+        if (m->proc_swaps) {
+                fclose(m->proc_swaps);
+                m->proc_swaps = NULL;
+        }
+
+        hashmap_free(m->swaps_by_proc_swaps);
+        m->swaps_by_proc_swaps = NULL;
+}
+
+static int swap_enumerate(Manager *m) {
+        int r;
+        struct epoll_event ev;
+        assert(m);
+
+        if (!m->proc_swaps) {
+                if (!(m->proc_swaps = fopen("/proc/swaps", "re")))
+                        return (errno == ENOENT) ? 0 : -errno;
+
+                m->swap_watch.type = WATCH_SWAP;
+                m->swap_watch.fd = fileno(m->proc_swaps);
+
+                zero(ev);
+                ev.events = EPOLLPRI;
+                ev.data.ptr = &m->swap_watch;
+
+                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->swap_watch.fd, &ev) < 0)
+                        return -errno;
+        }
+
+        /* We rely on mount.c to load /etc/fstab for us */
+
+        if ((r = swap_load_proc_swaps(m, false)) < 0)
+                swap_shutdown(m);
+
+        return r;
+}
+
+static void swap_reset_failed(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        if (s->state == SWAP_FAILED)
+                swap_set_state(s, SWAP_DEAD);
+
+        s->result = SWAP_SUCCESS;
+}
+
+static int swap_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Swap *s = SWAP(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Swap units have no main processes");
+                return -ESRCH;
+        }
+
+        if (s->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ESRCH;
+        }
+
+        if (who == KILL_CONTROL || who == KILL_ALL)
+                if (s->control_pid > 0)
+                        if (kill(s->control_pid, signo) < 0)
+                                r = -errno;
+
+        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control pid from being killed via the cgroup */
+                if (s->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
+                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
+static const char* const swap_state_table[_SWAP_STATE_MAX] = {
+        [SWAP_DEAD] = "dead",
+        [SWAP_ACTIVATING] = "activating",
+        [SWAP_ACTIVE] = "active",
+        [SWAP_DEACTIVATING] = "deactivating",
+        [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
+        [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
+        [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
+        [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
+        [SWAP_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
+
+static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
+        [SWAP_EXEC_ACTIVATE] = "ExecActivate",
+        [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
+
+static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
+        [SWAP_SUCCESS] = "success",
+        [SWAP_FAILURE_RESOURCES] = "resources",
+        [SWAP_FAILURE_TIMEOUT] = "timeout",
+        [SWAP_FAILURE_EXIT_CODE] = "exit-code",
+        [SWAP_FAILURE_SIGNAL] = "signal",
+        [SWAP_FAILURE_CORE_DUMP] = "core-dump"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
+
+const UnitVTable swap_vtable = {
+        .suffix = ".swap",
+        .object_size = sizeof(Swap),
+        .sections =
+                "Unit\0"
+                "Swap\0"
+                "Install\0",
+
+        .no_alias = true,
+        .no_instances = true,
+        .show_status = true,
+
+        .init = swap_init,
+        .load = swap_load,
+        .done = swap_done,
+
+        .coldplug = swap_coldplug,
+
+        .dump = swap_dump,
+
+        .start = swap_start,
+        .stop = swap_stop,
+
+        .kill = swap_kill,
+
+        .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,
+
+        .sigchld_event = swap_sigchld_event,
+        .timer_event = swap_timer_event,
+
+        .reset_failed = swap_reset_failed,
+
+        .bus_interface = "org.freedesktop.systemd1.Swap",
+        .bus_message_handler = bus_swap_message_handler,
+        .bus_invalidating_properties =  bus_swap_invalidating_properties,
+
+        .following = swap_following,
+        .following_set = swap_following_set,
+
+        .enumerate = swap_enumerate,
+        .shutdown = swap_shutdown
+};
diff --git a/src/core/swap.h b/src/core/swap.h
new file mode 100644
index 0000000..62d08da
--- /dev/null
+++ b/src/core/swap.h
@@ -0,0 +1,128 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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_ACTIVATING,
+        SWAP_ACTIVE,
+        SWAP_DEACTIVATING,
+        SWAP_ACTIVATING_SIGTERM,
+        SWAP_ACTIVATING_SIGKILL,
+        SWAP_DEACTIVATING_SIGTERM,
+        SWAP_DEACTIVATING_SIGKILL,
+        SWAP_FAILED,
+        _SWAP_STATE_MAX,
+        _SWAP_STATE_INVALID = -1
+} SwapState;
+
+typedef enum SwapExecCommand {
+        SWAP_EXEC_ACTIVATE,
+        SWAP_EXEC_DEACTIVATE,
+        _SWAP_EXEC_COMMAND_MAX,
+        _SWAP_EXEC_COMMAND_INVALID = -1
+} SwapExecCommand;
+
+typedef struct SwapParameters {
+        char *what;
+        int priority;
+        bool noauto:1;
+        bool nofail:1;
+        bool handle:1;
+} SwapParameters;
+
+typedef enum SwapResult {
+        SWAP_SUCCESS,
+        SWAP_FAILURE_RESOURCES,
+        SWAP_FAILURE_TIMEOUT,
+        SWAP_FAILURE_EXIT_CODE,
+        SWAP_FAILURE_SIGNAL,
+        SWAP_FAILURE_CORE_DUMP,
+        _SWAP_RESULT_MAX,
+        _SWAP_RESULT_INVALID = -1
+} SwapResult;
+
+struct Swap {
+        Unit meta;
+
+        char *what;
+
+        SwapParameters parameters_etc_fstab;
+        SwapParameters parameters_proc_swaps;
+        SwapParameters parameters_fragment;
+
+        bool from_etc_fstab:1;
+        bool from_proc_swaps:1;
+        bool from_fragment:1;
+
+        /* Used while looking for swaps that vanished or got added
+         * from/to /proc/swaps */
+        bool is_active:1;
+        bool just_activated:1;
+
+        SwapResult result;
+
+        usec_t timeout_usec;
+
+        ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
+        ExecContext exec_context;
+
+        SwapState state, deserialized_state;
+
+        ExecCommand* control_command;
+        SwapExecCommand control_command_id;
+        pid_t control_pid;
+
+        Watch timer_watch;
+
+        /* In order to be able to distinguish dependencies on
+        different device nodes we might end up creating multiple
+        devices for the same swap. We chain them up here. */
+
+        LIST_FIELDS(struct Swap, same_proc_swaps);
+};
+
+extern const UnitVTable swap_vtable;
+
+int swap_add_one(Manager *m, const char *what, const char *what_proc_swaps, int prio, bool no_auto, bool no_fail, bool handle, bool set_flags);
+
+int swap_add_one_mount_link(Swap *s, Mount *m);
+
+int swap_dispatch_reload(Manager *m);
+int swap_fd_event(Manager *m, int events);
+
+const char* swap_state_to_string(SwapState i);
+SwapState swap_state_from_string(const char *s);
+
+const char* swap_exec_command_to_string(SwapExecCommand i);
+SwapExecCommand swap_exec_command_from_string(const char *s);
+
+const char* swap_result_to_string(SwapResult i);
+SwapResult swap_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/sysfs-show.h b/src/core/sysfs-show.h
new file mode 100644
index 0000000..9939e8b
--- /dev/null
+++ b/src/core/sysfs-show.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosysfsshowhfoo
+#define foosysfsshowhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 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 show_sysfs(const char *seat, const char *prefix, unsigned columns);
+
+#endif
diff --git a/src/core/target.c b/src/core/target.c
new file mode 100644
index 0000000..6c1e0c3
--- /dev/null
+++ b/src/core/target.c
@@ -0,0 +1,224 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <unistd.h>
+
+#include "unit.h"
+#include "target.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "dbus-target.h"
+#include "special.h"
+#include "unit-name.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)->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], true);
+}
+
+static int target_add_default_dependencies(Target *t) {
+        static const UnitDependency deps[] = {
+                UNIT_REQUIRES,
+                UNIT_REQUIRES_OVERRIDABLE,
+                UNIT_REQUISITE,
+                UNIT_REQUISITE_OVERRIDABLE,
+                UNIT_WANTS,
+                UNIT_BIND_TO
+        };
+
+        Iterator i;
+        Unit *other;
+        int r;
+        unsigned k;
+
+        assert(t);
+
+        /* Imply ordering for requirement dependencies on target
+         * units. Note that when the user created a contradicting
+         * ordering manually we won't add anything in here to make
+         * sure we don't create a loop. */
+
+        for (k = 0; k < ELEMENTSOF(deps); k++)
+                SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i)
+                        if ((r = unit_add_default_target_dependency(other, UNIT(t))) < 0)
+                                return r;
+
+        /* Make sure targets are unloaded on shutdown */
+        return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
+static int target_load(Unit *u) {
+        Target *t = TARGET(u);
+        int r;
+
+        assert(t);
+
+        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->load_state == UNIT_LOADED) {
+                if (u->default_dependencies)
+                        if ((r = target_add_default_dependencies(t)) < 0)
+                                return r;
+        }
+
+        return 0;
+}
+
+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);
+}
+
+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",
+        .object_size = sizeof(Target),
+        .sections =
+                "Unit\0"
+                "Target\0"
+                "Install\0",
+
+        .load = target_load,
+        .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_interface = "org.freedesktop.systemd1.Target",
+        .bus_message_handler = bus_target_message_handler
+};
diff --git a/src/core/target.h b/src/core/target.h
new file mode 100644
index 0000000..5b97c86
--- /dev/null
+++ b/src/core/target.h
@@ -0,0 +1,47 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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 {
+        Unit meta;
+
+        TargetState state, deserialized_state;
+};
+
+extern const UnitVTable target_vtable;
+
+const char* target_state_to_string(TargetState i);
+TargetState target_state_from_string(const char *s);
+
+#endif
diff --git a/src/core/tcpwrap.c b/src/core/tcpwrap.c
new file mode 100644
index 0000000..0aab142
--- /dev/null
+++ b/src/core/tcpwrap.c
@@ -0,0 +1,68 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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/un.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include "tcpwrap.h"
+#include "log.h"
+
+bool socket_tcpwrap(int fd, const char *name) {
+#ifdef HAVE_LIBWRAP
+        struct request_info req;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_in in;
+                struct sockaddr_in6 in6;
+                struct sockaddr_un un;
+                struct sockaddr_storage storage;
+        } sa_union;
+        socklen_t l = sizeof(sa_union);
+
+        if (getsockname(fd, &sa_union.sa, &l) < 0)
+                return true;
+
+        if (sa_union.sa.sa_family != AF_INET &&
+            sa_union.sa.sa_family != AF_INET6)
+                return true;
+
+        request_init(&req,
+                     RQ_DAEMON, name,
+                     RQ_FILE, fd,
+                     NULL);
+
+        fromhost(&req);
+
+        if (!hosts_access(&req)) {
+                log_warning("Connection refused by tcpwrap.");
+                return false;
+        }
+
+        log_debug("Connection accepted by tcpwrap.");
+#endif
+        return true;
+}
diff --git a/src/core/tcpwrap.h b/src/core/tcpwrap.h
new file mode 100644
index 0000000..4d4553e
--- /dev/null
+++ b/src/core/tcpwrap.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foolibwraphfoo
+#define foolibwraphfoo
+
+/***
+  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>
+
+bool socket_tcpwrap(int fd, const char *name);
+
+#endif
diff --git a/src/core/timer.c b/src/core/timer.c
new file mode 100644
index 0000000..e318fee
--- /dev/null
+++ b/src/core/timer.c
@@ -0,0 +1,520 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 "unit-name.h"
+#include "timer.h"
+#include "dbus-timer.h"
+#include "special.h"
+#include "bus-errors.h"
+
+static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
+        [TIMER_DEAD] = UNIT_INACTIVE,
+        [TIMER_WAITING] = UNIT_ACTIVE,
+        [TIMER_RUNNING] = UNIT_ACTIVE,
+        [TIMER_ELAPSED] = UNIT_ACTIVE,
+        [TIMER_FAILED] = UNIT_FAILED
+};
+
+static void timer_init(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        t->next_elapse = (usec_t) -1;
+}
+
+static void timer_done(Unit *u) {
+        Timer *t = TIMER(u);
+        TimerValue *v;
+
+        assert(t);
+
+        while ((v = t->values)) {
+                LIST_REMOVE(TimerValue, value, t->values, v);
+                free(v);
+        }
+
+        unit_unwatch_timer(u, &t->timer_watch);
+
+        unit_ref_unset(&t->unit);
+}
+
+static int timer_verify(Timer *t) {
+        assert(t);
+
+        if (UNIT(t)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (!t->values) {
+                log_error("%s lacks value setting. Refusing.", UNIT(t)->id);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int timer_add_default_dependencies(Timer *t) {
+        int r;
+
+        assert(t);
+
+        if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
+                if ((r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
+                        return r;
+
+                if ((r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+                        return r;
+        }
+
+        return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
+static int timer_load(Unit *u) {
+        Timer *t = TIMER(u);
+        int r;
+
+        assert(u);
+        assert(u->load_state == UNIT_STUB);
+
+        if ((r = unit_load_fragment_and_dropin(u)) < 0)
+                return r;
+
+        if (u->load_state == UNIT_LOADED) {
+
+                if (!UNIT_DEREF(t->unit)) {
+                        Unit *x;
+
+                        r = unit_load_related_unit(u, ".service", &x);
+                        if (r < 0)
+                                return r;
+
+                        unit_ref_set(&t->unit, x);
+                }
+
+                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
+                if (r < 0)
+                        return r;
+
+                if (UNIT(t)->default_dependencies)
+                        if ((r = timer_add_default_dependencies(t)) < 0)
+                                return r;
+        }
+
+        return timer_verify(t);
+}
+
+static void timer_dump(Unit *u, FILE *f, const char *prefix) {
+        Timer *t = TIMER(u);
+        TimerValue *v;
+        char
+                timespan1[FORMAT_TIMESPAN_MAX];
+
+        fprintf(f,
+                "%sTimer State: %s\n"
+                "%sResult: %s\n"
+                "%sUnit: %s\n",
+                prefix, timer_state_to_string(t->state),
+                prefix, timer_result_to_string(t->result),
+                prefix, UNIT_DEREF(t->unit)->id);
+
+        LIST_FOREACH(value, v, t->values)
+                fprintf(f,
+                        "%s%s: %s\n",
+                        prefix,
+                        timer_base_to_string(v->base),
+                        strna(format_timespan(timespan1, sizeof(timespan1), v->value)));
+}
+
+static void timer_set_state(Timer *t, TimerState state) {
+        TimerState old_state;
+        assert(t);
+
+        old_state = t->state;
+        t->state = state;
+
+        if (state != TIMER_WAITING)
+                unit_unwatch_timer(UNIT(t), &t->timer_watch);
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(t)->id,
+                          timer_state_to_string(old_state),
+                          timer_state_to_string(state));
+
+        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
+}
+
+static void timer_enter_waiting(Timer *t, bool initial);
+
+static int timer_coldplug(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+        assert(t->state == TIMER_DEAD);
+
+        if (t->deserialized_state != t->state) {
+
+                if (t->deserialized_state == TIMER_WAITING)
+                        timer_enter_waiting(t, false);
+                else
+                        timer_set_state(t, t->deserialized_state);
+        }
+
+        return 0;
+}
+
+static void timer_enter_dead(Timer *t, TimerResult f) {
+        assert(t);
+
+        if (f != TIMER_SUCCESS)
+                t->result = f;
+
+        timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
+}
+
+static void timer_enter_waiting(Timer *t, bool initial) {
+        TimerValue *v;
+        usec_t base = 0, delay, n;
+        bool found = false;
+        int r;
+
+        n = now(CLOCK_MONOTONIC);
+
+        LIST_FOREACH(value, v, t->values) {
+
+                if (v->disabled)
+                        continue;
+
+                switch (v->base) {
+
+                case TIMER_ACTIVE:
+                        if (state_translation_table[t->state] == UNIT_ACTIVE)
+                                base = UNIT(t)->inactive_exit_timestamp.monotonic;
+                        else
+                                base = n;
+                        break;
+
+                case TIMER_BOOT:
+                        /* CLOCK_MONOTONIC equals the uptime on Linux */
+                        base = 0;
+                        break;
+
+                case TIMER_STARTUP:
+                        base = UNIT(t)->manager->startup_timestamp.monotonic;
+                        break;
+
+                case TIMER_UNIT_ACTIVE:
+
+                        if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0)
+                                continue;
+
+                        base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic;
+                        break;
+
+                case TIMER_UNIT_INACTIVE:
+
+                        if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0)
+                                continue;
+
+                        base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic;
+                        break;
+
+                default:
+                        assert_not_reached("Unknown timer base");
+                }
+
+                v->next_elapse = base + v->value;
+
+                if (!initial && v->next_elapse < n) {
+                        v->disabled = true;
+                        continue;
+                }
+
+                if (!found)
+                        t->next_elapse = v->next_elapse;
+                else
+                        t->next_elapse = MIN(t->next_elapse, v->next_elapse);
+
+                found = true;
+        }
+
+        if (!found) {
+                timer_set_state(t, TIMER_ELAPSED);
+                return;
+        }
+
+        delay = n < t->next_elapse ? t->next_elapse - n : 0;
+
+        if ((r = unit_watch_timer(UNIT(t), delay, &t->timer_watch)) < 0)
+                goto fail;
+
+        timer_set_state(t, TIMER_WAITING);
+        return;
+
+fail:
+        log_warning("%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
+        timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
+}
+
+static void timer_enter_running(Timer *t) {
+        DBusError error;
+        int r;
+
+        assert(t);
+        dbus_error_init(&error);
+
+        /* Don't start job if we are supposed to go down */
+        if (UNIT(t)->job && UNIT(t)->job->type == JOB_STOP)
+                return;
+
+        if ((r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL)) < 0)
+                goto fail;
+
+        timer_set_state(t, TIMER_RUNNING);
+        return;
+
+fail:
+        log_warning("%s failed to queue unit startup job: %s", UNIT(t)->id, bus_error(&error, r));
+        timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
+
+        dbus_error_free(&error);
+}
+
+static int timer_start(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+        assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
+
+        if (UNIT_DEREF(t->unit)->load_state != UNIT_LOADED)
+                return -ENOENT;
+
+        t->result = TIMER_SUCCESS;
+        timer_enter_waiting(t, true);
+        return 0;
+}
+
+static int timer_stop(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+        assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
+
+        timer_enter_dead(t, TIMER_SUCCESS);
+        return 0;
+}
+
+static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Timer *t = TIMER(u);
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
+        unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
+
+        return 0;
+}
+
+static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Timer *t = TIMER(u);
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                TimerState state;
+
+                if ((state = timer_state_from_string(value)) < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        t->deserialized_state = state;
+        } else if (streq(key, "result")) {
+                TimerResult f;
+
+                f = timer_result_from_string(value);
+                if (f < 0)
+                        log_debug("Failed to parse result value %s", value);
+                else if (f != TIMER_SUCCESS)
+                        t->result = f;
+
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+static UnitActiveState timer_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[TIMER(u)->state];
+}
+
+static const char *timer_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return timer_state_to_string(TIMER(u)->state);
+}
+
+static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+        assert(elapsed == 1);
+
+        if (t->state != TIMER_WAITING)
+                return;
+
+        log_debug("Timer elapsed on %s", u->id);
+        timer_enter_running(t);
+}
+
+void timer_unit_notify(Unit *u, UnitActiveState new_state) {
+        Iterator i;
+        Unit *k;
+
+        if (u->type == UNIT_TIMER)
+                return;
+
+        SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
+                Timer *t;
+                TimerValue *v;
+
+                if (k->type != UNIT_TIMER)
+                        continue;
+
+                if (k->load_state != UNIT_LOADED)
+                        continue;
+
+                t = TIMER(k);
+
+                /* Reenable all timers that depend on unit state */
+                LIST_FOREACH(value, v, t->values)
+                        if (v->base == TIMER_UNIT_ACTIVE ||
+                            v->base == TIMER_UNIT_INACTIVE)
+                                v->disabled = false;
+
+                switch (t->state) {
+
+                case TIMER_WAITING:
+                case TIMER_ELAPSED:
+
+                        /* Recalculate sleep time */
+                        timer_enter_waiting(t, false);
+                        break;
+
+                case TIMER_RUNNING:
+
+                        if (UNIT_IS_INACTIVE_OR_FAILED(new_state)) {
+                                log_debug("%s got notified about unit deactivation.", UNIT(t)->id);
+                                timer_enter_waiting(t, false);
+                        }
+
+                        break;
+
+                case TIMER_DEAD:
+                case TIMER_FAILED:
+                        break;
+
+                default:
+                        assert_not_reached("Unknown timer state");
+                }
+        }
+}
+
+static void timer_reset_failed(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+
+        if (t->state == TIMER_FAILED)
+                timer_set_state(t, TIMER_DEAD);
+
+        t->result = TIMER_SUCCESS;
+}
+
+static const char* const timer_state_table[_TIMER_STATE_MAX] = {
+        [TIMER_DEAD] = "dead",
+        [TIMER_WAITING] = "waiting",
+        [TIMER_RUNNING] = "running",
+        [TIMER_ELAPSED] = "elapsed",
+        [TIMER_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
+
+static const char* const timer_base_table[_TIMER_BASE_MAX] = {
+        [TIMER_ACTIVE] = "OnActiveSec",
+        [TIMER_BOOT] = "OnBootSec",
+        [TIMER_STARTUP] = "OnStartupSec",
+        [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
+        [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
+
+static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
+        [TIMER_SUCCESS] = "success",
+        [TIMER_FAILURE_RESOURCES] = "resources"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
+
+const UnitVTable timer_vtable = {
+        .suffix = ".timer",
+        .object_size = sizeof(Timer),
+        .sections =
+                "Unit\0"
+                "Timer\0"
+                "Install\0",
+
+        .init = timer_init,
+        .done = timer_done,
+        .load = timer_load,
+
+        .coldplug = timer_coldplug,
+
+        .dump = timer_dump,
+
+        .start = timer_start,
+        .stop = timer_stop,
+
+        .serialize = timer_serialize,
+        .deserialize_item = timer_deserialize_item,
+
+        .active_state = timer_active_state,
+        .sub_state_to_string = timer_sub_state_to_string,
+
+        .timer_event = timer_timer_event,
+
+        .reset_failed = timer_reset_failed,
+
+        .bus_interface = "org.freedesktop.systemd1.Timer",
+        .bus_message_handler = bus_timer_message_handler,
+        .bus_invalidating_properties =  bus_timer_invalidating_properties
+};
diff --git a/src/core/timer.h b/src/core/timer.h
new file mode 100644
index 0000000..f5c5c64
--- /dev/null
+++ b/src/core/timer.h
@@ -0,0 +1,93 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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_ELAPSED,
+        TIMER_FAILED,
+        _TIMER_STATE_MAX,
+        _TIMER_STATE_INVALID = -1
+} TimerState;
+
+typedef enum TimerBase {
+        TIMER_ACTIVE,
+        TIMER_BOOT,
+        TIMER_STARTUP,
+        TIMER_UNIT_ACTIVE,
+        TIMER_UNIT_INACTIVE,
+        _TIMER_BASE_MAX,
+        _TIMER_BASE_INVALID = -1
+} TimerBase;
+
+typedef struct TimerValue {
+        usec_t value;
+        usec_t next_elapse;
+
+        LIST_FIELDS(struct TimerValue, value);
+
+        TimerBase base;
+        bool disabled;
+} TimerValue;
+
+typedef enum TimerResult {
+        TIMER_SUCCESS,
+        TIMER_FAILURE_RESOURCES,
+        _TIMER_RESULT_MAX,
+        _TIMER_RESULT_INVALID = -1
+} TimerResult;
+
+struct Timer {
+        Unit meta;
+
+        LIST_HEAD(TimerValue, values);
+        usec_t next_elapse;
+
+        TimerState state, deserialized_state;
+        UnitRef unit;
+
+        Watch timer_watch;
+
+        TimerResult result;
+};
+
+void timer_unit_notify(Unit *u, UnitActiveState new_state);
+
+extern const UnitVTable timer_vtable;
+
+const char *timer_state_to_string(TimerState i);
+TimerState timer_state_from_string(const char *s);
+
+const char *timer_base_to_string(TimerBase i);
+TimerBase timer_base_from_string(const char *s);
+
+const char* timer_result_to_string(TimerResult i);
+TimerResult timer_result_from_string(const char *s);
+
+#endif
diff --git a/src/core/unit.c b/src/core/unit.c
new file mode 100644
index 0000000..9e33701
--- /dev/null
+++ b/src/core/unit.c
@@ -0,0 +1,2676 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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 <sys/stat.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"
+#include "special.h"
+#include "cgroup-util.h"
+#include "missing.h"
+#include "cgroup-attr.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_PATH] = &path_vtable
+};
+
+Unit *unit_new(Manager *m, size_t size) {
+        Unit *u;
+
+        assert(m);
+        assert(size >= sizeof(Unit));
+
+        u = malloc0(size);
+        if (!u)
+                return NULL;
+
+        u->names = set_new(string_hash_func, string_compare_func);
+        if (!u->names) {
+                free(u);
+                return NULL;
+        }
+
+        u->manager = m;
+        u->type = _UNIT_TYPE_INVALID;
+        u->deserialized_job = _JOB_TYPE_INVALID;
+        u->default_dependencies = true;
+        u->unit_file_state = _UNIT_FILE_STATE_INVALID;
+
+        return u;
+}
+
+bool unit_has_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        return !!set_get(u->names, (char*) name);
+}
+
+int unit_add_name(Unit *u, const char *text) {
+        UnitType t;
+        char *s, *i = NULL;
+        int r;
+
+        assert(u);
+        assert(text);
+
+        if (unit_name_is_template(text)) {
+                if (!u->instance)
+                        return -EINVAL;
+
+                s = unit_name_replace_instance(text, u->instance);
+        } else
+                s = strdup(text);
+
+        if (!s)
+                return -ENOMEM;
+
+        if (!unit_name_is_valid(s, false)) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        assert_se((t = unit_name_to_type(s)) >= 0);
+
+        if (u->type != _UNIT_TYPE_INVALID && t != u->type) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        if ((r = unit_name_to_instance(s, &i)) < 0)
+                goto fail;
+
+        if (i && unit_vtable[t]->no_instances) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        /* Ensure that this unit is either instanced or not instanced,
+         * but not both. */
+        if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        if (unit_vtable[t]->no_alias &&
+            !set_isempty(u->names) &&
+            !set_get(u->names, s)) {
+                r = -EEXIST;
+                goto fail;
+        }
+
+        if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) {
+                r = -E2BIG;
+                goto fail;
+        }
+
+        if ((r = set_put(u->names, s)) < 0) {
+                if (r == -EEXIST)
+                        r = 0;
+                goto fail;
+        }
+
+        if ((r = hashmap_put(u->manager->units, s, u)) < 0) {
+                set_remove(u->names, s);
+                goto fail;
+        }
+
+        if (u->type == _UNIT_TYPE_INVALID) {
+
+                u->type = t;
+                u->id = s;
+                u->instance = i;
+
+                LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u);
+
+                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, *i;
+        int r;
+
+        assert(u);
+        assert(name);
+
+        if (unit_name_is_template(name)) {
+
+                if (!u->instance)
+                        return -EINVAL;
+
+                if (!(t = unit_name_replace_instance(name, u->instance)))
+                        return -ENOMEM;
+
+                name = t;
+        }
+
+        /* Selects one of the names of this unit as the id */
+        s = set_get(u->names, (char*) name);
+        free(t);
+
+        if (!s)
+                return -ENOENT;
+
+        if ((r = unit_name_to_instance(s, &i)) < 0)
+                return r;
+
+        u->id = s;
+
+        free(u->instance);
+        u->instance = i;
+
+        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->description);
+        u->description = s;
+
+        unit_add_to_dbus_queue(u);
+        return 0;
+}
+
+bool unit_check_gc(Unit *u) {
+        assert(u);
+
+        if (u->load_state == UNIT_STUB)
+                return true;
+
+        if (UNIT_VTABLE(u)->no_gc)
+                return true;
+
+        if (u->no_gc)
+                return true;
+
+        if (u->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->type != _UNIT_TYPE_INVALID);
+
+        if (u->load_state != UNIT_STUB || u->in_load_queue)
+                return;
+
+        LIST_PREPEND(Unit, load_queue, u->manager->load_queue, u);
+        u->in_load_queue = true;
+}
+
+void unit_add_to_cleanup_queue(Unit *u) {
+        assert(u);
+
+        if (u->in_cleanup_queue)
+                return;
+
+        LIST_PREPEND(Unit, cleanup_queue, u->manager->cleanup_queue, u);
+        u->in_cleanup_queue = true;
+}
+
+void unit_add_to_gc_queue(Unit *u) {
+        assert(u);
+
+        if (u->in_gc_queue || u->in_cleanup_queue)
+                return;
+
+        if (unit_check_gc(u))
+                return;
+
+        LIST_PREPEND(Unit, gc_queue, u->manager->gc_queue, u);
+        u->in_gc_queue = true;
+
+        u->manager->n_in_gc_queue ++;
+
+        if (u->manager->gc_queue_timestamp <= 0)
+                u->manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
+}
+
+void unit_add_to_dbus_queue(Unit *u) {
+        assert(u);
+        assert(u->type != _UNIT_TYPE_INVALID);
+
+        if (u->load_state == UNIT_STUB || u->in_dbus_queue)
+                return;
+
+        /* Shortcut things if nobody cares */
+        if (!bus_has_subscriber(u->manager)) {
+                u->sent_dbus_new_signal = true;
+                return;
+        }
+
+        LIST_PREPEND(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
+        u->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->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);
+
+        if (u->load_state != UNIT_STUB)
+                if (UNIT_VTABLE(u)->done)
+                        UNIT_VTABLE(u)->done(u);
+
+        SET_FOREACH(t, u->names, i)
+                hashmap_remove_value(u->manager->units, t, u);
+
+        if (u->job)
+                job_free(u->job);
+
+        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+                bidi_set_free(u, u->dependencies[d]);
+
+        if (u->type != _UNIT_TYPE_INVALID)
+                LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
+
+        if (u->in_load_queue)
+                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
+
+        if (u->in_dbus_queue)
+                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
+
+        if (u->in_cleanup_queue)
+                LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u);
+
+        if (u->in_gc_queue) {
+                LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u);
+                u->manager->n_in_gc_queue--;
+        }
+
+        cgroup_bonding_free_list(u->cgroup_bondings, u->manager->n_reloading <= 0);
+        cgroup_attribute_free_list(u->cgroup_attributes);
+
+        free(u->description);
+        free(u->fragment_path);
+        free(u->instance);
+
+        set_free_free(u->names);
+
+        condition_free_list(u->conditions);
+
+        while (u->refs)
+                unit_ref_unset(u->refs);
+
+        free(u);
+}
+
+UnitActiveState unit_active_state(Unit *u) {
+        assert(u);
+
+        if (u->load_state == UNIT_MERGED)
+                return unit_active_state(unit_follow_merge(u));
+
+        /* After a reload it might happen that a unit is not correctly
+         * loaded but still has a process around. That's why we won't
+         * shortcut failed loading to UNIT_INACTIVE_FAILED. */
+
+        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->names, &other->names);
+
+        set_free_free(other->names);
+        other->names = NULL;
+        other->id = NULL;
+
+        SET_FOREACH(t, u->names, i)
+                assert_se(hashmap_replace(u->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);
+
+        /* Fix backwards pointers */
+        SET_FOREACH(back, other->dependencies[d], i) {
+                UnitDependency k;
+
+                for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
+                        if ((r = set_remove_and_put(back->dependencies[k], other, u)) < 0) {
+
+                                if (r == -EEXIST)
+                                        set_remove(back->dependencies[k], other);
+                                else
+                                        assert(r == -ENOENT);
+                        }
+        }
+
+        complete_move(&u->dependencies[d], &other->dependencies[d]);
+
+        set_free(other->dependencies[d]);
+        other->dependencies[d] = NULL;
+}
+
+int unit_merge(Unit *u, Unit *other) {
+        UnitDependency d;
+
+        assert(u);
+        assert(other);
+        assert(u->manager == other->manager);
+        assert(u->type != _UNIT_TYPE_INVALID);
+
+        other = unit_follow_merge(other);
+
+        if (other == u)
+                return 0;
+
+        if (u->type != other->type)
+                return -EINVAL;
+
+        if (!u->instance != !other->instance)
+                return -EINVAL;
+
+        if (other->load_state != UNIT_STUB &&
+            other->load_state != UNIT_ERROR)
+                return -EEXIST;
+
+        if (other->job)
+                return -EEXIST;
+
+        if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
+                return -EEXIST;
+
+        /* Merge names */
+        merge_names(u, other);
+
+        /* Redirect all references */
+        while (other->refs)
+                unit_ref_set(other->refs, u);
+
+        /* Merge dependencies */
+        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+                merge_dependencies(u, other, d);
+
+        other->load_state = UNIT_MERGED;
+        other->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->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->instance)
+                        return -EINVAL;
+
+                if (!(s = unit_name_replace_instance(name, u->instance)))
+                        return -ENOMEM;
+
+                name = s;
+        }
+
+        if (!(other = manager_get_unit(u->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->load_state == UNIT_MERGED)
+                assert_se(u = u->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_KMSG &&
+            c->std_output != EXEC_OUTPUT_SYSLOG &&
+            c->std_output != EXEC_OUTPUT_JOURNAL &&
+            c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
+            c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE &&
+            c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
+            c->std_error != EXEC_OUTPUT_KMSG &&
+            c->std_error != EXEC_OUTPUT_SYSLOG &&
+            c->std_error != EXEC_OUTPUT_JOURNAL &&
+            c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
+            c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
+            c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE)
+                return 0;
+
+        /* If syslog or kernel logging is requested, make sure our own
+         * logging daemon is run first. */
+
+        if (u->manager->running_as == MANAGER_SYSTEM)
+                if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true)) < 0)
+                        return r;
+
+        return 0;
+}
+
+const char *unit_description(Unit *u) {
+        assert(u);
+
+        if (u->description)
+                return u->description;
+
+        return strna(u->id);
+}
+
+void unit_dump(Unit *u, FILE *f, const char *prefix) {
+        char *t;
+        UnitDependency d;
+        Iterator i;
+        char *p2;
+        const char *prefix2;
+        char
+                timestamp1[FORMAT_TIMESTAMP_MAX],
+                timestamp2[FORMAT_TIMESTAMP_MAX],
+                timestamp3[FORMAT_TIMESTAMP_MAX],
+                timestamp4[FORMAT_TIMESTAMP_MAX],
+                timespan[FORMAT_TIMESPAN_MAX];
+        Unit *following;
+
+        assert(u);
+        assert(u->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"
+                "%s\tNeed Daemon Reload: %s\n",
+                prefix, u->id,
+                prefix, unit_description(u),
+                prefix, strna(u->instance),
+                prefix, unit_load_state_to_string(u->load_state),
+                prefix, unit_active_state_to_string(unit_active_state(u)),
+                prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
+                prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
+                prefix, yes_no(unit_check_gc(u)),
+                prefix, yes_no(unit_need_daemon_reload(u)));
+
+        SET_FOREACH(t, u->names, i)
+                fprintf(f, "%s\tName: %s\n", prefix, t);
+
+        if ((following = unit_following(u)))
+                fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
+
+        if (u->fragment_path)
+                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
+
+        if (u->job_timeout > 0)
+                fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout));
+
+        condition_dump_list(u->conditions, f, prefix);
+
+        if (dual_timestamp_is_set(&u->condition_timestamp))
+                fprintf(f,
+                        "%s\tCondition Timestamp: %s\n"
+                        "%s\tCondition Result: %s\n",
+                        prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)),
+                        prefix, yes_no(u->condition_result));
+
+        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+                Unit *other;
+
+                SET_FOREACH(other, u->dependencies[d], i)
+                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id);
+        }
+
+        if (u->load_state == UNIT_LOADED) {
+                CGroupBonding *b;
+                CGroupAttribute *a;
+
+                fprintf(f,
+                        "%s\tStopWhenUnneeded: %s\n"
+                        "%s\tRefuseManualStart: %s\n"
+                        "%s\tRefuseManualStop: %s\n"
+                        "%s\tDefaultDependencies: %s\n"
+                        "%s\tOnFailureIsolate: %s\n"
+                        "%s\tIgnoreOnIsolate: %s\n"
+                        "%s\tIgnoreOnSnapshot: %s\n",
+                        prefix, yes_no(u->stop_when_unneeded),
+                        prefix, yes_no(u->refuse_manual_start),
+                        prefix, yes_no(u->refuse_manual_stop),
+                        prefix, yes_no(u->default_dependencies),
+                        prefix, yes_no(u->on_failure_isolate),
+                        prefix, yes_no(u->ignore_on_isolate),
+                        prefix, yes_no(u->ignore_on_snapshot));
+
+                LIST_FOREACH(by_unit, b, u->cgroup_bondings)
+                        fprintf(f, "%s\tControlGroup: %s:%s\n",
+                                prefix, b->controller, b->path);
+
+                LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
+                        char *v = NULL;
+
+                        if (a->map_callback)
+                                a->map_callback(a->controller, a->name, a->value, &v);
+
+                        fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n",
+                                prefix, a->controller, a->name, v ? v : a->value);
+
+                        free(v);
+                }
+
+                if (UNIT_VTABLE(u)->dump)
+                        UNIT_VTABLE(u)->dump(u, f, prefix2);
+
+        } else if (u->load_state == UNIT_MERGED)
+                fprintf(f,
+                        "%s\tMerged into: %s\n",
+                        prefix, u->merged_into->id);
+        else if (u->load_state == UNIT_ERROR)
+                fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
+
+
+        if (u->job)
+                job_dump(u->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->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->load_state == UNIT_STUB)
+                u->load_state = UNIT_LOADED;
+
+        /* Load drop-in directory data */
+        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
+                return r;
+
+        return 0;
+}
+
+int unit_add_default_target_dependency(Unit *u, Unit *target) {
+        assert(u);
+        assert(target);
+
+        if (target->type != UNIT_TARGET)
+                return 0;
+
+        /* Only add the dependency if both units are loaded, so that
+         * that loop check below is reliable */
+        if (u->load_state != UNIT_LOADED ||
+            target->load_state != UNIT_LOADED)
+                return 0;
+
+        /* If either side wants no automatic dependencies, then let's
+         * skip this */
+        if (!u->default_dependencies ||
+            !target->default_dependencies)
+                return 0;
+
+        /* Don't create loops */
+        if (set_get(target->dependencies[UNIT_BEFORE], u))
+                return 0;
+
+        return unit_add_dependency(target, UNIT_AFTER, u, true);
+}
+
+static int unit_add_default_dependencies(Unit *u) {
+        static const UnitDependency deps[] = {
+                UNIT_REQUIRED_BY,
+                UNIT_REQUIRED_BY_OVERRIDABLE,
+                UNIT_WANTED_BY,
+                UNIT_BOUND_BY
+        };
+
+        Unit *target;
+        Iterator i;
+        int r;
+        unsigned k;
+
+        assert(u);
+
+        for (k = 0; k < ELEMENTSOF(deps); k++)
+                SET_FOREACH(target, u->dependencies[deps[k]], i)
+                        if ((r = unit_add_default_target_dependency(u, target)) < 0)
+                                return r;
+
+        return 0;
+}
+
+int unit_load(Unit *u) {
+        int r;
+
+        assert(u);
+
+        if (u->in_load_queue) {
+                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
+                u->in_load_queue = false;
+        }
+
+        if (u->type == _UNIT_TYPE_INVALID)
+                return -EINVAL;
+
+        if (u->load_state != UNIT_STUB)
+                return 0;
+
+        if (UNIT_VTABLE(u)->load)
+                if ((r = UNIT_VTABLE(u)->load(u)) < 0)
+                        goto fail;
+
+        if (u->load_state == UNIT_STUB) {
+                r = -ENOENT;
+                goto fail;
+        }
+
+        if (u->load_state == UNIT_LOADED &&
+            u->default_dependencies)
+                if ((r = unit_add_default_dependencies(u)) < 0)
+                        goto fail;
+
+        if (u->on_failure_isolate &&
+            set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
+
+                log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.",
+                          u->id);
+
+                r = -EINVAL;
+                goto fail;
+        }
+
+        assert((u->load_state != UNIT_MERGED) == !u->merged_into);
+
+        unit_add_to_dbus_queue(unit_follow_merge(u));
+        unit_add_to_gc_queue(u);
+
+        return 0;
+
+fail:
+        u->load_state = UNIT_ERROR;
+        u->load_error = r;
+        unit_add_to_dbus_queue(u);
+        unit_add_to_gc_queue(u);
+
+        log_debug("Failed to load configuration for %s: %s", u->id, strerror(-r));
+
+        return r;
+}
+
+bool unit_condition_test(Unit *u) {
+        assert(u);
+
+        dual_timestamp_get(&u->condition_timestamp);
+        u->condition_result = condition_test_list(u->conditions);
+
+        return u->condition_result;
+}
+
+/* Errors:
+ *         -EBADR:     This unit type does not support starting.
+ *         -EALREADY:  Unit is already started.
+ *         -EAGAIN:    An operation is already in progress. Retry later.
+ *         -ECANCELED: Too many requests for now.
+ */
+int unit_start(Unit *u) {
+        UnitActiveState state;
+        Unit *following;
+
+        assert(u);
+
+        if (u->load_state != UNIT_LOADED)
+                return -EINVAL;
+
+        /* If this is already 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 the conditions failed, don't do anything at all. If we
+         * already are activating this call might still be useful to
+         * speed up activation in case there is some hold-off time,
+         * but we don't want to recheck the condition in that case. */
+        if (state != UNIT_ACTIVATING &&
+            !unit_condition_test(u)) {
+                log_debug("Starting of %s requested but condition failed. Ignoring.", u->id);
+                return -EALREADY;
+        }
+
+        /* Forward to the main object, if we aren't it. */
+        if ((following = unit_following(u))) {
+                log_debug("Redirecting start request from %s to %s.", u->id, following->id);
+                return unit_start(following);
+        }
+
+        /* 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);
+
+        unit_status_printf(u, NULL, "Starting %s...", unit_description(u));
+        return UNIT_VTABLE(u)->start(u);
+}
+
+bool unit_can_start(Unit *u) {
+        assert(u);
+
+        return !!UNIT_VTABLE(u)->start;
+}
+
+bool unit_can_isolate(Unit *u) {
+        assert(u);
+
+        return unit_can_start(u) &&
+                u->allow_isolate;
+}
+
+/* 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;
+        Unit *following;
+
+        assert(u);
+
+        state = unit_active_state(u);
+        if (UNIT_IS_INACTIVE_OR_FAILED(state))
+                return -EALREADY;
+
+        if ((following = unit_following(u))) {
+                log_debug("Redirecting stop request from %s to %s.", u->id, following->id);
+                return unit_stop(following);
+        }
+
+        if (!UNIT_VTABLE(u)->stop)
+                return -EBADR;
+
+        unit_add_to_dbus_queue(u);
+
+        unit_status_printf(u, NULL, "Stopping %s...", unit_description(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;
+        Unit *following;
+
+        assert(u);
+
+        if (u->load_state != UNIT_LOADED)
+                return -EINVAL;
+
+        if (!unit_can_reload(u))
+                return -EBADR;
+
+        state = unit_active_state(u);
+        if (state == UNIT_RELOADING)
+                return -EALREADY;
+
+        if (state != UNIT_ACTIVE)
+                return -ENOEXEC;
+
+        if ((following = unit_following(u))) {
+                log_debug("Redirecting reload request from %s to %s.", u->id, following->id);
+                return unit_reload(following);
+        }
+
+        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_unneeded(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+
+        /* If this service shall be shut down when unneeded then do
+         * so. */
+
+        if (!u->stop_when_unneeded)
+                return;
+
+        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return;
+
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
+                if (unit_pending_active(other))
+                        return;
+
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
+                if (unit_pending_active(other))
+                        return;
+
+        SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
+                if (unit_pending_active(other))
+                        return;
+
+        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
+                if (unit_pending_active(other))
+                        return;
+
+        log_info("Service %s is not needed anymore. Stopping.", u->id);
+
+        /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
+        manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, 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->dependencies[UNIT_REQUIRES], i)
+                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
+
+        SET_FOREACH(other, u->dependencies[UNIT_BIND_TO], i)
+                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
+
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
+
+        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
+                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
+
+        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
+                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
+
+        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+
+        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+}
+
+static void retroactively_stop_dependencies(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
+
+        /* Pull down units which are bound to us recursively if enabled */
+        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+}
+
+static void check_unneeded_dependencies(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
+
+        /* Garbage collect services that might not be needed anymore, if enabled */
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_unneeded(other);
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_unneeded(other);
+        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_unneeded(other);
+        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_unneeded(other);
+        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_unneeded(other);
+        SET_FOREACH(other, u->dependencies[UNIT_BIND_TO], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_unneeded(other);
+}
+
+void unit_trigger_on_failure(Unit *u) {
+        Unit *other;
+        Iterator i;
+
+        assert(u);
+
+        if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
+                return;
+
+        log_info("Triggering OnFailure= dependencies of %s.", u->id);
+
+        SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
+                int r;
+
+                if ((r = manager_add_job(u->manager, JOB_START, other, u->on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL)) < 0)
+                        log_error("Failed to enqueue OnFailure= job: %s", strerror(-r));
+        }
+}
+
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
+        bool unexpected;
+
+        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! */
+
+        if (u->manager->n_reloading <= 0) {
+                dual_timestamp ts;
+
+                dual_timestamp_get(&ts);
+
+                if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
+                        u->inactive_exit_timestamp = ts;
+                else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
+                        u->inactive_enter_timestamp = ts;
+
+                if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                        u->active_enter_timestamp = ts;
+                else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                        u->active_exit_timestamp = ts;
+
+                timer_unit_notify(u, ns);
+                path_unit_notify(u, ns);
+        }
+
+        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+                cgroup_bonding_trim_list(u->cgroup_bondings, true);
+
+        if (u->job) {
+                unexpected = false;
+
+                if (u->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->job);
+
+                /* Let's check whether this state change constitutes a
+                 * finished job, or maybe contradicts a running job and
+                 * hence needs to invalidate jobs. */
+
+                switch (u->job->type) {
+
+                case JOB_START:
+                case JOB_VERIFY_ACTIVE:
+
+                        if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
+                                job_finish_and_invalidate(u->job, JOB_DONE);
+                        else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
+                                unexpected = true;
+
+                                if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+                                        job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
+                        }
+
+                        break;
+
+                case JOB_RELOAD:
+                case JOB_RELOAD_OR_START:
+
+                        if (u->job->state == JOB_RUNNING) {
+                                if (ns == UNIT_ACTIVE)
+                                        job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED);
+                                else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
+                                        unexpected = true;
+
+                                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+                                                job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
+                                }
+                        }
+
+                        break;
+
+                case JOB_STOP:
+                case JOB_RESTART:
+                case JOB_TRY_RESTART:
+
+                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+                                job_finish_and_invalidate(u->job, JOB_DONE);
+                        else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
+                                unexpected = true;
+                                job_finish_and_invalidate(u->job, JOB_FAILED);
+                        }
+
+                        break;
+
+                default:
+                        assert_not_reached("Job type unknown");
+                }
+
+        } else
+                unexpected = true;
+
+        if (u->manager->n_reloading <= 0) {
+
+                /* If this state change happened without being
+                 * requested by a job, then let's retroactively start
+                 * or stop dependencies. We skip that step when
+                 * deserializing, since we don't want to create any
+                 * additional jobs just because something is already
+                 * activated. */
+
+                if (unexpected) {
+                        if (UNIT_IS_INACTIVE_OR_FAILED(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);
+                }
+
+                /* stop unneeded units regardless if going down was expected or not */
+                if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
+                        check_unneeded_dependencies(u);
+
+                if (ns != os && ns == UNIT_FAILED) {
+                        log_notice("Unit %s entered failed state.", u->id);
+                        unit_trigger_on_failure(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(u->manager, true);
+
+                if (u->type == UNIT_SERVICE &&
+                    !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
+                    u->manager->n_reloading <= 0) {
+                        /* Write audit record if we have just finished starting up */
+                        manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, true);
+                        u->in_audit = true;
+                }
+
+                if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
+                        manager_send_unit_plymouth(u->manager, u);
+
+        } else {
+
+                /* We don't care about D-Bus here, since we'll get an
+                 * asynchronous notification for it anyway. */
+
+                if (u->type == UNIT_SERVICE &&
+                    UNIT_IS_INACTIVE_OR_FAILED(ns) &&
+                    !UNIT_IS_INACTIVE_OR_FAILED(os) &&
+                    u->manager->n_reloading <= 0) {
+
+                        /* Hmm, if there was no start record written
+                         * write it now, so that we always have a nice
+                         * pair */
+                        if (!u->in_audit) {
+                                manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
+
+                                if (ns == UNIT_INACTIVE)
+                                        manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, true);
+                        } else
+                                /* Write audit record if we have just finished shutting down */
+                                manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
+
+                        u->in_audit = false;
+                }
+        }
+
+        manager_recheck_journal(u->manager);
+
+        /* Maybe we finished startup and are now ready for being
+         * stopped because unneeded? */
+        unit_check_unneeded(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->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->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->manager->watch_pids, LONG_TO_PTR(pid), u);
+}
+
+void unit_unwatch_pid(Unit *u, pid_t pid) {
+        assert(u);
+        assert(pid >= 1);
+
+        hashmap_remove_value(u->manager->watch_pids, LONG_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_UNIT_TIMER && w->data.unit == u));
+
+        /* This will try to reuse the old timer if there is one */
+
+        if (w->type == WATCH_UNIT_TIMER) {
+                assert(w->data.unit == u);
+                assert(w->fd >= 0);
+
+                ours = false;
+                fd = w->fd;
+        } else if (w->type == WATCH_INVALID) {
+
+                ours = true;
+                if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
+                        return -errno;
+        } else
+                assert_not_reached("Invalid watch type");
+
+        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->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
+                        goto fail;
+        }
+
+        w->type = WATCH_UNIT_TIMER;
+        w->fd = fd;
+        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_UNIT_TIMER);
+        assert(w->data.unit == u);
+        assert(w->fd >= 0);
+
+        assert_se(epoll_ctl(u->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:
+        case JOB_STOP:
+                return true;
+
+        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_BIND_TO] = UNIT_BOUND_BY,
+                [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_BOUND_BY] = UNIT_BIND_TO,
+                [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
+                [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
+                [UNIT_BEFORE] = UNIT_AFTER,
+                [UNIT_AFTER] = UNIT_BEFORE,
+                [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
+                [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
+                [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
+                [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
+                [UNIT_PROPAGATE_RELOAD_TO] = UNIT_PROPAGATE_RELOAD_FROM,
+                [UNIT_PROPAGATE_RELOAD_FROM] = UNIT_PROPAGATE_RELOAD_TO
+        };
+        int r, q = 0, v = 0, w = 0;
+
+        assert(u);
+        assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
+        assert(other);
+
+        u = unit_follow_merge(u);
+        other = unit_follow_merge(other);
+
+        /* We won't allow dependencies on ourselves. We will not
+         * consider them an error however. */
+        if (u == other)
+                return 0;
+
+        if ((r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
+                return r;
+
+        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
+                if ((r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
+                        return r;
+
+        if (add_reference)
+                if ((r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
+                    (r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
+                        return r;
+
+        if ((q = set_put(u->dependencies[d], other)) < 0)
+                return q;
+
+        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
+                if ((v = set_put(other->dependencies[inverse_table[d]], u)) < 0) {
+                        r = v;
+                        goto fail;
+                }
+
+        if (add_reference) {
+                if ((w = set_put(u->dependencies[UNIT_REFERENCES], other)) < 0) {
+                        r = w;
+                        goto fail;
+                }
+
+                if ((r = set_put(other->dependencies[UNIT_REFERENCED_BY], u)) < 0)
+                        goto fail;
+        }
+
+        unit_add_to_dbus_queue(u);
+        return 0;
+
+fail:
+        if (q > 0)
+                set_remove(u->dependencies[d], other);
+
+        if (v > 0)
+                set_remove(other->dependencies[inverse_table[d]], u);
+
+        if (w > 0)
+                set_remove(u->dependencies[UNIT_REFERENCES], other);
+
+        return r;
+}
+
+int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) {
+        int r;
+
+        assert(u);
+
+        if ((r = unit_add_dependency(u, d, other, add_reference)) < 0)
+                return r;
+
+        if ((r = unit_add_dependency(u, e, other, add_reference)) < 0)
+                return r;
+
+        return 0;
+}
+
+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->instance)
+                s = unit_name_replace_instance(name, u->instance);
+        else {
+                char *i;
+
+                if (!(i = unit_name_to_prefix(u->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->manager, name, path, NULL, &other)) < 0)
+                goto finish;
+
+        r = unit_add_dependency(u, d, other, add_reference);
+
+finish:
+        free(s);
+        return r;
+}
+
+int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, 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->manager, name, path, NULL, &other)) < 0)
+                goto finish;
+
+        r = unit_add_two_dependencies(u, d, e, 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->manager, name, path, NULL, &other)) < 0)
+                goto finish;
+
+        r = unit_add_dependency(other, d, u, add_reference);
+
+finish:
+        free(s);
+        return r;
+}
+
+int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, 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->manager, name, path, NULL, &other)) < 0)
+                goto finish;
+
+        if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0)
+                goto finish;
+
+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 (!u->id)
+                return NULL;
+
+        if (!(e = bus_path_escape(u->id)))
+                return NULL;
+
+        p = strappend("/org/freedesktop/systemd1/unit/", e);
+        free(e);
+
+        return p;
+}
+
+int unit_add_cgroup(Unit *u, CGroupBonding *b) {
+        int r;
+
+        assert(u);
+        assert(b);
+
+        assert(b->path);
+
+        if (!b->controller) {
+                if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER)))
+                        return -ENOMEM;
+
+                b->ours = true;
+        }
+
+        /* Ensure this hasn't been added yet */
+        assert(!b->unit);
+
+        if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                CGroupBonding *l;
+
+                l = hashmap_get(u->manager->cgroup_bondings, b->path);
+                LIST_PREPEND(CGroupBonding, by_path, l, b);
+
+                if ((r = hashmap_replace(u->manager->cgroup_bondings, b->path, l)) < 0) {
+                        LIST_REMOVE(CGroupBonding, by_path, l, b);
+                        return r;
+                }
+        }
+
+        LIST_PREPEND(CGroupBonding, by_unit, u->cgroup_bondings, b);
+        b->unit = u;
+
+        return 0;
+}
+
+static char *default_cgroup_path(Unit *u) {
+        char *p;
+
+        assert(u);
+
+        if (u->instance) {
+                char *t;
+
+                t = unit_name_template(u->id);
+                if (!t)
+                        return NULL;
+
+                p = join(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL);
+                free(t);
+        } else
+                p = join(u->manager->cgroup_hierarchy, "/", u->id, NULL);
+
+        return p;
+}
+
+int unit_add_cgroup_from_text(Unit *u, const char *name) {
+        char *controller = NULL, *path = NULL;
+        CGroupBonding *b = NULL;
+        bool ours = false;
+        int r;
+
+        assert(u);
+        assert(name);
+
+        if ((r = cg_split_spec(name, &controller, &path)) < 0)
+                return r;
+
+        if (!path) {
+                path = default_cgroup_path(u);
+                ours = true;
+        }
+
+        if (!controller) {
+                controller = strdup(SYSTEMD_CGROUP_CONTROLLER);
+                ours = true;
+        }
+
+        if (!path || !controller) {
+                free(path);
+                free(controller);
+
+                return -ENOMEM;
+        }
+
+        if (cgroup_bonding_find_list(u->cgroup_bondings, controller)) {
+                r = -EEXIST;
+                goto fail;
+        }
+
+        if (!(b = new0(CGroupBonding, 1))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        b->controller = controller;
+        b->path = path;
+        b->ours = ours;
+        b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
+
+        if ((r = unit_add_cgroup(u, b)) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        free(path);
+        free(controller);
+        free(b);
+
+        return r;
+}
+
+static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
+        CGroupBonding *b = NULL;
+        int r = -ENOMEM;
+
+        assert(u);
+
+        if (!controller)
+                controller = SYSTEMD_CGROUP_CONTROLLER;
+
+        if (cgroup_bonding_find_list(u->cgroup_bondings, controller))
+                return 0;
+
+        if (!(b = new0(CGroupBonding, 1)))
+                return -ENOMEM;
+
+        if (!(b->controller = strdup(controller)))
+                goto fail;
+
+        if (!(b->path = default_cgroup_path(u)))
+                goto fail;
+
+        b->ours = true;
+        b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
+
+        if ((r = unit_add_cgroup(u, b)) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        free(b->path);
+        free(b->controller);
+        free(b);
+
+        return r;
+}
+
+int unit_add_default_cgroups(Unit *u) {
+        CGroupAttribute *a;
+        char **c;
+        int r;
+
+        assert(u);
+
+        /* Adds in the default cgroups, if they weren't specified
+         * otherwise. */
+
+        if (!u->manager->cgroup_hierarchy)
+                return 0;
+
+        if ((r = unit_add_one_default_cgroup(u, NULL)) < 0)
+                return r;
+
+        STRV_FOREACH(c, u->manager->default_controllers)
+                unit_add_one_default_cgroup(u, *c);
+
+        LIST_FOREACH(by_unit, a, u->cgroup_attributes)
+                unit_add_one_default_cgroup(u, a->controller);
+
+        return 0;
+}
+
+CGroupBonding* unit_get_default_cgroup(Unit *u) {
+        assert(u);
+
+        return cgroup_bonding_find_list(u->cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER);
+}
+
+int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback) {
+        int r;
+        char *c = NULL;
+        CGroupAttribute *a;
+
+        assert(u);
+        assert(name);
+        assert(value);
+
+        if (!controller) {
+                const char *dot;
+
+                dot = strchr(name, '.');
+                if (!dot)
+                        return -EINVAL;
+
+                c = strndup(name, dot - name);
+                if (!c)
+                        return -ENOMEM;
+
+                controller = c;
+        }
+
+        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        a = new0(CGroupAttribute, 1);
+        if (!a) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (c) {
+                a->controller = c;
+                c = NULL;
+        } else
+                a->controller = strdup(controller);
+
+        a->name = strdup(name);
+        a->value = strdup(value);
+
+        if (!a->controller || !a->name || !a->value) {
+                free(a->controller);
+                free(a->name);
+                free(a->value);
+                free(a);
+
+                return -ENOMEM;
+        }
+
+        a->map_callback = map_callback;
+
+        LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a);
+
+        r = 0;
+
+finish:
+        free(c);
+        return r;
+}
+
+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->id, type)))
+                return -ENOMEM;
+
+        assert(!unit_has_name(u, t));
+
+        r = manager_load_unit(u->manager, t, NULL, 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->id, type)))
+                return -ENOMEM;
+
+        assert(!unit_has_name(u, t));
+
+        found = manager_get_unit(u->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->id);
+}
+
+static char *specifier_prefix(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        return unit_name_to_prefix(u->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->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->instance)
+                return unit_name_unescape(u->instance);
+
+        return strdup("");
+}
+
+static char *specifier_filename(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        if (u->instance)
+                return unit_name_path_unescape(u->instance);
+
+        return unit_name_to_path(u->instance);
+}
+
+static char *specifier_cgroup(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        return default_cgroup_path(u);
+}
+
+static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        char *p;
+        assert(u);
+
+        if (specifier == 'r')
+                return strdup(u->manager->cgroup_hierarchy);
+
+        if (parent_of_path(u->manager->cgroup_hierarchy, &p) < 0)
+                return strdup("");
+
+        if (streq(p, "/")) {
+                free(p);
+                return strdup("");
+        }
+
+        return p;
+}
+
+static char *specifier_runtime(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        if (u->manager->running_as == MANAGER_USER) {
+                const char *e;
+
+                e = getenv("XDG_RUNTIME_DIR");
+                if (e)
+                        return strdup(e);
+        }
+
+        return strdup("/run");
+}
+
+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->id },
+                { 'N', specifier_prefix_and_instance, NULL },
+                { 'p', specifier_prefix,              NULL },
+                { 'i', specifier_string,              u->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. Also, adds a couple of additional codes:
+         *
+         * %c cgroup path of unit
+         * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
+         * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
+         * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
+         */
+
+        const Specifier table[] = {
+                { 'n', specifier_string,              u->id },
+                { 'N', specifier_prefix_and_instance, NULL },
+                { 'p', specifier_prefix,              NULL },
+                { 'P', specifier_prefix_unescaped,    NULL },
+                { 'i', specifier_string,              u->instance },
+                { 'I', specifier_instance_unescaped,  NULL },
+                { 'f', specifier_filename,            NULL },
+                { 'c', specifier_cgroup,              NULL },
+                { 'r', specifier_cgroup_root,         NULL },
+                { 'R', specifier_cgroup_root,         NULL },
+                { 't', specifier_runtime,             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:
+        for (j--; j >= r; j--)
+                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->manager->watch_bus, name, u);
+}
+
+void unit_unwatch_bus_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        hashmap_remove_value(u->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;
+
+        if (u->job)
+                unit_serialize_item(u, f, "job", job_type_to_string(u->job->type));
+
+        dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
+        dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
+        dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
+        dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
+        dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
+
+        if (dual_timestamp_is_set(&u->condition_timestamp))
+                unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
+
+        /* 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[LINE_MAX], *l, *v;
+                size_t k;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                return 0;
+                        return -errno;
+                }
+
+                char_array_0(line);
+                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 (streq(l, "job")) {
+                        JobType type;
+
+                        if ((type = job_type_from_string(v)) < 0)
+                                log_debug("Failed to parse job type value %s", v);
+                        else
+                                u->deserialized_job = type;
+
+                        continue;
+                } else if (streq(l, "inactive-exit-timestamp")) {
+                        dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
+                        continue;
+                } else if (streq(l, "active-enter-timestamp")) {
+                        dual_timestamp_deserialize(v, &u->active_enter_timestamp);
+                        continue;
+                } else if (streq(l, "active-exit-timestamp")) {
+                        dual_timestamp_deserialize(v, &u->active_exit_timestamp);
+                        continue;
+                } else if (streq(l, "inactive-enter-timestamp")) {
+                        dual_timestamp_deserialize(v, &u->inactive_enter_timestamp);
+                        continue;
+                } else if (streq(l, "condition-timestamp")) {
+                        dual_timestamp_deserialize(v, &u->condition_timestamp);
+                        continue;
+                } else if (streq(l, "condition-result")) {
+                        int b;
+
+                        if ((b = parse_boolean(v)) < 0)
+                                log_debug("Failed to parse condition result value %s", v);
+                        else
+                                u->condition_result = b;
+
+                        continue;
+                }
+
+                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->manager, e, NULL, NULL, &device);
+        free(e);
+
+        if (r < 0)
+                return r;
+
+        if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BIND_TO, device, true)) < 0)
+                return r;
+
+        if (wants)
+                if ((r = unit_add_dependency(device, UNIT_WANTS, u, false)) < 0)
+                        return r;
+
+        return 0;
+}
+
+int unit_coldplug(Unit *u) {
+        int r;
+
+        assert(u);
+
+        if (UNIT_VTABLE(u)->coldplug)
+                if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
+                        return r;
+
+        if (u->deserialized_job >= 0) {
+                if ((r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL)) < 0)
+                        return r;
+
+                u->deserialized_job = _JOB_TYPE_INVALID;
+        }
+
+        return 0;
+}
+
+void unit_status_printf(Unit *u, const char *status, const char *format, ...) {
+        va_list ap;
+
+        assert(u);
+        assert(format);
+
+        if (!UNIT_VTABLE(u)->show_status)
+                return;
+
+        if (!manager_get_show_status(u->manager))
+                return;
+
+        if (!manager_is_booting_or_shutting_down(u->manager))
+                return;
+
+        va_start(ap, format);
+        status_vprintf(status, true, format, ap);
+        va_end(ap);
+}
+
+bool unit_need_daemon_reload(Unit *u) {
+        assert(u);
+
+        if (u->fragment_path) {
+                struct stat st;
+
+                zero(st);
+                if (stat(u->fragment_path, &st) < 0)
+                        /* What, cannot access this anymore? */
+                        return true;
+
+                if (u->fragment_mtime > 0 &&
+                    timespec_load(&st.st_mtim) != u->fragment_mtime)
+                        return true;
+        }
+
+        if (UNIT_VTABLE(u)->need_daemon_reload)
+                return UNIT_VTABLE(u)->need_daemon_reload(u);
+
+        return false;
+}
+
+void unit_reset_failed(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->reset_failed)
+                UNIT_VTABLE(u)->reset_failed(u);
+}
+
+Unit *unit_following(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->following)
+                return UNIT_VTABLE(u)->following(u);
+
+        return NULL;
+}
+
+bool unit_pending_inactive(Unit *u) {
+        assert(u);
+
+        /* Returns true if the unit is inactive or going down */
+
+        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)))
+                return true;
+
+        if (u->job && u->job->type == JOB_STOP)
+                return true;
+
+        return false;
+}
+
+bool unit_pending_active(Unit *u) {
+        assert(u);
+
+        /* Returns true if the unit is active or going up */
+
+        if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return true;
+
+        if (u->job &&
+            (u->job->type == JOB_START ||
+             u->job->type == JOB_RELOAD_OR_START ||
+             u->job->type == JOB_RESTART))
+                return true;
+
+        return false;
+}
+
+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, bool template_ok) {
+        UnitType t;
+
+        t = unit_name_to_type(n);
+        if (t < 0 || t >= _UNIT_TYPE_MAX)
+                return false;
+
+        return unit_name_is_valid_no_type(n, template_ok);
+}
+
+int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error) {
+        assert(u);
+        assert(w >= 0 && w < _KILL_WHO_MAX);
+        assert(m >= 0 && m < _KILL_MODE_MAX);
+        assert(signo > 0);
+        assert(signo < _NSIG);
+
+        if (m == KILL_NONE)
+                return 0;
+
+        if (!UNIT_VTABLE(u)->kill)
+                return -ENOTSUP;
+
+        return UNIT_VTABLE(u)->kill(u, w, m, signo, error);
+}
+
+int unit_following_set(Unit *u, Set **s) {
+        assert(u);
+        assert(s);
+
+        if (UNIT_VTABLE(u)->following_set)
+                return UNIT_VTABLE(u)->following_set(u, s);
+
+        *s = NULL;
+        return 0;
+}
+
+UnitFileState unit_get_unit_file_state(Unit *u) {
+        assert(u);
+
+        if (u->unit_file_state < 0 && u->fragment_path)
+                u->unit_file_state = unit_file_get_state(
+                                u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+                                NULL, file_name_from_path(u->fragment_path));
+
+        return u->unit_file_state;
+}
+
+Unit* unit_ref_set(UnitRef *ref, Unit *u) {
+        assert(ref);
+        assert(u);
+
+        if (ref->unit)
+                unit_ref_unset(ref);
+
+        ref->unit = u;
+        LIST_PREPEND(UnitRef, refs, u->refs, ref);
+        return u;
+}
+
+void unit_ref_unset(UnitRef *ref) {
+        assert(ref);
+
+        if (!ref->unit)
+                return;
+
+        LIST_REMOVE(UnitRef, refs, ref->unit->refs, ref);
+        ref->unit = NULL;
+}
+
+static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
+        [UNIT_STUB] = "stub",
+        [UNIT_LOADED] = "loaded",
+        [UNIT_ERROR] = "error",
+        [UNIT_MERGED] = "merged",
+        [UNIT_MASKED] = "masked"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+
+static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
+        [UNIT_ACTIVE] = "active",
+        [UNIT_RELOADING] = "reloading",
+        [UNIT_INACTIVE] = "inactive",
+        [UNIT_FAILED] = "failed",
+        [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_BIND_TO] = "BindTo",
+        [UNIT_WANTED_BY] = "WantedBy",
+        [UNIT_CONFLICTS] = "Conflicts",
+        [UNIT_CONFLICTED_BY] = "ConflictedBy",
+        [UNIT_BOUND_BY] = "BoundBy",
+        [UNIT_BEFORE] = "Before",
+        [UNIT_AFTER] = "After",
+        [UNIT_REFERENCES] = "References",
+        [UNIT_REFERENCED_BY] = "ReferencedBy",
+        [UNIT_ON_FAILURE] = "OnFailure",
+        [UNIT_TRIGGERS] = "Triggers",
+        [UNIT_TRIGGERED_BY] = "TriggeredBy",
+        [UNIT_PROPAGATE_RELOAD_TO] = "PropagateReloadTo",
+        [UNIT_PROPAGATE_RELOAD_FROM] = "PropagateReloadFrom"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
diff --git a/src/core/unit.h b/src/core/unit.h
new file mode 100644
index 0000000..756f465
--- /dev/null
+++ b/src/core/unit.h
@@ -0,0 +1,562 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#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 struct Unit Unit;
+typedef struct UnitVTable UnitVTable;
+typedef enum UnitType UnitType;
+typedef enum UnitLoadState UnitLoadState;
+typedef enum UnitActiveState UnitActiveState;
+typedef enum UnitDependency UnitDependency;
+typedef struct UnitRef UnitRef;
+
+#include "set.h"
+#include "util.h"
+#include "list.h"
+#include "socket-util.h"
+#include "execute.h"
+#include "condition.h"
+#include "install.h"
+
+enum UnitType {
+        UNIT_SERVICE = 0,
+        UNIT_SOCKET,
+        UNIT_TARGET,
+        UNIT_DEVICE,
+        UNIT_MOUNT,
+        UNIT_AUTOMOUNT,
+        UNIT_SNAPSHOT,
+        UNIT_TIMER,
+        UNIT_SWAP,
+        UNIT_PATH,
+        _UNIT_TYPE_MAX,
+        _UNIT_TYPE_INVALID = -1
+};
+
+enum UnitLoadState {
+        UNIT_STUB,
+        UNIT_LOADED,
+        UNIT_ERROR,
+        UNIT_MERGED,
+        UNIT_MASKED,
+        _UNIT_LOAD_STATE_MAX,
+        _UNIT_LOAD_STATE_INVALID = -1
+};
+
+enum UnitActiveState {
+        UNIT_ACTIVE,
+        UNIT_RELOADING,
+        UNIT_INACTIVE,
+        UNIT_FAILED,
+        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_RELOADING;
+}
+
+static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) {
+        return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_RELOADING;
+}
+
+static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
+        return t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING;
+}
+
+static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
+        return t == UNIT_INACTIVE || t == UNIT_FAILED;
+}
+
+enum UnitDependency {
+        /* Positive dependencies */
+        UNIT_REQUIRES,
+        UNIT_REQUIRES_OVERRIDABLE,
+        UNIT_REQUISITE,
+        UNIT_REQUISITE_OVERRIDABLE,
+        UNIT_WANTS,
+        UNIT_BIND_TO,
+
+        /* Inverse of the above */
+        UNIT_REQUIRED_BY,             /* inverse of 'requires' and 'requisite' is 'required_by' */
+        UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */
+        UNIT_WANTED_BY,               /* inverse of 'wants' */
+        UNIT_BOUND_BY,                /* inverse of 'bind_to' */
+
+        /* Negative dependencies */
+        UNIT_CONFLICTS,               /* inverse of 'conflicts' is 'conflicted_by' */
+        UNIT_CONFLICTED_BY,
+
+        /* Order */
+        UNIT_BEFORE,                  /* inverse of 'before' is 'after' and vice versa */
+        UNIT_AFTER,
+
+        /* On Failure */
+        UNIT_ON_FAILURE,
+
+        /* Triggers (i.e. a socket triggers a service) */
+        UNIT_TRIGGERS,
+        UNIT_TRIGGERED_BY,
+
+        /* Propagate reloads */
+        UNIT_PROPAGATE_RELOAD_TO,
+        UNIT_PROPAGATE_RELOAD_FROM,
+
+        /* 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"
+#include "cgroup-attr.h"
+
+struct Unit {
+        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 */
+        usec_t fragment_mtime;
+
+        /* If there is something to do with this unit, then this is
+         * the job for it */
+        Job *job;
+
+        usec_t job_timeout;
+
+        /* References to this */
+        LIST_HEAD(UnitRef, refs);
+
+        /* Conditions to check */
+        LIST_HEAD(Condition, conditions);
+
+        dual_timestamp condition_timestamp;
+
+        dual_timestamp inactive_exit_timestamp;
+        dual_timestamp active_enter_timestamp;
+        dual_timestamp active_exit_timestamp;
+        dual_timestamp inactive_enter_timestamp;
+
+        /* Counterparts in the cgroup filesystem */
+        CGroupBonding *cgroup_bondings;
+        CGroupAttribute *cgroup_attributes;
+
+        /* Per type list */
+        LIST_FIELDS(Unit, units_by_type);
+
+        /* Load queue */
+        LIST_FIELDS(Unit, load_queue);
+
+        /* D-Bus queue */
+        LIST_FIELDS(Unit, dbus_queue);
+
+        /* Cleanup queue */
+        LIST_FIELDS(Unit, cleanup_queue);
+
+        /* GC queue */
+        LIST_FIELDS(Unit, gc_queue);
+
+        /* Used during GC sweeps */
+        unsigned gc_marker;
+
+        /* When deserializing, temporarily store the job type for this
+         * unit here, if there was a job scheduled */
+        int deserialized_job; /* This is actually of type JobType */
+
+        /* Error code when we didn't manage to load the unit (negative) */
+        int load_error;
+
+        /* Cached unit file state */
+        UnitFileState unit_file_state;
+
+        /* Garbage collect us we nobody wants or requires us anymore */
+        bool stop_when_unneeded;
+
+        /* Create default dependencies */
+        bool default_dependencies;
+
+        /* Refuse manual starting, allow starting only indirectly via dependency. */
+        bool refuse_manual_start;
+
+        /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */
+        bool refuse_manual_stop;
+
+        /* Allow isolation requests */
+        bool allow_isolate;
+
+        /* Isolate OnFailure unit */
+        bool on_failure_isolate;
+
+        /* Ignore this unit when isolating */
+        bool ignore_on_isolate;
+
+        /* Ignore this unit when snapshotting */
+        bool ignore_on_snapshot;
+
+        /* Did the last condition check suceed? */
+        bool condition_result;
+
+        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;
+
+        bool no_gc:1;
+
+        bool in_audit:1;
+};
+
+struct UnitRef {
+        /* Keeps tracks of references to a unit. This is useful so
+         * that we can merge two units if necessary and correct all
+         * references to them */
+
+        Unit* unit;
+        LIST_FIELDS(UnitRef, refs);
+};
+
+#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"
+#include "path.h"
+
+struct UnitVTable {
+        const char *suffix;
+
+        /* How much memory does an object of this unit type need */
+        size_t object_size;
+
+        /* Config file sections this unit type understands, separated
+         * by NUL chars */
+        const char *sections;
+
+        /* 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);
+
+        int (*kill)(Unit *u, KillWho w, KillMode m, int signo, DBusError *error);
+
+        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 fine grained 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);
+
+        /* Check whether unit needs a daemon reload */
+        bool (*need_daemon_reload)(Unit *u);
+
+        /* Reset failed state if we are in failed state */
+        void (*reset_failed)(Unit *u);
+
+        /* Called whenever any of the cgroups this unit watches for
+         * ran empty */
+        void (*cgroup_notify_empty)(Unit *u);
+
+        /* Called whenever a process of this unit sends us a message */
+        void (*notify_message)(Unit *u, pid_t pid, char **tags);
+
+        /* 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, DBusConnection *c, DBusMessage *message);
+
+        /* Return the unit this unit is following */
+        Unit *(*following)(Unit *u);
+
+        /* Return the set of units that are following each other */
+        int (*following_set)(Unit *u, Set **s);
+
+        /* 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);
+
+        /* When sending out PropertiesChanged signal, which properties
+         * shall be invalidated? This is a NUL separated list of
+         * strings, to minimize relocations a little. */
+        const char *bus_invalidating_properties;
+
+        /* The interface name */
+        const char *bus_interface;
+
+        /* Can units of this type have multiple names? */
+        bool no_alias:1;
+
+        /* Instances make no sense for this type */
+        bool no_instances:1;
+
+        /* Exclude from automatic gc */
+        bool no_gc:1;
+
+        /* Show status updates on the console */
+        bool show_status:1;
+};
+
+extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
+
+#define UNIT_VTABLE(u) unit_vtable[(u)->type]
+
+/* For casting a unit into the various unit types */
+#define DEFINE_CAST(UPPERCASE, MixedCase)                               \
+        static inline MixedCase* UPPERCASE(Unit *u) {                   \
+                if (_unlikely_(!u || u->type != UNIT_##UPPERCASE))      \
+                        return NULL;                                    \
+                                                                        \
+                return (MixedCase*) u;                                  \
+        }
+
+/* For casting the various unit types into a unit */
+#define UNIT(u) (&(u)->meta)
+
+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);
+DEFINE_CAST(PATH, Path);
+
+Unit *unit_new(Manager *m, size_t size);
+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_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, 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_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, 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_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, 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_cgroups(Unit *u);
+CGroupBonding* unit_get_default_cgroup(Unit *u);
+int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback);
+
+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(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);
+bool unit_can_isolate(Unit *u);
+
+int unit_start(Unit *u);
+int unit_stop(Unit *u);
+int unit_reload(Unit *u);
+
+int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error);
+
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success);
+
+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);
+
+int unit_coldplug(Unit *u);
+
+void unit_status_printf(Unit *u, const char *status, const char *format, ...);
+
+bool unit_need_daemon_reload(Unit *u);
+
+void unit_reset_failed(Unit *u);
+
+Unit *unit_following(Unit *u);
+
+bool unit_pending_inactive(Unit *u);
+bool unit_pending_active(Unit *u);
+
+int unit_add_default_target_dependency(Unit *u, Unit *target);
+
+int unit_following_set(Unit *u, Set **s);
+
+UnitType unit_name_to_type(const char *n);
+bool unit_name_is_valid(const char *n, bool template_ok);
+
+void unit_trigger_on_failure(Unit *u);
+
+bool unit_condition_test(Unit *u);
+
+UnitFileState unit_get_unit_file_state(Unit *u);
+
+Unit* unit_ref_set(UnitRef *ref, Unit *u);
+void unit_ref_unset(UnitRef *ref);
+
+#define UNIT_DEREF(ref) ((ref).unit)
+
+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);
+
+#endif
diff --git a/src/dbus-automount.c b/src/dbus-automount.c
deleted file mode 100644
index 8e45f81..0000000
--- a/src/dbus-automount.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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-automount.h"
-#include "dbus-common.h"
-
-#define BUS_AUTOMOUNT_INTERFACE                                      \
-        " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \
-        "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"
-
-#define INTROSPECTION                                                \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                    \
-        "<node>\n"                                                   \
-        BUS_UNIT_INTERFACE                                           \
-        BUS_AUTOMOUNT_INTERFACE                                      \
-        BUS_PROPERTIES_INTERFACE                                     \
-        BUS_PEER_INTERFACE                                           \
-        BUS_INTROSPECTABLE_INTERFACE                                 \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Automount\0"
-
-const char bus_automount_interface[] _introspect_("Automount") = BUS_AUTOMOUNT_INTERFACE;
-
-const char bus_automount_invalidating_properties[] =
-        "Result\0";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_automount_append_automount_result, automount_result, AutomountResult);
-
-static const BusProperty bus_automount_properties[] = {
-        { "Where",         bus_property_append_string, "s", offsetof(Automount, where),    true },
-        { "DirectoryMode", bus_property_append_mode,   "u", offsetof(Automount, directory_mode) },
-        { "Result",        bus_automount_append_automount_result, "s", offsetof(Automount, result) },
-        { NULL, }
-};
-
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Automount *am = AUTOMOUNT(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",      bus_unit_properties,      u  },
-                { "org.freedesktop.systemd1.Automount", bus_automount_properties, am },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-automount.h b/src/dbus-automount.h
deleted file mode 100644
index 2fc8345..0000000
--- a/src/dbus-automount.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_automount_interface[];
-extern const char bus_automount_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-device.c b/src/dbus-device.c
deleted file mode 100644
index b39fb9d..0000000
--- a/src/dbus-device.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "dbus-common.h"
-
-#define BUS_DEVICE_INTERFACE                                            \
-        " <interface name=\"org.freedesktop.systemd1.Device\">\n"       \
-        "  <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>\n" \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_DEVICE_INTERFACE                                            \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Device\0"
-
-const char bus_device_interface[] _introspect_("Device") = BUS_DEVICE_INTERFACE;
-
-const char bus_device_invalidating_properties[] =
-        "SysFSPath\0";
-
-static const BusProperty bus_device_properties[] = {
-        { "SysFSPath", bus_property_append_string, "s", offsetof(Device, sysfs), true },
-        { NULL, }
-};
-
-
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Device *d = DEVICE(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",   bus_unit_properties,   u },
-                { "org.freedesktop.systemd1.Device", bus_device_properties, d },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-device.h b/src/dbus-device.h
deleted file mode 100644
index fba270b..0000000
--- a/src/dbus-device.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_device_interface[];
-extern const char bus_device_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-execute.c b/src/dbus-execute.c
deleted file mode 100644
index 1fd2b21..0000000
--- a/src/dbus-execute.c
+++ /dev/null
@@ -1,422 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <sys/prctl.h>
-
-#include "dbus-execute.h"
-#include "missing.h"
-#include "ioprio.h"
-#include "strv.h"
-#include "dbus-common.h"
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode);
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
-
-int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
-        char **env_files = data, **j;
-        DBusMessageIter sub, sub2;
-
-        assert(i);
-        assert(property);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
-                return -ENOMEM;
-
-        STRV_FOREACH(j, env_files) {
-                dbus_bool_t b = false;
-                char *fn = *j;
-
-                if (fn[0] == '-') {
-                        b = true;
-                        fn++;
-                }
-
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int32_t n;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->oom_score_adjust_set)
-                n = c->oom_score_adjust;
-        else {
-                char *t;
-
-                n = 0;
-                if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
-                        safe_atoi(t, &n);
-                        free(t);
-                } else if (read_one_line_file("/proc/self/oom_adj", &t) >= 0) {
-                        safe_atoi(t, &n);
-                        free(t);
-
-                        if (n == OOM_ADJUST_MAX)
-                                n = OOM_SCORE_ADJ_MAX;
-                        else
-                                n = (n * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
-                }
-        }
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int32_t n;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->nice_set)
-                n = c->nice;
-        else
-                n = getpriority(PRIO_PROCESS, 0);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int32_t n;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->ioprio_set)
-                n = c->ioprio;
-        else
-                n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int32_t n;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->cpu_sched_set)
-                n = c->cpu_sched_policy;
-        else
-                n = sched_getscheduler(0);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int32_t n;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->cpu_sched_set)
-                n = c->cpu_sched_priority;
-        else {
-                struct sched_param p;
-                n = 0;
-
-                zero(p);
-                if (sched_getparam(0, &p) >= 0)
-                        n = p.sched_priority;
-        }
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        dbus_bool_t b;
-        DBusMessageIter sub;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
-                return -ENOMEM;
-
-        if (c->cpuset)
-                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
-        else
-                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
-
-        if (!b)
-                return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->timer_slack_nsec_set)
-                u = (uint64_t) c->timer_slack_nsec;
-        else
-                u = (uint64_t) prctl(PR_GET_TIMERSLACK);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        uint64_t normal, inverted;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        /* We store this negated internally, to match the kernel, but
-         * we expose it normalized. */
-
-        normal = *(uint64_t*) data;
-        inverted = ~normal;
-
-        return bus_property_append_uint64(i, property, &inverted);
-}
-
-int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        char *t = NULL;
-        const char *s;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        if (c->capabilities)
-                s = t = cap_to_text(c->capabilities, NULL);
-        else
-                s = "";
-
-        if (!s)
-                return -ENOMEM;
-
-        b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
-
-        if (t)
-                cap_free(t);
-
-        if (!b)
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
-        ExecContext *c = data;
-        int r;
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(c);
-
-        assert_se((r = rlimit_from_string(property)) >= 0);
-
-        if (c->rlimit[r])
-                u = (uint64_t) c->rlimit[r]->rlim_max;
-        else {
-                struct rlimit rl;
-
-                zero(rl);
-                getrlimit(r, &rl);
-
-                u = (uint64_t) rl.rlim_max;
-        }
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
-        ExecCommand *c = data;
-        DBusMessageIter sub, sub2, sub3;
-
-        assert(i);
-        assert(property);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
-                return -ENOMEM;
-
-        LIST_FOREACH(command, c, c) {
-                char **l;
-                uint32_t pid;
-                int32_t code, status;
-                dbus_bool_t b;
-
-                if (!c->path)
-                        continue;
-
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
-                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
-                        return -ENOMEM;
-
-                STRV_FOREACH(l, c->argv)
-                        if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
-                                return -ENOMEM;
-
-                pid = (uint32_t) c->exec_status.pid;
-                code = (int32_t) c->exec_status.code;
-                status = (int32_t) c->exec_status.status;
-
-                b = !!c->ignore;
-
-                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
-                        return -ENOMEM;
-
-                if (!dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-const BusProperty bus_exec_context_properties[] = {
-        { "Environment",              bus_property_append_strv,             "as", offsetof(ExecContext, environment),            true },
-        { "EnvironmentFiles",         bus_execute_append_env_files,      "a(sb)", offsetof(ExecContext, environment_files),      true },
-        { "UMask",                    bus_property_append_mode,              "u", offsetof(ExecContext, umask)                        },
-        { "LimitCPU",                 bus_execute_append_rlimits,            "t", 0 },
-        { "LimitFSIZE",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitDATA",                bus_execute_append_rlimits,            "t", 0 },
-        { "LimitSTACK",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitCORE",                bus_execute_append_rlimits,            "t", 0 },
-        { "LimitRSS",                 bus_execute_append_rlimits,            "t", 0 },
-        { "LimitNOFILE",              bus_execute_append_rlimits,            "t", 0 },
-        { "LimitAS",                  bus_execute_append_rlimits,            "t", 0 },
-        { "LimitNPROC",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitMEMLOCK",             bus_execute_append_rlimits,            "t", 0 },
-        { "LimitLOCKS",               bus_execute_append_rlimits,            "t", 0 },
-        { "LimitSIGPENDING",          bus_execute_append_rlimits,            "t", 0 },
-        { "LimitMSGQUEUE",            bus_execute_append_rlimits,            "t", 0 },
-        { "LimitNICE",                bus_execute_append_rlimits,            "t", 0 },
-        { "LimitRTPRIO",              bus_execute_append_rlimits,            "t", 0 },
-        { "LimitRTTIME",              bus_execute_append_rlimits,            "t", 0 },
-        { "WorkingDirectory",         bus_property_append_string,            "s", offsetof(ExecContext, working_directory),      true },
-        { "RootDirectory",            bus_property_append_string,            "s", offsetof(ExecContext, root_directory),         true },
-        { "OOMScoreAdjust",           bus_execute_append_oom_score_adjust,   "i", 0 },
-        { "Nice",                     bus_execute_append_nice,               "i", 0 },
-        { "IOScheduling",             bus_execute_append_ioprio,             "i", 0 },
-        { "CPUSchedulingPolicy",      bus_execute_append_cpu_sched_policy,   "i", 0 },
-        { "CPUSchedulingPriority",    bus_execute_append_cpu_sched_priority, "i", 0 },
-        { "CPUAffinity",              bus_execute_append_affinity,          "ay", 0 },
-        { "TimerSlackNSec",           bus_execute_append_timer_slack_nsec,   "t", 0 },
-        { "CPUSchedulingResetOnFork", bus_property_append_bool,              "b", offsetof(ExecContext, cpu_sched_reset_on_fork)      },
-        { "NonBlocking",              bus_property_append_bool,              "b", offsetof(ExecContext, non_blocking)                 },
-        { "StandardInput",            bus_execute_append_input,              "s", offsetof(ExecContext, std_input)                    },
-        { "StandardOutput",           bus_execute_append_output,             "s", offsetof(ExecContext, std_output)                   },
-        { "StandardError",            bus_execute_append_output,             "s", offsetof(ExecContext, std_error)                    },
-        { "TTYPath",                  bus_property_append_string,            "s", offsetof(ExecContext, tty_path),               true },
-        { "TTYReset",                 bus_property_append_bool,              "b", offsetof(ExecContext, tty_reset)                    },
-        { "TTYVHangup",               bus_property_append_bool,              "b", offsetof(ExecContext, tty_vhangup)                  },
-        { "TTYVTDisallocate",         bus_property_append_bool,              "b", offsetof(ExecContext, tty_vt_disallocate)           },
-        { "SyslogPriority",           bus_property_append_int,               "i", offsetof(ExecContext, syslog_priority)              },
-        { "SyslogIdentifier",         bus_property_append_string,            "s", offsetof(ExecContext, syslog_identifier),      true },
-        { "SyslogLevelPrefix",        bus_property_append_bool,              "b", offsetof(ExecContext, syslog_level_prefix)          },
-        { "Capabilities",             bus_execute_append_capabilities,       "s", 0 },
-        { "SecureBits",               bus_property_append_int,               "i", offsetof(ExecContext, secure_bits)                  },
-        { "CapabilityBoundingSet",    bus_execute_append_capability_bs,      "t", offsetof(ExecContext, capability_bounding_set_drop) },
-        { "User",                     bus_property_append_string,            "s", offsetof(ExecContext, user),                   true },
-        { "Group",                    bus_property_append_string,            "s", offsetof(ExecContext, group),                  true },
-        { "SupplementaryGroups",      bus_property_append_strv,             "as", offsetof(ExecContext, supplementary_groups),   true },
-        { "TCPWrapName",              bus_property_append_string,            "s", offsetof(ExecContext, tcpwrap_name),           true },
-        { "PAMName",                  bus_property_append_string,            "s", offsetof(ExecContext, pam_name),               true },
-        { "ReadWriteDirectories",     bus_property_append_strv,             "as", offsetof(ExecContext, read_write_dirs),        true },
-        { "ReadOnlyDirectories",      bus_property_append_strv,             "as", offsetof(ExecContext, read_only_dirs),         true },
-        { "InaccessibleDirectories",  bus_property_append_strv,             "as", offsetof(ExecContext, inaccessible_dirs),      true },
-        { "MountFlags",               bus_property_append_ul,                "t", offsetof(ExecContext, mount_flags)                  },
-        { "PrivateTmp",               bus_property_append_bool,              "b", offsetof(ExecContext, private_tmp)                  },
-        { "PrivateNetwork",           bus_property_append_bool,              "b", offsetof(ExecContext, private_network)              },
-        { "SameProcessGroup",         bus_property_append_bool,              "b", offsetof(ExecContext, same_pgrp)                    },
-        { "KillMode",                 bus_execute_append_kill_mode,          "s", offsetof(ExecContext, kill_mode)                    },
-        { "KillSignal",               bus_property_append_int,               "i", offsetof(ExecContext, kill_signal)                  },
-        { "UtmpIdentifier",           bus_property_append_string,            "s", offsetof(ExecContext, utmp_id),                true },
-        { "ControlGroupModify",       bus_property_append_bool,              "b", offsetof(ExecContext, control_group_modify)         },
-        { "ControlGroupPersistent",   bus_property_append_tristate_false,    "b", offsetof(ExecContext, control_group_persistent)     },
-        { "IgnoreSIGPIPE",            bus_property_append_bool,              "b", offsetof(ExecContext, ignore_sigpipe          )     },
-        { NULL, }
-};
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
deleted file mode 100644
index 03cd69d..0000000
--- a/src/dbus-execute.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-#include "dbus-common.h"
-
-#define BUS_EXEC_STATUS_INTERFACE(prefix)                               \
-        "  <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "StartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "ExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n"
-
-#define BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"UMask\" type=\"u\" access=\"read\"/>\n"     \
-        "  <property name=\"LimitCPU\" type=\"t\" access=\"read\"/>\n"  \
-        "  <property name=\"LimitFSIZE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitDATA\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitSTACK\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitCORE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitRSS\" type=\"t\" access=\"read\"/>\n"  \
-        "  <property name=\"LimitNOFILE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitAS\" type=\"t\" access=\"read\"/>\n"   \
-        "  <property name=\"LimitNPROC\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitMEMLOCK\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitLOCKS\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitSIGPENDING\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitMSGQUEUE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitNICE\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitRTPRIO\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LimitRTTIME\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"OOMScoreAdjust\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"Nice\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"IOScheduling\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CPUSchedulingPolicy\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CPUSchedulingPriority\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CPUAffinity\" type=\"ay\" access=\"read\"/>\n" \
-        "  <property name=\"TimerSlackNS\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"StandardInput\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"StandardError\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"TTYReset\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"TTYVHangup\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"TTYVTDisallocate\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SyslogLevelPrefix\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"CapabilityBoundingSet\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"User\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Group\" type=\"s\" access=\"read\"/>\n"     \
-        "  <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"TCPWrapName\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"ReadWriteDirectories\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"ReadOnlyDirectories\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupModify\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupPersistent\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"PrivateNetwork\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"IgnoreSIGPIPE\" type=\"b\" access=\"read\"/>\n"
-
-#define BUS_EXEC_COMMAND_INTERFACE(name)                             \
-        "  <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
-
-extern const BusProperty bus_exec_context_properties[];
-
-#define BUS_EXEC_COMMAND_PROPERTY(name, command, indirect)             \
-        { name, bus_execute_append_command, "a(sasbttttuii)", (command), (indirect), NULL }
-
-int bus_execute_append_output(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_input(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data);
-int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data);
-
-#endif
diff --git a/src/dbus-job.c b/src/dbus-job.c
deleted file mode 100644
index ab6d610..0000000
--- a/src/dbus-job.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "dbus-common.h"
-
-#define BUS_JOB_INTERFACE                                             \
-        " <interface name=\"org.freedesktop.systemd1.Job\">\n"        \
-        "  <method name=\"Cancel\"/>\n"                               \
-        "  <property name=\"Id\" type=\"u\" access=\"read\"/>\n"      \
-        "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>\n" \
-        "  <property name=\"JobType\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"   \
-        " </interface>\n"
-
-#define INTROSPECTION                                                 \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                     \
-        "<node>\n"                                                    \
-        BUS_JOB_INTERFACE                                             \
-        BUS_PROPERTIES_INTERFACE                                      \
-        BUS_PEER_INTERFACE                                            \
-        BUS_INTROSPECTABLE_INTERFACE                                  \
-        "</node>\n"
-
-const char bus_job_interface[] _introspect_("Job") = BUS_JOB_INTERFACE;
-
-#define INTERFACES_LIST                              \
-        BUS_GENERIC_INTERFACES_LIST                  \
-        "org.freedesktop.systemd1.Job\0"
-
-#define INVALIDATING_PROPERTIES                 \
-        "State\0"
-
-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(DBusMessageIter *i, const char *property, void *data) {
-        Job *j = data;
-        DBusMessageIter sub;
-        char *p;
-
-        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->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 const BusProperty bus_job_properties[] = {
-        { "Id",      bus_property_append_uint32, "u", offsetof(Job, id)    },
-        { "State",   bus_job_append_state,       "s", offsetof(Job, state) },
-        { "JobType", bus_job_append_type,        "s", offsetof(Job, type)  },
-        { "Unit",    bus_job_append_unit,     "(so)", 0 },
-        { NULL, }
-};
-
-static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connection, DBusMessage *message) {
-        DBusMessage *reply = NULL;
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                job_finish_and_invalidate(j, JOB_CANCELED);
-
-        } else {
-                const BusBoundProperties bps[] = {
-                        { "org.freedesktop.systemd1.Job", bus_job_properties, j },
-                        { NULL, }
-                };
-                return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
-        }
-
-        if (reply) {
-                if (!dbus_connection_send(connection, 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;
-        DBusMessage *reply;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) {
-                /* Be nice to gdbus and return introspection data for our mid-level paths */
-
-                if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-                        char *introspection = NULL;
-                        FILE *f;
-                        Iterator i;
-                        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(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-                              "<node>\n", f);
-
-                        fputs(BUS_INTROSPECTABLE_INTERFACE, f);
-                        fputs(BUS_PEER_INTERFACE, f);
-
-                        HASHMAP_FOREACH(j, m->jobs, i)
-                                fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
-
-                        fputs("</node>\n", 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);
-
-                        if (!dbus_connection_send(connection, reply, NULL))
-                                goto oom;
-
-                        dbus_message_unref(reply);
-
-                        return DBUS_HANDLER_RESULT_HANDLED;
-                }
-
-                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-        }
-
-        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) {
-                        DBusError e;
-
-                        dbus_error_init(&e);
-                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job");
-                        return bus_send_error_reply(connection, message, &e, r);
-                }
-
-                return bus_send_error_reply(connection, message, NULL, r);
-        }
-
-        return bus_job_message_dispatch(j, connection, message);
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-const DBusObjectPathVTable bus_job_vtable = {
-        .message_function = bus_job_message_handler
-};
-
-static int job_send_message(Job *j, DBusMessage *m) {
-        int r;
-
-        assert(j);
-        assert(m);
-
-        if (bus_has_subscriber(j->manager)) {
-                if ((r = bus_broadcast(j->manager, m)) < 0)
-                        return r;
-
-        } else  if (j->bus_client) {
-                /* If nobody is subscribed, we just send the message
-                 * to the client which created the job */
-
-                assert(j->bus);
-
-                if (!dbus_message_set_destination(m, j->bus_client))
-                        return -ENOMEM;
-
-                if (!dbus_connection_send(j->bus, m, NULL))
-                        return -ENOMEM;
-        }
-
-        return 0;
-}
-
-void bus_job_send_change_signal(Job *j) {
-        char *p = NULL;
-        DBusMessage *m = NULL;
-
-        assert(j);
-
-        if (j->in_dbus_queue) {
-                LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
-                j->in_dbus_queue = false;
-        }
-
-        if (!bus_has_subscriber(j->manager) && !j->bus_client) {
-                j->sent_dbus_new_signal = true;
-                return;
-        }
-
-        if (!(p = job_dbus_path(j)))
-                goto oom;
-
-        if (j->sent_dbus_new_signal) {
-                /* Send a properties changed signal */
-
-                if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES)))
-                        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 (job_send_message(j, m) < 0)
-                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;
-        const char *r;
-
-        assert(j);
-
-        if (!bus_has_subscriber(j->manager) && !j->bus_client)
-                return;
-
-        if (!j->sent_dbus_new_signal)
-                bus_job_send_change_signal(j);
-
-        if (!(p = job_dbus_path(j)))
-                goto oom;
-
-        if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved")))
-                goto oom;
-
-        r = job_result_to_string(j->result);
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_UINT32, &j->id,
-                                      DBUS_TYPE_OBJECT_PATH, &p,
-                                      DBUS_TYPE_STRING, &r,
-                                      DBUS_TYPE_INVALID))
-                goto oom;
-
-        if (job_send_message(j, m) < 0)
-                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
deleted file mode 100644
index 103c2ff..0000000
--- a/src/dbus-job.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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>
-
-#include "job.h"
-
-void bus_job_send_change_signal(Job *j);
-void bus_job_send_removed_signal(Job *j);
-
-extern const DBusObjectPathVTable bus_job_vtable;
-
-extern const char bus_job_interface[];
-
-#endif
diff --git a/src/dbus-loop.h b/src/dbus-loop.h
deleted file mode 100644
index 0bbdfe5..0000000
--- a/src/dbus-loop.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foodbusloophfoo
-#define foodbusloophfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2011 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>
-
-int bus_loop_open(DBusConnection *c);
-int bus_loop_dispatch(int fd);
-
-#endif
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
deleted file mode 100644
index 3bf0c07..0000000
--- a/src/dbus-manager.c
+++ /dev/null
@@ -1,1544 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <unistd.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-manager.h"
-#include "strv.h"
-#include "bus-errors.h"
-#include "build.h"
-#include "dbus-common.h"
-#include "install.h"
-
-#define BUS_MANAGER_INTERFACE_BEGIN                                     \
-        " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
-
-#define BUS_MANAGER_INTERFACE_METHODS                                   \
-        "  <method name=\"GetUnit\">\n"                                 \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetUnitByPID\">\n"                            \
-        "   <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n"          \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"LoadUnit\">\n"                                \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"StartUnit\">\n"                               \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"StartUnitReplace\">\n"                        \
-        "   <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n"     \
-        "   <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n"     \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"StopUnit\">\n"                                \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadUnit\">\n"                              \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"RestartUnit\">\n"                             \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"TryRestartUnit\">\n"                          \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadOrRestartUnit\">\n"                     \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadOrTryRestartUnit\">\n"                  \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"KillUnit\">\n"                                \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"ResetFailedUnit\">\n"                         \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetJob\">\n"                                  \
-        "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ClearJobs\"/>\n"                              \
-        "  <method name=\"ResetFailed\"/>\n"                            \
-        "  <method name=\"ListUnits\">\n"                               \
-        "   <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"ListJobs\">\n"                                \
-        "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"Subscribe\"/>\n"                              \
-        "  <method name=\"Unsubscribe\"/>\n"                            \
-        "  <method name=\"Dump\"/>\n"                                   \
-        "  <method name=\"CreateSnapshot\">\n"                          \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <method name=\"Reload\"/>\n"                                 \
-        "  <method name=\"Reexecute\"/>\n"                              \
-        "  <method name=\"Exit\"/>\n"                                   \
-        "  <method name=\"Reboot\"/>\n"                                 \
-        "  <method name=\"PowerOff\"/>\n"                               \
-        "  <method name=\"Halt\"/>\n"                                   \
-        "  <method name=\"KExec\"/>\n"                                  \
-        "  <method name=\"SetEnvironment\">\n"                          \
-        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnsetEnvironment\">\n"                        \
-        "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnsetAndSetEnvironment\">\n"                  \
-        "   <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"set\" type=\"as\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ListUnitFiles\">\n"                            \
-        "   <arg name=\"changes\" type=\"a(ss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetUnitFileState\">\n"                        \
-        "   <arg name=\"file\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"state\" type=\"s\" direction=\"out\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"EnableUnitFiles\">\n"                         \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"DisableUnitFiles\">\n"                        \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReenableUnitFiles\">\n"                       \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"LinkUnitFiles\">\n"                           \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"PresetUnitFiles\">\n"                         \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"MaskUnitFiles\">\n"                           \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnmaskUnitFiles\">\n"                         \
-        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
-        "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
-        "  </method>\n"
-
-#define BUS_MANAGER_INTERFACE_SIGNALS                                   \
-        "  <signal name=\"UnitNew\">\n"                                 \
-        "   <arg name=\"id\" type=\"s\"/>\n"                            \
-        "   <arg name=\"unit\" type=\"o\"/>\n"                          \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"UnitRemoved\">\n"                             \
-        "   <arg name=\"id\" type=\"s\"/>\n"                            \
-        "   <arg name=\"unit\" type=\"o\"/>\n"                          \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"JobNew\">\n"                                  \
-        "   <arg name=\"id\" type=\"u\"/>\n"                            \
-        "   <arg name=\"job\" type=\"o\"/>\n"                           \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"JobRemoved\">\n"                              \
-        "   <arg name=\"id\" type=\"u\"/>\n"                            \
-        "   <arg name=\"job\" type=\"o\"/>\n"                           \
-        "   <arg name=\"result\" type=\"s\"/>\n"                        \
-        "  </signal>"                                                   \
-        "  <signal name=\"StartupFinished\">\n"                         \
-        "   <arg name=\"kernel\" type=\"t\"/>\n"                        \
-        "   <arg name=\"initrd\" type=\"t\"/>\n"                        \
-        "   <arg name=\"userspace\" type=\"t\"/>\n"                     \
-        "   <arg name=\"total\" type=\"t\"/>\n"                         \
-        "  </signal>"                                                   \
-        "  <signal name=\"UnitFilesChanged\"/>\n"
-
-#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
-        "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"Features\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n"  \
-        "  <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
-        "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
-        "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
-        "  <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Progress\" type=\"d\" access=\"read\"/>\n"  \
-        "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"MountAuto\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"SwapAuto\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"read\"/>\n"
-
-#ifdef HAVE_SYSV_COMPAT
-#define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV                           \
-        "  <property name=\"SysVConsole\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
-#else
-#define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
-#endif
-
-#define BUS_MANAGER_INTERFACE_END                                       \
-        " </interface>\n"
-
-#define BUS_MANAGER_INTERFACE                                           \
-        BUS_MANAGER_INTERFACE_BEGIN                                     \
-        BUS_MANAGER_INTERFACE_METHODS                                   \
-        BUS_MANAGER_INTERFACE_SIGNALS                                   \
-        BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
-        BUS_MANAGER_INTERFACE_PROPERTIES_SYSV                           \
-        BUS_MANAGER_INTERFACE_END
-
-#define INTROSPECTION_BEGIN                                             \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_MANAGER_INTERFACE                                           \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE
-
-#define INTROSPECTION_END                                               \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_GENERIC_INTERFACES_LIST                  \
-        "org.freedesktop.systemd1.Manager\0"
-
-const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
-
-static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-        Manager *m = data;
-        char buf[LINE_MAX] = "", *e = buf, *p = NULL;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        if (m->taint_usr)
-                e = stpcpy(e, "usr-separate-fs ");
-
-        if (readlink_malloc("/etc/mtab", &p) < 0)
-                e = stpcpy(e, "etc-mtab-not-symlink ");
-        else
-                free(p);
-
-        if (access("/proc/cgroups", F_OK) < 0)
-                stpcpy(e, "cgroups-missing ");
-
-        t = strstrip(buf);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        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_set_log_target(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        assert(i);
-        assert(property);
-
-        dbus_message_iter_get_basic(i, &t);
-
-        return log_set_target_from_string(t);
-}
-
-static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        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_set_log_level(DBusMessageIter *i, const char *property, void *data) {
-        const char *t;
-
-        assert(i);
-        assert(property);
-
-        dbus_message_iter_get_basic(i, &t);
-
-        return log_set_max_level_from_string(t);
-}
-
-static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        uint32_t u;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        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(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        uint32_t u;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        u = hashmap_size(m->jobs);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
-        double d;
-        Manager *m = data;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        if (dual_timestamp_is_set(&m->finish_timestamp))
-                d = 1.0;
-        else
-                d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static const char *message_get_sender_with_fallback(DBusMessage *m) {
-        const char *s;
-
-        assert(m);
-
-        if ((s = dbus_message_get_sender(m)))
-                return s;
-
-        /* When the message came in from a direct connection the
-         * message will have no sender. We fix that here. */
-
-        return ":no-sender";
-}
-
-static DBusMessage *message_from_file_changes(
-                DBusMessage *m,
-                UnitFileChange *changes,
-                unsigned n_changes,
-                int carries_install_info) {
-
-        DBusMessageIter iter, sub, sub2;
-        DBusMessage *reply;
-        unsigned i;
-
-        reply = dbus_message_new_method_return(m);
-        if (!reply)
-                return NULL;
-
-        dbus_message_iter_init_append(reply, &iter);
-
-        if (carries_install_info >= 0) {
-                dbus_bool_t b;
-
-                b = !!carries_install_info;
-                if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
-                        goto oom;
-        }
-
-        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
-                goto oom;
-
-        for (i = 0; i < n_changes; i++) {
-                const char *type, *path, *source;
-
-                type = unit_file_change_type_to_string(changes[i].type);
-                path = strempty(changes[i].path);
-                source = strempty(changes[i].source);
-
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        goto oom;
-        }
-
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                goto oom;
-
-        return reply;
-
-oom:
-        dbus_message_unref(reply);
-        return NULL;
-}
-
-static int bus_manager_send_unit_files_changed(Manager *m) {
-        DBusMessage *s;
-        int r;
-
-        s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
-        if (!s)
-                return -ENOMEM;
-
-        r = bus_broadcast(m, s);
-        dbus_message_unref(s);
-
-        return r;
-}
-
-static const char systemd_property_string[] =
-        PACKAGE_STRING "\0"
-        DISTRIBUTION "\0"
-        SYSTEMD_FEATURES;
-
-static const BusProperty bus_systemd_properties[] = {
-        { "Version",       bus_property_append_string,    "s",  0                                             },
-        { "Distribution",  bus_property_append_string,    "s",  sizeof(PACKAGE_STRING)                        },
-        { "Features",      bus_property_append_string,    "s",  sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
-        { NULL, }
-};
-
-static const BusProperty bus_manager_properties[] = {
-        { "RunningAs",     bus_manager_append_running_as,          "s", offsetof(Manager, running_as)                  },
-        { "Tainted",       bus_manager_append_tainted,             "s", 0                                              },
-        { "InitRDTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, initrd_timestamp.realtime)   },
-        { "InitRDTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, initrd_timestamp.monotonic)  },
-        { "StartupTimestamp", bus_property_append_uint64,          "t", offsetof(Manager, startup_timestamp.realtime)  },
-        { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
-        { "FinishTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, finish_timestamp.realtime)   },
-        { "FinishTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, finish_timestamp.monotonic)  },
-        { "LogLevel",      bus_manager_append_log_level,           "s", 0,                                             0, bus_manager_set_log_level },
-        { "LogTarget",     bus_manager_append_log_target,          "s", 0,                                             0, bus_manager_set_log_target },
-        { "NNames",        bus_manager_append_n_names,             "u", 0                                              },
-        { "NJobs",         bus_manager_append_n_jobs,              "u", 0                                              },
-        { "NInstalledJobs",bus_property_append_uint32,             "u", offsetof(Manager, n_installed_jobs)            },
-        { "NFailedJobs",   bus_property_append_uint32,             "u", offsetof(Manager, n_failed_jobs)               },
-        { "Progress",      bus_manager_append_progress,            "d", 0                                              },
-        { "Environment",   bus_property_append_strv,              "as", offsetof(Manager, environment),                true },
-        { "ConfirmSpawn",  bus_property_append_bool,               "b", offsetof(Manager, confirm_spawn)               },
-        { "ShowStatus",    bus_property_append_bool,               "b", offsetof(Manager, show_status)                 },
-        { "UnitPath",      bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.unit_path),     true },
-        { "NotifySocket",  bus_property_append_string,             "s", offsetof(Manager, notify_socket),              true },
-        { "ControlGroupHierarchy", bus_property_append_string,     "s", offsetof(Manager, cgroup_hierarchy),           true },
-        { "MountAuto",     bus_property_append_bool,               "b", offsetof(Manager, mount_auto)                  },
-        { "SwapAuto",      bus_property_append_bool,               "b", offsetof(Manager, swap_auto)                   },
-        { "DefaultControllers", bus_property_append_strv,         "as", offsetof(Manager, default_controllers),        true },
-        { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output)          },
-        { "DefaultStandardError",  bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error)           },
-        { "RuntimeWatchdogUSec", bus_property_append_usec,         "t", offsetof(Manager, runtime_watchdog),           },
-        { "ShutdownWatchdogUSec", bus_property_append_usec,        "t", offsetof(Manager, shutdown_watchdog),          },
-#ifdef HAVE_SYSV_COMPAT
-        { "SysVConsole",   bus_property_append_bool,               "b", offsetof(Manager, sysv_console)                },
-        { "SysVInitPath",  bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.sysvinit_path), true },
-        { "SysVRcndPath",  bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.sysvrcnd_path), true },
-#endif
-        { NULL, }
-};
-
-static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
-        Manager *m = data;
-
-        int r;
-        DBusError error;
-        DBusMessage *reply = NULL;
-        char * path = NULL;
-        JobType job_type = _JOB_TYPE_INVALID;
-        bool reload_if_possible = false;
-        const char *member;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        member = dbus_message_get_member(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(connection, message, &error, -EINVAL);
-
-                if (!(u = manager_get_unit(m, name))) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -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", "GetUnitByPID")) {
-                Unit *u;
-                uint32_t pid;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &pid,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
-                        return bus_send_error_reply(connection, message, &error, -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(connection, message, &error, -EINVAL);
-
-                if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
-                        return bus_send_error_reply(connection, message, &error, 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", "StartUnit"))
-                job_type = JOB_START;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
-                job_type = JOB_START;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
-                job_type = JOB_STOP;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
-                job_type = JOB_RELOAD;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
-                job_type = JOB_RESTART;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
-                job_type = JOB_TRY_RESTART;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
-                reload_if_possible = true;
-                job_type = JOB_RESTART;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
-                reload_if_possible = true;
-                job_type = JOB_TRY_RESTART;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
-                const char *name, *swho, *smode;
-                int32_t signo;
-                Unit *u;
-                KillMode mode;
-                KillWho who;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_STRING, &swho,
-                                    DBUS_TYPE_STRING, &smode,
-                                    DBUS_TYPE_INT32, &signo,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (isempty(swho))
-                        who = KILL_ALL;
-                else {
-                        who = kill_who_from_string(swho);
-                        if (who < 0)
-                                return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
-
-                if (isempty(smode))
-                        mode = KILL_CONTROL_GROUP;
-                else {
-                        mode = kill_mode_from_string(smode);
-                        if (mode < 0)
-                                return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
-
-                if (signo <= 0 || signo >= _NSIG)
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (!(u = manager_get_unit(m, name))) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
-
-                if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        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(connection, message, &error, -EINVAL);
-
-                if (!(j = manager_get_job(m, id))) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
-                        return bus_send_error_reply(connection, message, &error, -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", "ResetFailed")) {
-
-                manager_reset_failed(m);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
-                const char *name;
-                Unit *u;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (!(u = manager_get_unit(m, name))) {
-                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-                }
-
-                unit_reset_failed(u);
-
-                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, "(ssssssouso)", &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, *sjob_type, *following;
-                        DBusMessageIter sub2;
-                        uint32_t job_id;
-                        Unit *f;
-
-                        if (k != u->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->load_state);
-                        active_state = unit_active_state_to_string(unit_active_state(u));
-                        sub_state = unit_sub_state_to_string(u);
-
-                        f = unit_following(u);
-                        following = f ? f->id : "";
-
-                        if (!(u_path = unit_dbus_path(u)))
-                                goto oom;
-
-                        if (u->job) {
-                                job_id = (uint32_t) u->job->id;
-
-                                if (!(j_path = job_dbus_path(u->job))) {
-                                        free(u_path);
-                                        goto oom;
-                                }
-
-                                sjob_type = job_type_to_string(u->job->type);
-                        } else {
-                                job_id = 0;
-                                j_path = u_path;
-                                sjob_type = "";
-                        }
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->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_STRING, &following) ||
-                            !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, &sjob_type) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
-                                free(u_path);
-                                if (u->job)
-                                        free(j_path);
-                                goto oom;
-                        }
-
-                        free(u_path);
-                        if (u->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->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;
-                Set *s;
-
-                if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
-                        if (!(s = set_new(string_hash_func, string_compare_func)))
-                                goto oom;
-
-                        if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
-                                set_free(s);
-                                goto oom;
-                        }
-                }
-
-                if (!(client = strdup(message_get_sender_with_fallback(message))))
-                        goto oom;
-
-                if ((r = set_put(s, client)) < 0) {
-                        free(client);
-                        return bus_send_error_reply(connection, 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(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
-                        return bus_send_error_reply(connection, message, &error, -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(connection, message, &error, -EINVAL);
-
-                if (name && name[0] == 0)
-                        name = NULL;
-
-                if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
-                        return bus_send_error_reply(connection, message, &error, 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->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->queued_message_connection = connection;
-                m->exit_code = MANAGER_RELOAD;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
-
-                /* We don't send a reply back here, the client should
-                 * just wait for us disconnecting. */
-
-                m->exit_code = MANAGER_REEXECUTE;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
-
-                if (m->running_as == MANAGER_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
-                        return bus_send_error_reply(connection, message, &error, -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", "Reboot")) {
-
-                if (m->running_as != MANAGER_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_REBOOT;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
-
-                if (m->running_as != MANAGER_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_POWEROFF;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
-
-                if (m->running_as != MANAGER_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_HALT;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
-
-                if (m->running_as != MANAGER_SYSTEM) {
-                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
-                        return bus_send_error_reply(connection, message, &error, -ENOTSUP);
-                }
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                m->exit_code = MANAGER_KEXEC;
-
-        } 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(connection, message, NULL, r);
-                }
-
-                e = strv_env_merge(2, m->environment, l);
-                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(connection, message, NULL, r);
-                }
-
-                e = strv_env_delete(m->environment, 1, l);
-                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", "UnsetAndSetEnvironment")) {
-                char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
-                DBusMessageIter iter;
-
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
-
-                r = bus_parse_strv_iter(&iter, &l_unset);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                if (!dbus_message_iter_next(&iter)) {
-                        strv_free(l_unset);
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-                }
-
-                r = bus_parse_strv_iter(&iter, &l_set);
-                if (r < 0) {
-                        strv_free(l_unset);
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                e = strv_env_delete(m->environment, 1, l_unset);
-                strv_free(l_unset);
-
-                if (!e) {
-                        strv_free(l_set);
-                        goto oom;
-                }
-
-                f = strv_env_merge(2, e, l_set);
-                strv_free(l_set);
-                strv_free(e);
-
-                if (!f)
-                        goto oom;
-
-                if (!(reply = dbus_message_new_method_return(message))) {
-                        strv_free(f);
-                        goto oom;
-                }
-
-                strv_free(m->environment);
-                m->environment = f;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
-                DBusMessageIter iter, sub, sub2;
-                Hashmap *h;
-                Iterator i;
-                UnitFileList *item;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                h = hashmap_new(string_hash_func, string_compare_func);
-                if (!h)
-                        goto oom;
-
-                r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
-                if (r < 0) {
-                        unit_file_list_free(h);
-                        dbus_message_unref(reply);
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
-                        unit_file_list_free(h);
-                        goto oom;
-                }
-
-                HASHMAP_FOREACH(item, h, i) {
-                        const char *state;
-
-                        state = unit_file_state_to_string(item->state);
-                        assert(state);
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
-                            !dbus_message_iter_close_container(&sub, &sub2)) {
-                                unit_file_list_free(h);
-                                goto oom;
-                        }
-                }
-
-                unit_file_list_free(h);
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
-                const char *name;
-                UnitFileState state;
-                const char *s;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
-                if (state < 0)
-                        return bus_send_error_reply(connection, message, NULL, state);
-
-                s = unit_file_state_to_string(state);
-                assert(s);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                if (!dbus_message_append_args(
-                                    reply,
-                                    DBUS_TYPE_STRING, &s,
-                                    DBUS_TYPE_INVALID))
-                        goto oom;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
-
-                char **l = NULL;
-                DBusMessageIter iter;
-                UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-                UnitFileChange *changes = NULL;
-                unsigned n_changes = 0;
-                dbus_bool_t runtime, force;
-                int carries_install_info = -1;
-
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
-
-                r = bus_parse_strv_iter(&iter, &l);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                if (!dbus_message_iter_next(&iter) ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
-                        strv_free(l);
-                        return bus_send_error_reply(connection, message, NULL, -EIO);
-                }
-
-                if (streq(member, "EnableUnitFiles")) {
-                        r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(member, "ReenableUnitFiles")) {
-                        r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(member, "LinkUnitFiles"))
-                        r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
-                else if (streq(member, "PresetUnitFiles")) {
-                        r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
-                        carries_install_info = r;
-                } else if (streq(member, "MaskUnitFiles"))
-                        r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
-                else
-                        assert_not_reached("Uh? Wrong method");
-
-                strv_free(l);
-                bus_manager_send_unit_files_changed(m);
-
-                if (r < 0) {
-                        unit_file_changes_free(changes, n_changes);
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
-                unit_file_changes_free(changes, n_changes);
-
-                if (!reply)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
-
-                char **l = NULL;
-                DBusMessageIter iter;
-                UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-                UnitFileChange *changes = NULL;
-                unsigned n_changes = 0;
-                dbus_bool_t runtime;
-
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
-
-                r = bus_parse_strv_iter(&iter, &l);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                if (!dbus_message_iter_next(&iter) ||
-                    bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
-                        strv_free(l);
-                        return bus_send_error_reply(connection, message, NULL, -EIO);
-                }
-
-                if (streq(member, "DisableUnitFiles"))
-                        r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
-                else if (streq(member, "UnmaskUnitFiles"))
-                        r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
-                else
-                        assert_not_reached("Uh? Wrong method");
-
-                strv_free(l);
-                bus_manager_send_unit_files_changed(m);
-
-                if (r < 0) {
-                        unit_file_changes_free(changes, n_changes);
-                        return bus_send_error_reply(connection, message, NULL, r);
-                }
-
-                reply = message_from_file_changes(message, changes, n_changes, -1);
-                unit_file_changes_free(changes, n_changes);
-
-                if (!reply)
-                        goto oom;
-
-        } else {
-                const BusBoundProperties bps[] = {
-                        { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
-                        { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
-                        { NULL, }
-                };
-                return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
-        }
-
-        if (job_type != _JOB_TYPE_INVALID) {
-                const char *name, *smode, *old_name = NULL;
-                JobMode mode;
-                Job *j;
-                Unit *u;
-                bool b;
-
-                if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
-                        b = dbus_message_get_args(
-                                        message,
-                                        &error,
-                                        DBUS_TYPE_STRING, &old_name,
-                                        DBUS_TYPE_STRING, &name,
-                                        DBUS_TYPE_STRING, &smode,
-                                        DBUS_TYPE_INVALID);
-                else
-                        b = dbus_message_get_args(
-                                        message,
-                                        &error,
-                                        DBUS_TYPE_STRING, &name,
-                                        DBUS_TYPE_STRING, &smode,
-                                        DBUS_TYPE_INVALID);
-
-                if (!b)
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (old_name)
-                        if (!(u = manager_get_unit(m, old_name)) ||
-                            !u->job ||
-                            u->job->type != JOB_START) {
-                                dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
-                                return bus_send_error_reply(connection, message, &error, -ENOENT);
-                        }
-
-
-                if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
-                        dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
-
-                if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                if (reload_if_possible && unit_can_reload(u)) {
-                        if (job_type == JOB_RESTART)
-                                job_type = JOB_RELOAD_OR_START;
-                        else if (job_type == JOB_TRY_RESTART)
-                                job_type = JOB_RELOAD;
-                }
-
-                if ((job_type == JOB_START && u->refuse_manual_start) ||
-                    (job_type == JOB_STOP && u->refuse_manual_stop) ||
-                    ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
-                     (u->refuse_manual_start || u->refuse_manual_stop))) {
-                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
-                        return bus_send_error_reply(connection, message, &error, -EPERM);
-                }
-
-                if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                if (!(j->bus_client = strdup(message_get_sender_with_fallback(message))))
-                        goto oom;
-
-                j->bus = connection;
-
-                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(connection, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        free(path);
-
-        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
deleted file mode 100644
index 2eb2fbb..0000000
--- a/src/dbus-manager.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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;
-
-extern const char bus_manager_interface[];
-
-#endif
diff --git a/src/dbus-mount.c b/src/dbus-mount.c
deleted file mode 100644
index 35d6ea7..0000000
--- a/src/dbus-mount.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "dbus-common.h"
-
-#define BUS_MOUNT_INTERFACE                                             \
-        " <interface name=\"org.freedesktop.systemd1.Mount\">\n"        \
-        "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"     \
-        "  <property name=\"What\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Options\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
-        BUS_EXEC_COMMAND_INTERFACE("ExecMount")                         \
-        BUS_EXEC_COMMAND_INTERFACE("ExecUnmount")                       \
-        BUS_EXEC_COMMAND_INTERFACE("ExecRemount")                       \
-        BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_MOUNT_INTERFACE                                             \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Mount\0"
-
-const char bus_mount_interface[] _introspect_("Mount") = BUS_MOUNT_INTERFACE;
-
-const char bus_mount_invalidating_properties[] =
-        "What\0"
-        "Options\0"
-        "Type\0"
-        "ExecMount\0"
-        "ExecUnmount\0"
-        "ExecRemount\0"
-        "ControlPID\0"
-        "Result\0";
-
-static int bus_mount_append_what(DBusMessageIter *i, const char *property, void *data) {
-        Mount *m = data;
-        const char *d;
-
-        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(DBusMessageIter *i, const char *property, void *data) {
-        Mount *m = data;
-        const char *d;
-
-        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(DBusMessageIter *i, const char *property, void *data) {
-        Mount *m = data;
-        const char *d;
-
-        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;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_mount_append_mount_result, mount_result, MountResult);
-
-static const BusProperty bus_mount_properties[] = {
-        { "Where",         bus_property_append_string, "s", offsetof(Mount, where),    true },
-        { "What",          bus_mount_append_what,      "s", 0 },
-        { "Options",       bus_mount_append_options,   "s", 0 },
-        { "Type",          bus_mount_append_type,      "s", 0 },
-        { "TimeoutUSec",   bus_property_append_usec,   "t", offsetof(Mount, timeout_usec)   },
-        BUS_EXEC_COMMAND_PROPERTY("ExecMount",   offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]),   false),
-        BUS_EXEC_COMMAND_PROPERTY("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), false),
-        BUS_EXEC_COMMAND_PROPERTY("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), false),
-        { "ControlPID",    bus_property_append_pid,    "u", offsetof(Mount, control_pid)    },
-        { "DirectoryMode", bus_property_append_mode,   "u", offsetof(Mount, directory_mode) },
-        { "Result",        bus_mount_append_mount_result, "s", offsetof(Mount, result)      },
-        { NULL, }
-};
-
-DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Mount *m = MOUNT(u);
-
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,         u },
-                { "org.freedesktop.systemd1.Mount", bus_mount_properties,        m },
-                { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps );
-}
diff --git a/src/dbus-mount.h b/src/dbus-mount.h
deleted file mode 100644
index b5613fa..0000000
--- a/src/dbus-mount.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_mount_interface[];
-extern const char bus_mount_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-path.c b/src/dbus-path.c
deleted file mode 100644
index 5506784..0000000
--- a/src/dbus-path.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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-path.h"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-
-#define BUS_PATH_INTERFACE                                              \
-        " <interface name=\"org.freedesktop.systemd1.Path\">\n"         \
-        "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Paths\" type=\"a(ss)\" access=\"read\"/>\n" \
-        "  <property name=\"MakeDirectory\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_PATH_INTERFACE                                              \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Path\0"
-
-const char bus_path_interface[] _introspect_("Path") = BUS_PATH_INTERFACE;
-
-const char bus_path_invalidating_properties[] =
-        "Result\0";
-
-static int bus_path_append_paths(DBusMessageIter *i, const char *property, void *data) {
-        Path *p = data;
-        DBusMessageIter sub, sub2;
-        PathSpec *k;
-
-        assert(i);
-        assert(property);
-        assert(p);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
-                return -ENOMEM;
-
-        LIST_FOREACH(spec, k, p->specs) {
-                const char *t = path_type_to_string(k->type);
-
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &k->path) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        Path *p = PATH(u);
-        const char *t;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        t = UNIT_DEREF(p->unit) ? UNIT_DEREF(p->unit)->id : "";
-
-        return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_path_append_path_result, path_result, PathResult);
-
-static const BusProperty bus_path_properties[] = {
-        { "Unit",          bus_path_append_unit,      "s", 0 },
-        { "Paths",         bus_path_append_paths, "a(ss)", 0 },
-        { "MakeDirectory", bus_property_append_bool,  "b", offsetof(Path, make_directory) },
-        { "DirectoryMode", bus_property_append_mode,  "u", offsetof(Path, directory_mode) },
-        { "Result",        bus_path_append_path_result, "s", offsetof(Path, result) },
-        { NULL, }
-};
-
-DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Path *p = PATH(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
-                { "org.freedesktop.systemd1.Path", bus_path_properties, p },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-path.h b/src/dbus-path.h
deleted file mode 100644
index 2888400..0000000
--- a/src/dbus-path.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foodbuspathhfoo
-#define foodbuspathhfoo
-
-/***
-  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_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_path_interface[];
-
-extern const char bus_path_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-service.c b/src/dbus-service.c
deleted file mode 100644
index d840415..0000000
--- a/src/dbus-service.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "dbus-common.h"
-
-#ifdef HAVE_SYSV_COMPAT
-#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT                            \
-        "  <property name=\"SysVStartPriority\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"SysVRunLevels\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SysVPath\" type=\"s\" access=\"read\"/>\n"
-#else
-#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT ""
-#endif
-
-#define BUS_SERVICE_INTERFACE                                           \
-        " <interface name=\"org.freedesktop.systemd1.Service\">\n"      \
-        "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Restart\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStart")                         \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
-        BUS_EXEC_COMMAND_INTERFACE("ExecReload")                        \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStop")                          \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
-        BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
-        BUS_EXEC_STATUS_INTERFACE("ExecMain")                           \
-        "  <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n"   \
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"BusName\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"FsckPassNo\" type=\"i\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        BUS_SERVICE_SYSV_INTERFACE_FRAGMENT                             \
-       " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_SERVICE_INTERFACE                                           \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Service\0"
-
-const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
-
-const char bus_service_invalidating_properties[] =
-        "ExecStartPre\0"
-        "ExecStart\0"
-        "ExecStartPost\0"
-        "ExecReload\0"
-        "ExecStop\0"
-        "ExecStopPost\0"
-        "ExecMain\0"
-        "WatchdogTimestamp\0"
-        "WatchdogTimestampMonotonic\0"
-        "MainPID\0"
-        "ControlPID\0"
-        "StatusText\0"
-        "Result\0";
-
-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);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
-static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction);
-
-static const BusProperty bus_exec_main_status_properties[] = {
-        { "ExecMainStartTimestamp",         bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
-        { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
-        { "ExecMainExitTimestamp",          bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
-        { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
-        { "ExecMainPID",                    bus_property_append_pid,  "u", offsetof(ExecStatus, pid)                       },
-        { "ExecMainCode",                   bus_property_append_int,  "i", offsetof(ExecStatus, code)                      },
-        { "ExecMainStatus",                 bus_property_append_int,  "i", offsetof(ExecStatus, status)                    },
-        { NULL, }
-};
-
-static const BusProperty bus_service_properties[] = {
-        { "Type",                   bus_service_append_type,          "s", offsetof(Service, type)                         },
-        { "Restart",                bus_service_append_restart,       "s", offsetof(Service, restart)                      },
-        { "PIDFile",                bus_property_append_string,       "s", offsetof(Service, pid_file),               true },
-        { "NotifyAccess",           bus_service_append_notify_access, "s", offsetof(Service, notify_access)                },
-        { "RestartUSec",            bus_property_append_usec,         "t", offsetof(Service, restart_usec)                 },
-        { "TimeoutUSec",            bus_property_append_usec,         "t", offsetof(Service, timeout_usec)                 },
-        { "WatchdogUSec",           bus_property_append_usec,         "t", offsetof(Service, watchdog_usec)                },
-        { "WatchdogTimestamp",      bus_property_append_usec,         "t", offsetof(Service, watchdog_timestamp.realtime)  },
-        { "WatchdogTimestampMonotonic",bus_property_append_usec,      "t", offsetof(Service, watchdog_timestamp.monotonic) },
-        { "StartLimitInterval",     bus_property_append_usec,         "t", offsetof(Service, start_limit.interval)         },
-        { "StartLimitBurst",        bus_property_append_uint32,       "u", offsetof(Service, start_limit.burst)            },
-        { "StartLimitAction",       bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action), false, bus_service_set_start_limit_action},
-        BUS_EXEC_COMMAND_PROPERTY("ExecStartPre",  offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]),  true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStart",     offsetof(Service, exec_command[SERVICE_EXEC_START]),      true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecReload",    offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]),     true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStop",      offsetof(Service, exec_command[SERVICE_EXEC_STOP]),       true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStopPost",  offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]),  true ),
-        { "PermissionsStartOnly",   bus_property_append_bool,         "b", offsetof(Service, permissions_start_only)       },
-        { "RootDirectoryStartOnly", bus_property_append_bool,         "b", offsetof(Service, root_directory_start_only)    },
-        { "RemainAfterExit",        bus_property_append_bool,         "b", offsetof(Service, remain_after_exit)            },
-        { "GuessMainPID",           bus_property_append_bool,         "b", offsetof(Service, guess_main_pid)               },
-        { "MainPID",                bus_property_append_pid,          "u", offsetof(Service, main_pid)                     },
-        { "ControlPID",             bus_property_append_pid,          "u", offsetof(Service, control_pid)                  },
-        { "BusName",                bus_property_append_string,       "s", offsetof(Service, bus_name),               true },
-        { "StatusText",             bus_property_append_string,       "s", offsetof(Service, status_text),            true },
-#ifdef HAVE_SYSV_COMPAT
-        { "SysVRunLevels",          bus_property_append_string,       "s", offsetof(Service, sysv_runlevels),         true },
-        { "SysVStartPriority",      bus_property_append_int,          "i", offsetof(Service, sysv_start_priority)          },
-        { "SysVPath",               bus_property_append_string,       "s", offsetof(Service, sysv_path),              true },
-#endif
-        { "FsckPassNo",             bus_property_append_int,          "i", offsetof(Service, fsck_passno)                  },
-        { "Result",                 bus_service_append_service_result,"s", offsetof(Service, result)                       },
-        { NULL, }
-};
-
-DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
-        Service *s = SERVICE(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",    bus_unit_properties,             u },
-                { "org.freedesktop.systemd1.Service", bus_service_properties,          s },
-                { "org.freedesktop.systemd1.Service", bus_exec_context_properties,     &s->exec_context },
-                { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-service.h b/src/dbus-service.h
deleted file mode 100644
index d6eab65..0000000
--- a/src/dbus-service.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_service_interface[];
-extern const char bus_service_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-snapshot.c b/src/dbus-snapshot.c
deleted file mode 100644
index e69388a..0000000
--- a/src/dbus-snapshot.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "dbus-common.h"
-
-#define BUS_SNAPSHOT_INTERFACE                                          \
-        " <interface name=\"org.freedesktop.systemd1.Snapshot\">\n"     \
-        "  <method name=\"Remove\"/>\n"                                 \
-        "  <property name=\"Cleanup\" type=\"b\" access=\"read\"/>\n"   \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_SNAPSHOT_INTERFACE                                          \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Snapshot\0"
-
-const char bus_snapshot_interface[] _introspect_("Snapshot") = BUS_SNAPSHOT_INTERFACE;
-
-static const BusProperty bus_snapshot_properties[] = {
-        { "Cleanup", bus_property_append_bool, "b", offsetof(Snapshot, cleanup) },
-        { NULL, }
-};
-
-DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Snapshot *s = SNAPSHOT(u);
-
-        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 {
-                const BusBoundProperties bps[] = {
-                        { "org.freedesktop.systemd1.Unit",     bus_unit_properties,     u },
-                        { "org.freedesktop.systemd1.Snapshot", bus_snapshot_properties, s },
-                        { NULL, }
-                };
-                return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-        }
-
-        if (reply) {
-                if (!dbus_connection_send(c, 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
deleted file mode 100644
index 0b82279..0000000
--- a/src/dbus-snapshot.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_snapshot_interface[];
-
-#endif
diff --git a/src/dbus-socket.c b/src/dbus-socket.c
deleted file mode 100644
index 2e3342c..0000000
--- a/src/dbus-socket.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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-socket.h"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-
-#define BUS_SOCKET_INTERFACE                                            \
-        " <interface name=\"org.freedesktop.systemd1.Socket\">\n"       \
-        "  <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Backlog\" type=\"u\" access=\"read\"/>\n"   \
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStopPre")                       \
-        BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
-        BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"SocketMode\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Accept\" type=\"b\" access=\"read\"/>\n"    \
-        "  <property name=\"KeepAlive\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Priority\" type=\"i\" access=\"read\"/>\n"  \
-        "  <property name=\"ReceiveBuffer\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"SendBuffer\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"IPTOS\" type=\"i\" access=\"read\"/>\n"     \
-        "  <property name=\"IPTTL\" type=\"i\" access=\"read\"/>\n"     \
-        "  <property name=\"PipeSize\" type=\"t\" access=\"read\"/>\n"  \
-        "  <property name=\"FreeBind\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"Transparent\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Broadcast\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"PassCredentials\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"PassSecurity\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Mark\" type=\"i\" access=\"read\"/>\n"      \
-        "  <property name=\"MaxConnections\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"NAccepted\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"NConnections\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"MessageQueueMaxMessages\" type=\"x\" access=\"read\"/>\n" \
-        "  <property name=\"MessageQueueMessageSize\" type=\"x\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"                                               \
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_SOCKET_INTERFACE                                            \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Socket\0"
-
-const char bus_socket_interface[] _introspect_("Socket") = BUS_SOCKET_INTERFACE;
-
-const char bus_socket_invalidating_properties[] =
-        "ExecStartPre\0"
-        "ExecStartPost\0"
-        "ExecStopPre\0"
-        "ExecStopPost\0"
-        "ControlPID\0"
-        "NAccepted\0"
-        "NConnections\0"
-        "Result\0";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_socket_result, socket_result, SocketResult);
-
-static const BusProperty bus_socket_properties[] = {
-        { "BindIPv6Only",   bus_socket_append_bind_ipv6_only,  "s", offsetof(Socket, bind_ipv6_only)  },
-        { "Backlog",        bus_property_append_unsigned,      "u", offsetof(Socket, backlog)         },
-        { "TimeoutUSec",    bus_property_append_usec,          "t", offsetof(Socket, timeout_usec)    },
-        BUS_EXEC_COMMAND_PROPERTY("ExecStartPre",  offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]),  true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStopPre",   offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]),   true ),
-        BUS_EXEC_COMMAND_PROPERTY("ExecStopPost",  offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]),  true ),
-        { "ControlPID",     bus_property_append_pid,           "u", offsetof(Socket, control_pid)     },
-        { "BindToDevice",   bus_property_append_string,        "s", offsetof(Socket, bind_to_device), true },
-        { "DirectoryMode",  bus_property_append_mode,          "u", offsetof(Socket, directory_mode)  },
-        { "SocketMode",     bus_property_append_mode,          "u", offsetof(Socket, socket_mode)     },
-        { "Accept",         bus_property_append_bool,          "b", offsetof(Socket, accept)          },
-        { "KeepAlive",      bus_property_append_bool,          "b", offsetof(Socket, keep_alive)      },
-        { "Priority",       bus_property_append_int,           "i", offsetof(Socket, priority)        },
-        { "ReceiveBuffer",  bus_property_append_size,          "t", offsetof(Socket, receive_buffer)  },
-        { "SendBuffer",     bus_property_append_size,          "t", offsetof(Socket, send_buffer)     },
-        { "IPTOS",          bus_property_append_int,           "i", offsetof(Socket, ip_tos)          },
-        { "IPTTL",          bus_property_append_int,           "i", offsetof(Socket, ip_ttl)          },
-        { "PipeSize",       bus_property_append_size,          "t", offsetof(Socket, pipe_size)       },
-        { "FreeBind",       bus_property_append_bool,          "b", offsetof(Socket, free_bind)       },
-        { "Transparent",    bus_property_append_bool,          "b", offsetof(Socket, transparent)     },
-        { "Broadcast",      bus_property_append_bool,          "b", offsetof(Socket, broadcast)       },
-        { "PassCredentials",bus_property_append_bool,          "b", offsetof(Socket, pass_cred)       },
-        { "PassSecurity",   bus_property_append_bool,          "b", offsetof(Socket, pass_sec)        },
-        { "Mark",           bus_property_append_int,           "i", offsetof(Socket, mark)            },
-        { "MaxConnections", bus_property_append_unsigned,      "u", offsetof(Socket, max_connections) },
-        { "NConnections",   bus_property_append_unsigned,      "u", offsetof(Socket, n_connections)   },
-        { "NAccepted",      bus_property_append_unsigned,      "u", offsetof(Socket, n_accepted)      },
-        { "MessageQueueMaxMessages", bus_property_append_long, "x", offsetof(Socket, mq_maxmsg)       },
-        { "MessageQueueMessageSize", bus_property_append_long, "x", offsetof(Socket, mq_msgsize)      },
-        { "Result",         bus_socket_append_socket_result,   "s", offsetof(Socket, result)          },
-        { NULL, }
-};
-
-DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Socket *s = SOCKET(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",   bus_unit_properties,         u },
-                { "org.freedesktop.systemd1.Socket", bus_socket_properties,       s },
-                { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-socket.h b/src/dbus-socket.h
deleted file mode 100644
index 069a2f5..0000000
--- a/src/dbus-socket.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_socket_interface[];
-extern const char bus_socket_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-swap.c b/src/dbus-swap.c
deleted file mode 100644
index 09cd1e8..0000000
--- a/src/dbus-swap.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-
-#define BUS_SWAP_INTERFACE                                              \
-        " <interface name=\"org.freedesktop.systemd1.Swap\">\n"         \
-        "  <property name=\"What\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Priority\" type=\"i\" access=\"read\"/>\n"  \
-        "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
-        BUS_EXEC_COMMAND_INTERFACE("ExecActivate")                      \
-        BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate")                    \
-        BUS_EXEC_CONTEXT_INTERFACE                                      \
-        "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_SWAP_INTERFACE                                              \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Swap\0"
-
-const char bus_swap_interface[] _introspect_("Swap") = BUS_SWAP_INTERFACE;
-
-const char bus_swap_invalidating_properties[] =
-        "What\0"
-        "Priority\0"
-        "ExecActivate\0"
-        "ExecDeactivate\0"
-        "ControlPID\0"
-        "Result\0";
-
-static int bus_swap_append_priority(DBusMessageIter *i, const char *property, void *data) {
-        Swap *s = data;
-        dbus_int32_t j;
-
-        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;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_swap_append_swap_result, swap_result, SwapResult);
-
-static const BusProperty bus_swap_properties[] = {
-        { "What",       bus_property_append_string, "s", offsetof(Swap, what),  true },
-        { "Priority",   bus_swap_append_priority,   "i", 0 },
-        BUS_EXEC_COMMAND_PROPERTY("ExecActivate",   offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]),   false),
-        BUS_EXEC_COMMAND_PROPERTY("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), false),
-        { "ControlPID", bus_property_append_pid,    "u", offsetof(Swap, control_pid) },
-        { "Result",     bus_swap_append_swap_result,"s", offsetof(Swap, result)      },
-        { NULL, }
-};
-
-DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Swap *s = SWAP(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit", bus_unit_properties,         u },
-                { "org.freedesktop.systemd1.Swap", bus_swap_properties,         s },
-                { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-swap.h b/src/dbus-swap.h
deleted file mode 100644
index 15b9147..0000000
--- a/src/dbus-swap.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_swap_interface[];
-extern const char bus_swap_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-target.c b/src/dbus-target.c
deleted file mode 100644
index 55cf862..0000000
--- a/src/dbus-target.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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-target.h"
-#include "dbus-common.h"
-
-#define BUS_TARGET_INTERFACE                                            \
-        " <interface name=\"org.freedesktop.systemd1.Target\">\n"       \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_TARGET_INTERFACE                                            \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Target\0"
-
-const char bus_target_interface[] _introspect_("Target") = BUS_TARGET_INTERFACE;
-
-DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-target.h b/src/dbus-target.h
deleted file mode 100644
index 13d3876..0000000
--- a/src/dbus-target.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_target_interface[];
-
-#endif
diff --git a/src/dbus-timer.c b/src/dbus-timer.c
deleted file mode 100644
index b396aed..0000000
--- a/src/dbus-timer.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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-timer.h"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-
-#define BUS_TIMER_INTERFACE                                             \
-        " <interface name=\"org.freedesktop.systemd1.Timer\">\n"        \
-        "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Timers\" type=\"a(stt)\" access=\"read\"/>\n" \
-        "  <property name=\"NextElapseUSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        BUS_UNIT_INTERFACE                                              \
-        BUS_TIMER_INTERFACE                                             \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_PEER_INTERFACE                                              \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        "</node>\n"
-
-#define INTERFACES_LIST                              \
-        BUS_UNIT_INTERFACES_LIST                     \
-        "org.freedesktop.systemd1.Timer\0"
-
-const char bus_timer_interface[] _introspect_("Timer") = BUS_TIMER_INTERFACE;
-
-const char bus_timer_invalidating_properties[] =
-        "Timers\0"
-        "NextElapseUSec\0"
-        "Result\0";
-
-static int bus_timer_append_timers(DBusMessageIter *i, const char *property, void *data) {
-        Timer *p = data;
-        DBusMessageIter sub, sub2;
-        TimerValue *k;
-
-        assert(i);
-        assert(property);
-        assert(p);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(stt)", &sub))
-                return -ENOMEM;
-
-        LIST_FOREACH(value, k, p->values) {
-                char *buf;
-                const char *t;
-                size_t l;
-                bool b;
-
-                t = timer_base_to_string(k->base);
-                assert(endswith(t, "Sec"));
-
-                /* s/Sec/USec/ */
-                l = strlen(t);
-                if (!(buf = new(char, l+2)))
-                        return -ENOMEM;
-
-                memcpy(buf, t, l-3);
-                memcpy(buf+l-3, "USec", 5);
-
-                b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) &&
-                        dbus_message_iter_close_container(&sub, &sub2);
-
-                free(buf);
-                if (!b)
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_timer_append_unit(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        Timer *timer = TIMER(u);
-        const char *t;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        t = UNIT_DEREF(timer->unit) ? UNIT_DEREF(timer->unit)->id : "";
-
-        return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_timer_append_timer_result, timer_result, TimerResult);
-
-static const BusProperty bus_timer_properties[] = {
-        { "Unit",           bus_timer_append_unit,        "s", 0 },
-        { "Timers",         bus_timer_append_timers, "a(stt)", 0 },
-        { "NextElapseUSec", bus_property_append_usec,     "t", offsetof(Timer, next_elapse) },
-        { "Result",         bus_timer_append_timer_result,"s", offsetof(Timer, result)      },
-        { NULL, }
-};
-
-DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
-        Timer *t = TIMER(u);
-        const BusBoundProperties bps[] = {
-                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,  u },
-                { "org.freedesktop.systemd1.Timer", bus_timer_properties, t },
-                { NULL, }
-        };
-
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/dbus-timer.h b/src/dbus-timer.h
deleted file mode 100644
index e692e12..0000000
--- a/src/dbus-timer.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foodbustimerhfoo
-#define foodbustimerhfoo
-
-/***
-  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_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_timer_interface[];
-extern const char bus_timer_invalidating_properties[];
-
-#endif
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
deleted file mode 100644
index c7532c7..0000000
--- a/src/dbus-unit.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "bus-errors.h"
-#include "dbus-common.h"
-
-const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE;
-
-#define INVALIDATING_PROPERTIES                 \
-        "LoadState\0"                           \
-        "ActiveState\0"                         \
-        "SubState\0"                            \
-        "InactiveExitTimestamp\0"               \
-        "ActiveEnterTimestamp\0"                \
-        "ActiveExitTimestamp\0"                 \
-        "InactiveEnterTimestamp\0"              \
-        "Job\0"                                 \
-        "NeedDaemonReload\0"
-
-static int bus_unit_append_names(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->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;
-}
-
-static int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data, *f;
-        const char *d;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        f = unit_following(u);
-        d = f ? f->id : "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_dependencies(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->id))
-                        return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *d;
-
-        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;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState);
-
-static int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *state;
-
-        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;
-}
-
-static int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *state;
-
-        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;
-}
-
-static int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *state;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        state = strempty(unit_file_state_to_string(unit_get_unit_file_state(u)));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        b = unit_can_start(u) &&
-                !u->refuse_manual_start;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        /* On the lower levels we assume that every unit we can start
-         * we can also stop */
-
-        b = unit_can_start(u) &&
-                !u->refuse_manual_stop;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        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;
-}
-
-static int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        b = unit_can_isolate(u) &&
-                !u->refuse_manual_start;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        DBusMessageIter sub;
-        char *p;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
-                return -ENOMEM;
-
-        if (u->job) {
-
-                if (!(p = job_dbus_path(u->job)))
-                        return -ENOMEM;
-
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->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;
-}
-
-static int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        char *t;
-        CGroupBonding *cgb;
-        bool success;
-
-        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;
-}
-
-static int bus_unit_append_cgroups(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->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;
-}
-
-static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        CGroupAttribute *a;
-        DBusMessageIter sub, sub2;
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub))
-                return -ENOMEM;
-
-        LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
-                char *v = NULL;
-                bool success;
-
-                if (a->map_callback)
-                        a->map_callback(a->controller, a->name, a->value, &v);
-
-                success =
-                        dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) &&
-                        dbus_message_iter_close_container(&sub, &sub2);
-
-                free(v);
-
-                if (!success)
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        b = unit_need_daemon_reload(u);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *name, *message;
-        DBusMessageIter sub;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        if (u->load_error != 0) {
-                name = bus_errno_to_dbus(u->load_error);
-                message = strempty(strerror(-u->load_error));
-        } else
-                name = message = "";
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub) ||
-            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name) ||
-            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &message) ||
-            !dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) {
-        DBusMessage *reply = NULL;
-        Manager *m = u->manager;
-        DBusError error;
-        JobType job_type = _JOB_TYPE_INVALID;
-        char *path = NULL;
-        bool reload_if_possible = false;
-
-        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 (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "TryRestart"))
-                job_type = JOB_TRY_RESTART;
-        else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) {
-                reload_if_possible = true;
-                job_type = JOB_RESTART;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
-                reload_if_possible = true;
-                job_type = JOB_TRY_RESTART;
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) {
-                const char *swho, *smode;
-                int32_t signo;
-                KillMode mode;
-                KillWho who;
-                int r;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &swho,
-                                    DBUS_TYPE_STRING, &smode,
-                                    DBUS_TYPE_INT32, &signo,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (isempty(swho))
-                        who = KILL_ALL;
-                else {
-                        who = kill_who_from_string(swho);
-                        if (who < 0)
-                                return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
-
-                if (isempty(smode))
-                        mode = KILL_CONTROL_GROUP;
-                else {
-                        mode = kill_mode_from_string(smode);
-                        if (mode < 0)
-                                return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
-
-                if (signo <= 0 || signo >= _NSIG)
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) {
-
-                unit_reset_failed(u);
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-        } else if (UNIT_VTABLE(u)->bus_message_handler)
-                return UNIT_VTABLE(u)->bus_message_handler(u, connection, message);
-        else
-                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-        if (job_type != _JOB_TYPE_INVALID) {
-                const char *smode;
-                JobMode mode;
-                Job *j;
-                int r;
-
-                if ((job_type == JOB_START && u->refuse_manual_start) ||
-                    (job_type == JOB_STOP && u->refuse_manual_stop) ||
-                    ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
-                     (u->refuse_manual_start || u->refuse_manual_stop))) {
-                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
-                        return bus_send_error_reply(connection, message, &error, -EPERM);
-                }
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &smode,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (reload_if_possible && unit_can_reload(u)) {
-                        if (job_type == JOB_RESTART)
-                                job_type = JOB_RELOAD_OR_START;
-                        else if (job_type == JOB_TRY_RESTART)
-                                job_type = JOB_RELOAD;
-                }
-
-                if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
-                        dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-                }
-
-                if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
-                        return bus_send_error_reply(connection, message, &error, 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(connection, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        free(path);
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        free(path);
-
-        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;
-        DBusMessage *reply;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) {
-                /* Be nice to gdbus and return introspection data for our mid-level paths */
-
-                if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-                        char *introspection = NULL;
-                        FILE *f;
-                        Iterator i;
-                        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(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-                              "<node>\n", f);
-
-                        fputs(BUS_INTROSPECTABLE_INTERFACE, f);
-                        fputs(BUS_PEER_INTERFACE, f);
-
-                        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-                                char *p;
-
-                                if (k != u->id)
-                                        continue;
-
-                                if (!(p = bus_path_escape(k))) {
-                                        fclose(f);
-                                        free(introspection);
-                                        goto oom;
-                                }
-
-                                fprintf(f, "<node name=\"%s\"/>", p);
-                                free(p);
-                        }
-
-                        fputs("</node>\n", 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);
-
-                        if (!dbus_connection_send(connection, reply, NULL))
-                                goto oom;
-
-                        dbus_message_unref(reply);
-
-                        return DBUS_HANDLER_RESULT_HANDLED;
-                }
-
-                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-        }
-
-        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) {
-                        DBusError e;
-
-                        dbus_error_init(&e);
-                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown unit");
-                        return bus_send_error_reply(connection, message, &e, r);
-                }
-
-                return bus_send_error_reply(connection, message, NULL, r);
-        }
-
-        return bus_unit_message_dispatch(u, connection, message);
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-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);
-
-        if (u->in_dbus_queue) {
-                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
-                u->in_dbus_queue = false;
-        }
-
-        if (!u->id)
-                return;
-
-        if (!bus_has_subscriber(u->manager)) {
-                u->sent_dbus_new_signal = true;
-                return;
-        }
-
-        if (!(p = unit_dbus_path(u)))
-                goto oom;
-
-        if (u->sent_dbus_new_signal) {
-                /* Send a properties changed signal. First for the
-                 * specific type, then for the generic unit. The
-                 * clients may rely on this order to get atomic
-                 * behaviour if needed. */
-
-                if (UNIT_VTABLE(u)->bus_invalidating_properties) {
-
-                        if (!(m = bus_properties_changed_new(p,
-                                                             UNIT_VTABLE(u)->bus_interface,
-                                                             UNIT_VTABLE(u)->bus_invalidating_properties)))
-                                goto oom;
-
-                        if (bus_broadcast(u->manager, m) < 0)
-                                goto oom;
-
-                        dbus_message_unref(m);
-                }
-
-                if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", INVALIDATING_PROPERTIES)))
-                        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->id,
-                                              DBUS_TYPE_OBJECT_PATH, &p,
-                                              DBUS_TYPE_INVALID))
-                        goto oom;
-        }
-
-        if (bus_broadcast(u->manager, m) < 0)
-                goto oom;
-
-        free(p);
-        dbus_message_unref(m);
-
-        u->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 (!bus_has_subscriber(u->manager))
-                return;
-
-        if (!u->sent_dbus_new_signal)
-                bus_unit_send_change_signal(u);
-
-        if (!u->id)
-                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->id,
-                                      DBUS_TYPE_OBJECT_PATH, &p,
-                                      DBUS_TYPE_INVALID))
-                goto oom;
-
-        if (bus_broadcast(u->manager, m) < 0)
-                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.");
-}
-
-const BusProperty bus_unit_properties[] = {
-        { "Id",                   bus_property_append_string,         "s", offsetof(Unit, id),                                         true },
-        { "Names",                bus_unit_append_names,             "as", 0 },
-        { "Following",            bus_unit_append_following,          "s", 0 },
-        { "Requires",             bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRES]),                true },
-        { "RequiresOverridable",  bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]),    true },
-        { "Requisite",            bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUISITE]),               true },
-        { "RequisiteOverridable", bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]),   true },
-        { "Wants",                bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_WANTS]),                   true },
-        { "BindTo",               bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_BIND_TO]),                 true },
-        { "RequiredBy",           bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY]),             true },
-        { "RequiredByOverridable",bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), true },
-        { "WantedBy",             bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_WANTED_BY]),               true },
-        { "BoundBy",              bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_BOUND_BY]),                true },
-        { "Conflicts",            bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_CONFLICTS]),               true },
-        { "ConflictedBy",         bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]),           true },
-        { "Before",               bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_BEFORE]),                  true },
-        { "After",                bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_AFTER]),                   true },
-        { "OnFailure",            bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_ON_FAILURE]),              true },
-        { "Triggers",             bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_TRIGGERS]),                true },
-        { "TriggeredBy",          bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]),            true },
-        { "PropagateReloadTo",    bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_TO]),     true },
-        { "PropagateReloadFrom",  bus_unit_append_dependencies,      "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_FROM]),   true },
-        { "Description",          bus_unit_append_description,        "s", 0 },
-        { "LoadState",            bus_unit_append_load_state,         "s", offsetof(Unit, load_state)                         },
-        { "ActiveState",          bus_unit_append_active_state,       "s", 0 },
-        { "SubState",             bus_unit_append_sub_state,          "s", 0 },
-        { "FragmentPath",         bus_property_append_string,         "s", offsetof(Unit, fragment_path),                              true },
-        { "UnitFileState",        bus_unit_append_file_state,         "s", 0 },
-        { "InactiveExitTimestamp",bus_property_append_usec,           "t", offsetof(Unit, inactive_exit_timestamp.realtime)   },
-        { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic)  },
-        { "ActiveEnterTimestamp", bus_property_append_usec,           "t", offsetof(Unit, active_enter_timestamp.realtime)    },
-        { "ActiveEnterTimestampMonotonic", bus_property_append_usec,  "t", offsetof(Unit, active_enter_timestamp.monotonic)   },
-        { "ActiveExitTimestamp",  bus_property_append_usec,           "t", offsetof(Unit, active_exit_timestamp.realtime)     },
-        { "ActiveExitTimestampMonotonic",  bus_property_append_usec,  "t", offsetof(Unit, active_exit_timestamp.monotonic)    },
-        { "InactiveEnterTimestamp", bus_property_append_usec,         "t", offsetof(Unit, inactive_enter_timestamp.realtime)  },
-        { "InactiveEnterTimestampMonotonic",bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.monotonic) },
-        { "CanStart",             bus_unit_append_can_start,          "b", 0 },
-        { "CanStop",              bus_unit_append_can_stop,           "b", 0 },
-        { "CanReload",            bus_unit_append_can_reload,         "b", 0 },
-        { "CanIsolate",           bus_unit_append_can_isolate,        "b", 0 },
-        { "Job",                  bus_unit_append_job,             "(uo)", 0 },
-        { "StopWhenUnneeded",     bus_property_append_bool,           "b", offsetof(Unit, stop_when_unneeded)                 },
-        { "RefuseManualStart",    bus_property_append_bool,           "b", offsetof(Unit, refuse_manual_start)                },
-        { "RefuseManualStop",     bus_property_append_bool,           "b", offsetof(Unit, refuse_manual_stop)                 },
-        { "AllowIsolate",         bus_property_append_bool,           "b", offsetof(Unit, allow_isolate)                      },
-        { "DefaultDependencies",  bus_property_append_bool,           "b", offsetof(Unit, default_dependencies)               },
-        { "OnFailureIsolate",     bus_property_append_bool,           "b", offsetof(Unit, on_failure_isolate)                 },
-        { "IgnoreOnIsolate",      bus_property_append_bool,           "b", offsetof(Unit, ignore_on_isolate)                  },
-        { "IgnoreOnSnapshot",     bus_property_append_bool,           "b", offsetof(Unit, ignore_on_snapshot)                 },
-        { "DefaultControlGroup",  bus_unit_append_default_cgroup,     "s", 0 },
-        { "ControlGroup",         bus_unit_append_cgroups,           "as", 0 },
-        { "ControlGroupAttributes", bus_unit_append_cgroup_attrs,"a(sss)", 0 },
-        { "NeedDaemonReload",     bus_unit_append_need_daemon_reload, "b", 0 },
-        { "JobTimeoutUSec",       bus_property_append_usec,           "t", offsetof(Unit, job_timeout)                        },
-        { "ConditionTimestamp",   bus_property_append_usec,           "t", offsetof(Unit, condition_timestamp.realtime)       },
-        { "ConditionTimestampMonotonic", bus_property_append_usec,    "t", offsetof(Unit, condition_timestamp.monotonic)      },
-        { "ConditionResult",      bus_property_append_bool,           "b", offsetof(Unit, condition_result)                   },
-        { "LoadError",            bus_unit_append_load_error,      "(ss)", 0 },
-        { NULL, }
-};
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
deleted file mode 100644
index 4f19a80..0000000
--- a/src/dbus-unit.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-#include "dbus-common.h"
-
-#define BUS_UNIT_INTERFACE \
-        " <interface name=\"org.freedesktop.systemd1.Unit\">\n"         \
-        "  <method name=\"Start\">\n"                                   \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"Stop\">\n"                                    \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"Reload\">\n"                                  \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"Restart\">\n"                                 \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"TryRestart\">\n"                              \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadOrRestart\">\n"                         \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"ReloadOrTryRestart\">\n"                      \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"Kill\">\n"                                    \
-        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"ResetFailed\"/>\n"                            \
-        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
-        "  <property name=\"Names\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"Following\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"Requires\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"RequiresOverridable\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"Requisite\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"RequisiteOverridable\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"Wants\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"BindTo\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"RequiredBy\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"RequiredByOverridable\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"WantedBy\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"BoundBy\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"Conflicts\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"ConflictedBy\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"Before\" type=\"as\" access=\"read\"/>\n"   \
-        "  <property name=\"After\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"OnFailure\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"Triggers\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"TriggeredBy\" type=\"as\" access=\"read\"/>\n"    \
-        "  <property name=\"PropagateReloadTo\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"PropagateReloadFrom\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"Description\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"LoadState\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ActiveState\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SubState\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"UnitFileState\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"InactiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ActiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ActiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"InactiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n"   \
-        "  <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"CanIsolate\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n"    \
-        "  <property name=\"StopWhenUnneeded\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"AllowIsolate\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"OnFailureIsolate\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"IgnoreOnIsolate\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"IgnoreOnSnapshot\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroup\" type=\"as\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupAttributes\" type=\"a(sss)\" access=\"read\"/>\n" \
-        "  <property name=\"NeedDaemonReload\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"JobTimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ConditionTimestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ConditionTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"LoadError\" type=\"(ss)\" access=\"read\"/>\n" \
-        " </interface>\n"
-
-#define BUS_UNIT_INTERFACES_LIST                \
-        BUS_GENERIC_INTERFACES_LIST             \
-        "org.freedesktop.systemd1.Unit\0"
-
-extern const BusProperty bus_unit_properties[];
-
-void bus_unit_send_change_signal(Unit *u);
-void bus_unit_send_removed_signal(Unit *u);
-
-extern const DBusObjectPathVTable bus_unit_vtable;
-
-extern const char bus_unit_interface[];
-
-#endif
diff --git a/src/dbus.c b/src/dbus.c
deleted file mode 100644
index ddf91f2..0000000
--- a/src/dbus.c
+++ /dev/null
@@ -1,1483 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 "mkdir.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "dbus-service.h"
-#include "dbus-socket.h"
-#include "dbus-target.h"
-#include "dbus-device.h"
-#include "dbus-mount.h"
-#include "dbus-automount.h"
-#include "dbus-snapshot.h"
-#include "dbus-swap.h"
-#include "dbus-timer.h"
-#include "dbus-path.h"
-#include "bus-errors.h"
-#include "special.h"
-#include "dbus-common.h"
-
-#define CONNECTIONS_MAX 52
-
-/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
-#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
-/* Only used as a fallback */
-#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
-
-static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
-static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
-
-const char *const bus_interface_table[] = {
-        "org.freedesktop.DBus.Properties",     bus_properties_interface,
-        "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
-        "org.freedesktop.systemd1.Manager",    bus_manager_interface,
-        "org.freedesktop.systemd1.Job",        bus_job_interface,
-        "org.freedesktop.systemd1.Unit",       bus_unit_interface,
-        "org.freedesktop.systemd1.Service",    bus_service_interface,
-        "org.freedesktop.systemd1.Socket",     bus_socket_interface,
-        "org.freedesktop.systemd1.Target",     bus_target_interface,
-        "org.freedesktop.systemd1.Device",     bus_device_interface,
-        "org.freedesktop.systemd1.Mount",      bus_mount_interface,
-        "org.freedesktop.systemd1.Automount",  bus_automount_interface,
-        "org.freedesktop.systemd1.Snapshot",   bus_snapshot_interface,
-        "org.freedesktop.systemd1.Swap",       bus_swap_interface,
-        "org.freedesktop.systemd1.Timer",      bus_timer_interface,
-        "org.freedesktop.systemd1.Path",       bus_path_interface,
-        NULL
-};
-
-static void bus_done_api(Manager *m);
-static void bus_done_system(Manager *m);
-static void bus_done_private(Manager *m);
-static void shutdown_connection(Manager *m, DBusConnection *c);
-
-static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
-        Manager *m = data;
-
-        assert(bus);
-        assert(m);
-
-        /* We maintain two sets, one for those connections where we
-         * requested a dispatch, and another where we didn't. And then,
-         * we move the connections between the two sets. */
-
-        if (status == DBUS_DISPATCH_COMPLETE)
-                set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
-        else
-                set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
-}
-
-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, bus_events_to_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) {
-                        close_nointr_nofail(w->fd);
-                        free(w);
-                        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);
-
-        w = dbus_watch_get_data(bus_watch);
-        if (!w)
-                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);
-
-        w = dbus_watch_get_data(bus_watch);
-        if (!w)
-                return;
-
-        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_value;
-        }
-
-        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);
-
-        w = dbus_timeout_get_data(timeout);
-        if (!w)
-                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);
-
-        w = dbus_timeout_get_data(timeout);
-        if (!w)
-                return;
-
-        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;
-        DBusMessage *reply = NULL;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
-            dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
-                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_debug("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", bus_error_message(&error));
-                else  {
-                        if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
-                                log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
-
-                        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);
-                }
-        } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
-                const char *name;
-
-                if (!dbus_message_get_args(message, &error,
-                                           DBUS_TYPE_STRING, &name,
-                                           DBUS_TYPE_INVALID))
-                        log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
-                else  {
-                        int r;
-                        Unit *u;
-
-                        log_debug("Got D-Bus activation request for %s", name);
-
-                        if (manager_unit_pending_inactive(m, SPECIAL_DBUS_SERVICE) ||
-                            manager_unit_pending_inactive(m, SPECIAL_DBUS_SOCKET)) {
-                                r = -EADDRNOTAVAIL;
-                                dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
-                        } else {
-                                r = manager_load_unit(m, name, NULL, &error, &u);
-
-                                if (r >= 0 && u->refuse_manual_start)
-                                        r = -EPERM;
-
-                                if (r >= 0)
-                                        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
-                        }
-
-                        if (r < 0) {
-                                const char *id, *text;
-
-                                log_debug("D-Bus activation failed for %s: %s", name, strerror(-r));
-
-                                if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
-                                        goto oom;
-
-                                id = error.name ? error.name : bus_errno_to_dbus(r);
-                                text = bus_error(&error, r);
-
-                                if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
-                                    !dbus_message_append_args(reply,
-                                                              DBUS_TYPE_STRING, &name,
-                                                              DBUS_TYPE_STRING, &id,
-                                                              DBUS_TYPE_STRING, &text,
-                                                              DBUS_TYPE_INVALID))
-                                        goto oom;
-                        }
-
-                        /* On success we don't do anything, the service will be spawned now */
-                }
-        }
-
-        dbus_error_free(&error);
-
-        if (reply) {
-                if (!dbus_connection_send(connection, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-        }
-
-        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 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);
-
-        if (m->api_bus != m->system_bus &&
-            (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
-             dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL))
-                log_debug("Got D-Bus request on system bus: %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_debug("System D-Bus connection terminated.");
-                bus_done_system(m);
-
-        } else if (m->running_as != MANAGER_SYSTEM &&
-                   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", bus_error_message(&error));
-                else
-                        cgroup_notify_empty(m, cgroup);
-        }
-
-        dbus_error_free(&error);
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
-        Manager *m = data;
-        DBusError error;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
-            dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
-                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"))
-                shutdown_connection(m, connection);
-        else if (m->running_as == MANAGER_SYSTEM &&
-                 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", bus_error_message(&error));
-                else
-                        cgroup_notify_empty(m, cgroup);
-
-                /* Forward the message to the system bus, so that user
-                 * instances are notified as well */
-
-                if (m->system_bus)
-                        dbus_connection_send(m->system_bus, message, NULL);
-        }
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-unsigned bus_dispatch(Manager *m) {
-        DBusConnection *c;
-
-        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 (m->queued_message_connection)
-                        if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL))
-                                return 0;
-
-                dbus_message_unref(m->queued_message);
-                m->queued_message = NULL;
-                m->queued_message_connection = NULL;
-        }
-
-        if ((c = set_first(m->bus_connections_for_dispatch))) {
-                if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE)
-                        set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c);
-
-                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", bus_error_message(&error));
-                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", bus_error_message(&error));
-                        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";
-        /* Allow replacing of our name, to ease implementation of
-         * reexecution, where we keep the old connection open until
-         * after the new connection is set up and the name installed
-         * to allow clients to synchronously wait for reexecution to
-         * finish */
-        uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
-        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 void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
-        DBusMessage *reply;
-        DBusError error;
-        Manager *m = userdata;
-
-        assert(m);
-
-        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("ListNames() failed: %s", bus_error_message(&error));
-                break;
-
-        case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
-                int r;
-                char **l;
-
-                if ((r = bus_parse_strv(reply, &l)) < 0)
-                        log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
-                else {
-                        char **t;
-
-                        STRV_FOREACH(t, l)
-                                /* This is a bit hacky, we say the
-                                 * owner of the name is the name
-                                 * itself, because we don't want the
-                                 * extra traffic to figure out the
-                                 * real owner. */
-                                manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
-
-                        strv_free(l);
-                }
-
-                break;
-        }
-
-        default:
-                assert_not_reached("Invalid reply message");
-        }
-
-        dbus_message_unref(reply);
-        dbus_error_free(&error);
-}
-
-static int query_name_list(Manager *m) {
-        DBusMessage *message = NULL;
-        DBusPendingCall *pending = NULL;
-
-        /* Asks for the currently installed bus names */
-
-        if (!(message = dbus_message_new_method_call(
-                              DBUS_SERVICE_DBUS,
-                              DBUS_PATH_DBUS,
-                              DBUS_INTERFACE_DBUS,
-                              "ListNames")))
-                goto oom;
-
-        if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
-                goto oom;
-
-        if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
-                goto oom;
-
-        dbus_message_unref(message);
-        dbus_pending_call_unref(pending);
-
-        /* We simple ask for the list and don't wait for it. Sooner or
-         * later we'll get 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)) {
-                log_error("Not enough memory");
-                return -ENOMEM;
-        }
-
-        if (set_put(m->bus_connections_for_dispatch, bus) < 0) {
-                log_error("Not enough memory");
-                return -ENOMEM;
-        }
-
-        dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL);
-        return 0;
-}
-
-static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
-        return uid == 0 || uid == geteuid();
-}
-
-static void bus_new_connection(
-                DBusServer *server,
-                DBusConnection *new_connection,
-                void *data) {
-
-        Manager *m = data;
-
-        assert(m);
-
-        if (set_size(m->bus_connections) >= CONNECTIONS_MAX) {
-                log_error("Too many concurrent connections.");
-                return;
-        }
-
-        dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
-
-        if (bus_setup_loop(m, new_connection) < 0)
-                return;
-
-        if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
-            !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
-            !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
-            !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) {
-                log_error("Not enough memory.");
-                return;
-        }
-
-        log_debug("Accepted connection on private bus.");
-
-        dbus_connection_ref(new_connection);
-}
-
-static int init_registered_system_bus(Manager *m) {
-        char *id;
-
-        if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
-                log_error("Not enough memory");
-                return -ENOMEM;
-        }
-
-        if (m->running_as != MANAGER_SYSTEM) {
-                DBusError error;
-
-                dbus_error_init(&error);
-
-                dbus_bus_add_match(m->system_bus,
-                                   "type='signal',"
-                                   "interface='org.freedesktop.systemd1.Agent',"
-                                   "member='Released',"
-                                   "path='/org/freedesktop/systemd1/agent'",
-                                   &error);
-
-                if (dbus_error_is_set(&error)) {
-                        log_error("Failed to register match: %s", bus_error_message(&error));
-                        dbus_error_free(&error);
-                        return -1;
-                }
-        }
-
-        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;
-}
-
-static int init_registered_api_bus(Manager *m) {
-        int 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)) {
-                log_error("Not enough memory");
-                return -ENOMEM;
-        }
-
-        /* Get NameOwnerChange messages */
-        dbus_bus_add_match(m->api_bus,
-                           "type='signal',"
-                           "sender='"DBUS_SERVICE_DBUS"',"
-                           "interface='"DBUS_INTERFACE_DBUS"',"
-                           "member='NameOwnerChanged',"
-                           "path='"DBUS_PATH_DBUS"'",
-                           NULL);
-
-        /* Get activation requests */
-        dbus_bus_add_match(m->api_bus,
-                           "type='signal',"
-                           "sender='"DBUS_SERVICE_DBUS"',"
-                           "interface='org.freedesktop.systemd1.Activator',"
-                           "member='ActivationRequest',"
-                           "path='"DBUS_PATH_DBUS"'",
-                           NULL);
-
-        r = request_name(m);
-        if (r < 0)
-                return r;
-
-        r = query_name_list(m);
-        if (r < 0)
-                return r;
-
-        if (m->running_as == MANAGER_USER) {
-                char *id;
-                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);
-        } else
-                log_debug("Successfully initialized API on the system bus");
-
-        return 0;
-}
-
-static void bus_register_cb(DBusPendingCall *pending, void *userdata) {
-        Manager *m = userdata;
-        DBusConnection **conn;
-        DBusMessage *reply;
-        DBusError error;
-        const char *name;
-        int r = 0;
-
-        dbus_error_init(&error);
-
-        conn = dbus_pending_call_get_data(pending, m->conn_data_slot);
-        assert(conn == &m->system_bus || conn == &m->api_bus);
-
-        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("Failed to register to bus: %s", bus_error_message(&error));
-                r = -1;
-                break;
-        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
-                if (!dbus_message_get_args(reply, &error,
-                                           DBUS_TYPE_STRING, &name,
-                                           DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse Hello reply: %s", bus_error_message(&error));
-                        r = -1;
-                        break;
-                }
-
-                log_debug("Received name %s in reply to Hello", name);
-                if (!dbus_bus_set_unique_name(*conn, name)) {
-                        log_error("Failed to set unique name");
-                        r = -1;
-                        break;
-                }
-
-                if (conn == &m->system_bus) {
-                        r = init_registered_system_bus(m);
-                        if (r == 0 && m->running_as == MANAGER_SYSTEM)
-                                r = init_registered_api_bus(m);
-                } else
-                        r = init_registered_api_bus(m);
-
-                break;
-        default:
-                assert_not_reached("Invalid reply message");
-        }
-
-        dbus_message_unref(reply);
-        dbus_error_free(&error);
-
-        if (r < 0) {
-                if (conn == &m->system_bus) {
-                        log_debug("Failed setting up the system bus");
-                        bus_done_system(m);
-                } else {
-                        log_debug("Failed setting up the API bus");
-                        bus_done_api(m);
-                }
-        }
-}
-
-static int manager_bus_async_register(Manager *m, DBusConnection **conn) {
-        DBusMessage *message = NULL;
-        DBusPendingCall *pending = NULL;
-
-        message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
-                                               DBUS_PATH_DBUS,
-                                               DBUS_INTERFACE_DBUS,
-                                               "Hello");
-        if (!message)
-                goto oom;
-
-        if (!dbus_connection_send_with_reply(*conn, message, &pending, -1))
-                goto oom;
-
-        if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL))
-                goto oom;
-
-        if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL))
-                goto oom;
-
-        dbus_message_unref(message);
-        dbus_pending_call_unref(pending);
-
-        return 0;
-oom:
-        if (pending) {
-                dbus_pending_call_cancel(pending);
-                dbus_pending_call_unref(pending);
-        }
-
-        if (message)
-                dbus_message_unref(message);
-
-        return -ENOMEM;
-}
-
-static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) {
-        const char *address;
-        DBusConnection *connection;
-        DBusError error;
-
-        switch (type) {
-        case DBUS_BUS_SYSTEM:
-                address = getenv("DBUS_SYSTEM_BUS_ADDRESS");
-                if (!address || !address[0])
-                        address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
-                break;
-        case DBUS_BUS_SESSION:
-                address = getenv("DBUS_SESSION_BUS_ADDRESS");
-                if (!address || !address[0])
-                        address = DBUS_SESSION_BUS_DEFAULT_ADDRESS;
-                break;
-        default:
-                assert_not_reached("Invalid bus type");
-        }
-
-        dbus_error_init(&error);
-
-        connection = dbus_connection_open_private(address, &error);
-        if (!connection) {
-                log_warning("Failed to open private bus connection: %s", bus_error_message(&error));
-                goto fail;
-        }
-
-        return connection;
-fail:
-        if (connection)
-                dbus_connection_close(connection);
-        dbus_error_free(&error);
-        return NULL;
-}
-
-static int bus_init_system(Manager *m) {
-        int r;
-
-        if (m->system_bus)
-                return 0;
-
-        m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM);
-        if (!m->system_bus) {
-                log_debug("Failed to connect to system D-Bus, retrying later");
-                r = 0;
-                goto fail;
-        }
-
-        r = bus_setup_loop(m, m->system_bus);
-        if (r < 0)
-                goto fail;
-
-        r = manager_bus_async_register(m, &m->system_bus);
-        if (r < 0)
-                goto fail;
-
-        return 0;
-fail:
-        bus_done_system(m);
-
-        return r;
-}
-
-static int bus_init_api(Manager *m) {
-        int r;
-
-        if (m->api_bus)
-                return 0;
-
-        if (m->running_as == MANAGER_SYSTEM) {
-                m->api_bus = m->system_bus;
-                /* In this mode there is no distinct connection to the API bus,
-                 * the API is published on the system bus.
-                 * bus_register_cb() is aware of that and will init the API
-                 * when the system bus gets registered.
-                 * No need to setup anything here. */
-                return 0;
-        }
-
-        m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION);
-        if (!m->api_bus) {
-                log_debug("Failed to connect to API D-Bus, retrying later");
-                r = 0;
-                goto fail;
-        }
-
-        r = bus_setup_loop(m, m->api_bus);
-        if (r < 0)
-                goto fail;
-
-        r = manager_bus_async_register(m, &m->api_bus);
-        if (r < 0)
-                goto fail;
-
-        return 0;
-fail:
-        bus_done_api(m);
-
-        return r;
-}
-
-static int bus_init_private(Manager *m) {
-        DBusError error;
-        int r;
-        const char *const external_only[] = {
-                "EXTERNAL",
-                NULL
-        };
-
-        assert(m);
-
-        dbus_error_init(&error);
-
-        if (m->private_bus)
-                return 0;
-
-        if (m->running_as == MANAGER_SYSTEM) {
-
-                /* We want the private bus only when running as init */
-                if (getpid() != 1)
-                        return 0;
-
-                unlink("/run/systemd/private");
-                m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
-        } else {
-                const char *e;
-                char *p;
-
-                e = getenv("XDG_RUNTIME_DIR");
-                if (!e)
-                        return 0;
-
-                if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) {
-                        log_error("Not enough memory");
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                mkdir_parents(p+10, 0755);
-                unlink(p+10);
-                m->private_bus = dbus_server_listen(p, &error);
-                free(p);
-        }
-
-        if (!m->private_bus) {
-                log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
-                r = -EIO;
-                goto fail;
-        }
-
-        if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) ||
-            !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
-            !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
-                log_error("Not enough memory");
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL);
-
-        log_debug("Successfully created private D-Bus server.");
-
-        return 0;
-
-fail:
-        bus_done_private(m);
-        dbus_error_free(&error);
-
-        return r;
-}
-
-int bus_init(Manager *m, bool try_bus_connect) {
-        int r;
-
-        if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
-            set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
-                goto oom;
-
-        if (m->name_data_slot < 0)
-                if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
-                        goto oom;
-
-        if (m->conn_data_slot < 0)
-                if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot))
-                        goto oom;
-
-        if (m->subscribed_data_slot < 0)
-                if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot))
-                        goto oom;
-
-        if (try_bus_connect) {
-                if ((r = bus_init_system(m)) < 0 ||
-                    (r = bus_init_api(m)) < 0)
-                        return r;
-        }
-
-        if ((r = bus_init_private(m)) < 0)
-                return r;
-
-        return 0;
-oom:
-        log_error("Not enough memory");
-        return -ENOMEM;
-}
-
-static void shutdown_connection(Manager *m, DBusConnection *c) {
-        Set *s;
-        Job *j;
-        Iterator i;
-
-        HASHMAP_FOREACH(j, m->jobs, i)
-                if (j->bus == c) {
-                        free(j->bus_client);
-                        j->bus_client = NULL;
-
-                        j->bus = NULL;
-                }
-
-        set_remove(m->bus_connections, c);
-        set_remove(m->bus_connections_for_dispatch, c);
-
-        if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
-                char *t;
-
-                while ((t = set_steal_first(s)))
-                        free(t);
-
-                set_free(s);
-        }
-
-        if (m->queued_message_connection == c) {
-                m->queued_message_connection = NULL;
-
-                if (m->queued_message) {
-                        dbus_message_unref(m->queued_message);
-                        m->queued_message = NULL;
-                }
-        }
-
-        dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
-        /* system manager cannot afford to block on DBus */
-        if (m->running_as != MANAGER_SYSTEM)
-                dbus_connection_flush(c);
-        dbus_connection_close(c);
-        dbus_connection_unref(c);
-}
-
-static void bus_done_api(Manager *m) {
-        if (!m->api_bus)
-                return;
-
-        if (m->running_as == MANAGER_USER)
-                shutdown_connection(m, m->api_bus);
-
-        m->api_bus = NULL;
-
-        if (m->queued_message) {
-                dbus_message_unref(m->queued_message);
-                m->queued_message = NULL;
-        }
-}
-
-static void bus_done_system(Manager *m) {
-        if (!m->system_bus)
-                return;
-
-        if (m->running_as == MANAGER_SYSTEM)
-                bus_done_api(m);
-
-        shutdown_connection(m, m->system_bus);
-        m->system_bus = NULL;
-}
-
-static void bus_done_private(Manager *m) {
-        if (!m->private_bus)
-                return;
-
-        dbus_server_disconnect(m->private_bus);
-        dbus_server_unref(m->private_bus);
-        m->private_bus = NULL;
-}
-
-void bus_done(Manager *m) {
-        DBusConnection *c;
-
-        bus_done_api(m);
-        bus_done_system(m);
-        bus_done_private(m);
-
-        while ((c = set_steal_first(m->bus_connections)))
-                shutdown_connection(m, c);
-
-        while ((c = set_steal_first(m->bus_connections_for_dispatch)))
-                shutdown_connection(m, c);
-
-        set_free(m->bus_connections);
-        set_free(m->bus_connections_for_dispatch);
-
-        if (m->name_data_slot >= 0)
-               dbus_pending_call_free_data_slot(&m->name_data_slot);
-
-        if (m->conn_data_slot >= 0)
-               dbus_pending_call_free_data_slot(&m->conn_data_slot);
-
-        if (m->subscribed_data_slot >= 0)
-                dbus_connection_free_data_slot(&m->subscribed_data_slot);
-}
-
-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 = BUS_PENDING_CALL_NAME(m, pending));
-        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", bus_error_message(&error));
-                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", bus_error_message(&error));
-                        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;
-}
-
-int bus_broadcast(Manager *m, DBusMessage *message) {
-        bool oom = false;
-        Iterator i;
-        DBusConnection *c;
-
-        assert(m);
-        assert(message);
-
-        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
-                if (c != m->system_bus || m->running_as == MANAGER_SYSTEM)
-                        oom = !dbus_connection_send(c, message, NULL);
-
-        SET_FOREACH(c, m->bus_connections, i)
-                if (c != m->system_bus || m->running_as == MANAGER_SYSTEM)
-                        oom = !dbus_connection_send(c, message, NULL);
-
-        return oom ? -ENOMEM : 0;
-}
-
-bool bus_has_subscriber(Manager *m) {
-        Iterator i;
-        DBusConnection *c;
-
-        assert(m);
-
-        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
-                if (bus_connection_has_subscriber(m, c))
-                        return true;
-
-        SET_FOREACH(c, m->bus_connections, i)
-                if (bus_connection_has_subscriber(m, c))
-                        return true;
-
-        return false;
-}
-
-bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
-        assert(m);
-        assert(c);
-
-        return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
-}
-
-int bus_fdset_add_all(Manager *m, FDSet *fds) {
-        Iterator i;
-        DBusConnection *c;
-
-        assert(m);
-        assert(fds);
-
-        /* When we are about to reexecute we add all D-Bus fds to the
-         * set to pass over to the newly executed systemd. They won't
-         * be used there however, except that they are closed at the
-         * very end of deserialization, those making it possible for
-         * clients to synchronously wait for systemd to reexec by
-         * simply waiting for disconnection */
-
-        SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
-                int fd;
-
-                if (dbus_connection_get_unix_fd(c, &fd)) {
-                        fd = fdset_put_dup(fds, fd);
-
-                        if (fd < 0)
-                                return fd;
-                }
-        }
-
-        SET_FOREACH(c, m->bus_connections, i) {
-                int fd;
-
-                if (dbus_connection_get_unix_fd(c, &fd)) {
-                        fd = fdset_put_dup(fds, fd);
-
-                        if (fd < 0)
-                                return fd;
-                }
-        }
-
-        return 0;
-}
-
-void bus_broadcast_finished(
-                Manager *m,
-                usec_t kernel_usec,
-                usec_t initrd_usec,
-                usec_t userspace_usec,
-                usec_t total_usec) {
-
-        DBusMessage *message;
-
-        assert(m);
-
-        message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
-        if (!message) {
-                log_error("Out of memory.");
-                return;
-        }
-
-        assert_cc(sizeof(usec_t) == sizeof(uint64_t));
-        if (!dbus_message_append_args(message,
-                                      DBUS_TYPE_UINT64, &kernel_usec,
-                                      DBUS_TYPE_UINT64, &initrd_usec,
-                                      DBUS_TYPE_UINT64, &userspace_usec,
-                                      DBUS_TYPE_UINT64, &total_usec,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Out of memory.");
-                goto finish;
-        }
-
-
-        if (bus_broadcast(m, message) < 0) {
-                log_error("Out of memory.");
-                goto finish;
-        }
-
-finish:
-        if (message)
-                dbus_message_unref(message);
-}
diff --git a/src/dbus.h b/src/dbus.h
deleted file mode 100644
index bd539d0..0000000
--- a/src/dbus.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-int bus_init(Manager *m, bool try_bus_connect);
-void bus_done(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);
-
-int bus_broadcast(Manager *m, DBusMessage *message);
-
-bool bus_has_subscriber(Manager *m);
-bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
-
-int bus_fdset_add_all(Manager *m, FDSet *fds);
-
-void bus_broadcast_finished(Manager *m, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec);
-
-#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot)
-#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot)
-
-extern const char * const bus_interface_table[];
-
-#endif
diff --git a/src/device.c b/src/device.c
deleted file mode 100644
index 0575379..0000000
--- a/src/device.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "def.h"
-
-static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
-        [DEVICE_DEAD] = UNIT_INACTIVE,
-        [DEVICE_PLUGGED] = UNIT_ACTIVE
-};
-
-static void device_unset_sysfs(Device *d) {
-        Device *first;
-
-        assert(d);
-
-        if (!d->sysfs)
-                return;
-
-        /* Remove this unit from the chain of devices which share the
-         * same sysfs path. */
-        first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
-        LIST_REMOVE(Device, same_sysfs, first, d);
-
-        if (first)
-                hashmap_remove_and_replace(UNIT(d)->manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
-        else
-                hashmap_remove(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
-
-        free(d->sysfs);
-        d->sysfs = NULL;
-}
-
-static void device_init(Unit *u) {
-        Device *d = DEVICE(u);
-
-        assert(d);
-        assert(UNIT(d)->load_state == UNIT_STUB);
-
-        /* In contrast to all other unit types we timeout jobs waiting
-         * for devices by default. This is because they otherwise wait
-         * indefinitely for plugged in devices, something which cannot
-         * happen for the other units since their operations time out
-         * anyway. */
-        UNIT(d)->job_timeout = DEFAULT_TIMEOUT_USEC;
-
-        UNIT(d)->ignore_on_isolate = true;
-        UNIT(d)->ignore_on_snapshot = true;
-}
-
-static void device_done(Unit *u) {
-        Device *d = DEVICE(u);
-
-        assert(d);
-
-        device_unset_sysfs(d);
-}
-
-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)->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], true);
-}
-
-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_PLUGGED);
-
-        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) {
-        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);
-        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_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
-        const char *sysfs, *model;
-        Unit *u = NULL;
-        int r;
-        bool delete;
-
-        assert(m);
-
-        if (!(sysfs = udev_device_get_syspath(dev)))
-                return -ENOMEM;
-
-        if ((r = device_find_escape_name(m, path, &u)) < 0)
-                return r;
-
-        if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
-                return -EEXIST;
-
-        if (!u) {
-                delete = true;
-
-                u = unit_new(m, sizeof(Device));
-                if (!u)
-                        return -ENOMEM;
-
-                r = device_add_escaped_name(u, path);
-                if (r < 0)
-                        goto fail;
-
-                unit_add_to_load_queue(u);
-        } else
-                delete = false;
-
-        /* If this was created via some dependency and has not
-         * actually been seen yet ->sysfs will not be
-         * initialized. Hence initialize it if necessary. */
-
-        if (!DEVICE(u)->sysfs) {
-                Device *first;
-
-                if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                if (!m->devices_by_sysfs)
-                        if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                first = hashmap_get(m->devices_by_sysfs, sysfs);
-                LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
-
-                if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 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 ((r = unit_set_description(u, path)) < 0)
-                        goto fail;
-
-        if (main) {
-                /* The additional systemd udev properties we only
-                 * interpret for the main object */
-                const char *wants, *alias;
-
-                if ((alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS"))) {
-                        if (!is_path(alias))
-                                log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, alias);
-                        else {
-                                if ((r = device_add_escaped_name(u, alias)) < 0)
-                                        goto fail;
-                        }
-                }
-
-                if ((wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"))) {
-                        char *state, *w;
-                        size_t l;
-
-                        FOREACH_WORD_QUOTED(w, l, wants, state) {
-                                char *e;
-
-                                if (!(e = strndup(w, l))) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true);
-                                free(e);
-
-                                if (r < 0)
-                                        goto fail;
-                        }
-                }
-        }
-
-        unit_add_to_dbus_queue(u);
-        return 0;
-
-fail:
-        log_warning("Failed to load device unit: %s", strerror(-r));
-
-        if (delete && u)
-                unit_free(u);
-
-        return r;
-}
-
-static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
-        const char *sysfs, *dn;
-        struct udev_list_entry *item = NULL, *first = NULL;
-
-        assert(m);
-
-        if (!(sysfs = udev_device_get_syspath(dev)))
-                return -ENOMEM;
-
-        /* Add the main unit named after the sysfs path */
-        device_update_unit(m, dev, sysfs, true);
-
-        /* Add an additional unit for the device node */
-        if ((dn = udev_device_get_devnode(dev)))
-                device_update_unit(m, dev, dn, false);
-
-        /* Add additional units for all symlinks */
-        first = udev_device_get_devlinks_list_entry(dev);
-        udev_list_entry_foreach(item, first) {
-                const char *p;
-                struct stat st;
-
-                /* Don't bother with the /dev/block links */
-                p = udev_list_entry_get_name(item);
-
-                if (path_startswith(p, "/dev/block/") ||
-                    path_startswith(p, "/dev/char/"))
-                        continue;
-
-                /* Verify that the symlink in the FS actually belongs
-                 * to this device. This is useful to deal with
-                 * conflicting devices, e.g. when two disks want the
-                 * same /dev/disk/by-label/xxx link because they have
-                 * the same label. We want to make sure that the same
-                 * device that won the symlink wins in systemd, so we
-                 * check the device node major/minor*/
-                if (stat(p, &st) >= 0)
-                        if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
-                            st.st_rdev != udev_device_get_devnum(dev))
-                                continue;
-
-                device_update_unit(m, dev, p, false);
-        }
-
-        if (update_state) {
-                Device *d, *l;
-
-                manager_dispatch_load_queue(m);
-
-                l = hashmap_get(m->devices_by_sysfs, sysfs);
-                LIST_FOREACH(same_sysfs, d, l)
-                        device_set_state(d, DEVICE_PLUGGED);
-        }
-
-        return 0;
-}
-
-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;
-        Device *d;
-
-        assert(m);
-        assert(dev);
-
-        if (!(sysfs = udev_device_get_syspath(dev)))
-                return -ENOMEM;
-
-        /* Remove all units of this sysfs path */
-        while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
-                device_unset_sysfs(d);
-                device_set_state(d, DEVICE_DEAD);
-        }
-
-        return 0;
-}
-
-static Unit *device_following(Unit *u) {
-        Device *d = DEVICE(u);
-        Device *other, *first = NULL;
-
-        assert(d);
-
-        if (startswith(u->id, "sys-"))
-                return NULL;
-
-        /* Make everybody follow the unit that's named after the sysfs path */
-        for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
-                if (startswith(UNIT(other)->id, "sys-"))
-                        return UNIT(other);
-
-        for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
-                if (startswith(UNIT(other)->id, "sys-"))
-                        return UNIT(other);
-
-                first = other;
-        }
-
-        return UNIT(first);
-}
-
-static int device_following_set(Unit *u, Set **_s) {
-        Device *d = DEVICE(u);
-        Device *other;
-        Set *s;
-        int r;
-
-        assert(d);
-        assert(_s);
-
-        if (!d->same_sysfs_prev && !d->same_sysfs_next) {
-                *_s = NULL;
-                return 0;
-        }
-
-        if (!(s = set_new(NULL, NULL)))
-                return -ENOMEM;
-
-        for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
-                if ((r = set_put(s, other)) < 0)
-                        goto fail;
-
-        for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
-                if ((r = set_put(s, other)) < 0)
-                        goto fail;
-
-        *_s = s;
-        return 1;
-
-fail:
-        set_free(s);
-        return r;
-}
-
-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;
-        }
-
-        hashmap_free(m->devices_by_sysfs);
-        m->devices_by_sysfs = 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;
-                }
-
-                /* This will fail if we are unprivileged, but that
-                 * should not matter much, as user instances won't run
-                 * during boot. */
-                udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
-
-                if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
-                        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_add_match_tag(e, "systemd") < 0) {
-                r = -EIO;
-                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, *ready;
-
-        assert(m);
-
-        if (events != EPOLLIN) {
-                static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
-
-                if (!ratelimit_test(&limit))
-                        log_error("Failed to get udev event: %m");
-                if (!(events & EPOLLIN))
-                        return;
-        }
-
-        if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
-                /*
-                 * libudev might filter-out devices which pass the bloom filter,
-                 * so getting NULL here is not necessarily an error
-                 */
-                return;
-        }
-
-        if (!(action = udev_device_get_action(dev))) {
-                log_error("Failed to get udev action string.");
-                goto fail;
-        }
-
-        ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
-
-        if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
-                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_PLUGGED] = "plugged"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
-
-const UnitVTable device_vtable = {
-        .suffix = ".device",
-        .object_size = sizeof(Device),
-        .sections =
-                "Unit\0"
-                "Device\0"
-                "Install\0",
-
-        .no_instances = true,
-
-        .init = device_init,
-
-        .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_interface = "org.freedesktop.systemd1.Device",
-        .bus_message_handler = bus_device_message_handler,
-        .bus_invalidating_properties =  bus_device_invalidating_properties,
-
-        .following = device_following,
-        .following_set = device_following_set,
-
-        .enumerate = device_enumerate,
-        .shutdown = device_shutdown
-};
diff --git a/src/device.h b/src/device.h
deleted file mode 100644
index a05c3d3..0000000
--- a/src/device.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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_PLUGGED,
-        _DEVICE_STATE_MAX,
-        _DEVICE_STATE_INVALID = -1
-} DeviceState;
-
-struct Device {
-        Unit meta;
-
-        char *sysfs;
-
-        /* In order to be able to distinguish dependencies on
-        different device nodes we might end up creating multiple
-        devices for the same sysfs path. We chain them up here. */
-
-        LIST_FIELDS(struct Device, same_sysfs);
-
-        DeviceState state;
-};
-
-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
deleted file mode 100644
index 179ca7e..0000000
--- a/src/execute.c
+++ /dev/null
@@ -1,2113 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <linux/oom.h>
-
-#ifdef HAVE_PAM
-#include <security/pam_appl.h>
-#endif
-
-#include "execute.h"
-#include "strv.h"
-#include "macro.h"
-#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "cgroup.h"
-#include "namespace.h"
-#include "tcpwrap.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "utmp-wtmp.h"
-#include "def.h"
-#include "loopback-setup.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";
-}
-
-void exec_context_tty_reset(const ExecContext *context) {
-        assert(context);
-
-        if (context->tty_vhangup)
-                terminal_vhangup(tty_path(context));
-
-        if (context->tty_reset)
-                reset_terminal(tty_path(context));
-
-        if (context->tty_vt_disallocate && context->tty_path)
-                vt_disallocate(context->tty_path);
-}
-
-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 sockaddr_union sa;
-
-        assert(context);
-        assert(output < _EXEC_OUTPUT_MAX);
-        assert(ident);
-        assert(nfd >= 0);
-
-        fd = socket(AF_UNIX, SOCK_STREAM, 0);
-        if (fd < 0)
-                return -errno;
-
-        zero(sa);
-        sa.un.sun_family = AF_UNIX;
-        strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
-
-        r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
-        if (r < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        if (shutdown(fd, SHUT_RD) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        dprintf(fd,
-                "%s\n"
-                "%i\n"
-                "%i\n"
-                "%i\n"
-                "%i\n"
-                "%i\n",
-                context->syslog_identifier ? context->syslog_identifier : ident,
-                context->syslog_priority,
-                !!context->syslog_level_prefix,
-                output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
-                output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
-                output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || output == EXEC_OUTPUT_KMSG_AND_CONSOLE || output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
-
-        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(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
-
-        if (is_terminal_input(std_input) && !apply_tty_stdin)
-                return EXEC_INPUT_NULL;
-
-        if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
-                return EXEC_INPUT_NULL;
-
-        return std_input;
-}
-
-static int fixup_output(ExecOutput std_output, int socket_fd) {
-
-        if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
-                return EXEC_OUTPUT_INHERIT;
-
-        return std_output;
-}
-
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
-        ExecInput i;
-
-        assert(context);
-
-        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
-
-        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,
-                                     false)) < 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, bool apply_tty_stdin) {
-        ExecOutput o;
-        ExecInput i;
-
-        assert(context);
-        assert(ident);
-
-        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
-        o = fixup_output(context->std_output, socket_fd);
-
-        /* This expects the input is already set up */
-
-        switch (o) {
-
-        case EXEC_OUTPUT_INHERIT:
-
-                /* If input got downgraded, inherit the original value */
-                if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
-                        return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
-
-                /* If the input is connected to anything that's not a /dev/null, inherit that... */
-                if (i != EXEC_INPUT_NULL)
-                        return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
-                /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
-                if (getppid() != 1)
-                        return STDOUT_FILENO;
-
-                /* We need to open /dev/null here anew, to get the
-                 * right access mode. So we fall through */
-
-        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_SYSLOG_AND_CONSOLE:
-        case EXEC_OUTPUT_KMSG:
-        case EXEC_OUTPUT_KMSG_AND_CONSOLE:
-        case EXEC_OUTPUT_JOURNAL:
-        case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
-                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, bool apply_tty_stdin) {
-        ExecOutput o, e;
-        ExecInput i;
-
-        assert(context);
-        assert(ident);
-
-        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
-        o = fixup_output(context->std_output, socket_fd);
-        e = fixup_output(context->std_error, 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 &&
-            i == EXEC_INPUT_NULL &&
-            !is_terminal_input(context->std_input) &&
-            getppid () != 1)
-                return STDERR_FILENO;
-
-        /* Duplicate from 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_SYSLOG_AND_CONSOLE:
-        case EXEC_OUTPUT_KMSG:
-        case EXEC_OUTPUT_KMSG_AND_CONSOLE:
-        case EXEC_OUTPUT_JOURNAL:
-        case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
-                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,
-                             false)) < 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 enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
-        bool keep_groups = false;
-        int r;
-
-        assert(context);
-
-        /* Lookup and set GID and supplementary group list. Here too
-         * we avoid NSS lookups for gid=0. */
-
-        if (context->group || username) {
-
-                if (context->group) {
-                        const char *g = context->group;
-
-                        if ((r = get_group_creds(&g, &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 */
-                assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
-
-                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) {
-                        const char *g;
-
-                        if (k >= ngroups_max) {
-                                free(gids);
-                                return -E2BIG;
-                        }
-
-                        g = *i;
-                        r = get_group_creds(&g, gids+k);
-                        if (r < 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 privileges. */
-                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 capabilities. 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;
-}
-
-#ifdef HAVE_PAM
-
-static int null_conv(
-                int num_msg,
-                const struct pam_message **msg,
-                struct pam_response **resp,
-                void *appdata_ptr) {
-
-        /* We don't support conversations */
-
-        return PAM_CONV_ERR;
-}
-
-static int setup_pam(
-                const char *name,
-                const char *user,
-                const char *tty,
-                char ***pam_env,
-                int fds[], unsigned n_fds) {
-
-        static const struct pam_conv conv = {
-                .conv = null_conv,
-                .appdata_ptr = NULL
-        };
-
-        pam_handle_t *handle = NULL;
-        sigset_t ss, old_ss;
-        int pam_code = PAM_SUCCESS;
-        int err;
-        char **e = NULL;
-        bool close_session = false;
-        pid_t pam_pid = 0, parent_pid;
-
-        assert(name);
-        assert(user);
-        assert(pam_env);
-
-        /* We set up PAM in the parent process, then fork. The child
-         * will then stay around until killed via PR_GET_PDEATHSIG or
-         * systemd via the cgroup logic. It will then remove the PAM
-         * session again. The parent process will exec() the actual
-         * daemon. We do things this way to ensure that the main PID
-         * of the daemon is the one we initially fork()ed. */
-
-        if ((pam_code = pam_start(name, user, &conv, &handle)) != PAM_SUCCESS) {
-                handle = NULL;
-                goto fail;
-        }
-
-        if (tty)
-                if ((pam_code = pam_set_item(handle, PAM_TTY, tty)) != PAM_SUCCESS)
-                        goto fail;
-
-        if ((pam_code = pam_acct_mgmt(handle, PAM_SILENT)) != PAM_SUCCESS)
-                goto fail;
-
-        if ((pam_code = pam_open_session(handle, PAM_SILENT)) != PAM_SUCCESS)
-                goto fail;
-
-        close_session = true;
-
-        if ((!(e = pam_getenvlist(handle)))) {
-                pam_code = PAM_BUF_ERR;
-                goto fail;
-        }
-
-        /* Block SIGTERM, so that we know that it won't get lost in
-         * the child */
-        if (sigemptyset(&ss) < 0 ||
-            sigaddset(&ss, SIGTERM) < 0 ||
-            sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
-                goto fail;
-
-        parent_pid = getpid();
-
-        if ((pam_pid = fork()) < 0)
-                goto fail;
-
-        if (pam_pid == 0) {
-                int sig;
-                int r = EXIT_PAM;
-
-                /* The child's job is to reset the PAM session on
-                 * termination */
-
-                /* This string must fit in 10 chars (i.e. the length
-                 * of "/sbin/init"), to look pretty in /bin/ps */
-                rename_process("(sd-pam)");
-
-                /* Make sure we don't keep open the passed fds in this
-                child. We assume that otherwise only those fds are
-                open here that have been opened by PAM. */
-                close_many(fds, n_fds);
-
-                /* Wait until our parent died. This will most likely
-                 * not work since the kernel does not allow
-                 * unprivileged parents kill their privileged children
-                 * this way. We rely on the control groups kill logic
-                 * to do the rest for us. */
-                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                        goto child_finish;
-
-                /* Check if our parent process might already have
-                 * died? */
-                if (getppid() == parent_pid) {
-                        for (;;) {
-                                if (sigwait(&ss, &sig) < 0) {
-                                        if (errno == EINTR)
-                                                continue;
-
-                                        goto child_finish;
-                                }
-
-                                assert(sig == SIGTERM);
-                                break;
-                        }
-                }
-
-                /* If our parent died we'll end the session */
-                if (getppid() != parent_pid)
-                        if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS)
-                                goto child_finish;
-
-                r = 0;
-
-        child_finish:
-                pam_end(handle, pam_code | PAM_DATA_SILENT);
-                _exit(r);
-        }
-
-        /* If the child was forked off successfully it will do all the
-         * cleanups, so forget about the handle here. */
-        handle = NULL;
-
-        /* Unblock SIGTERM again in the parent */
-        if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
-                goto fail;
-
-        /* We close the log explicitly here, since the PAM modules
-         * might have opened it, but we don't want this fd around. */
-        closelog();
-
-        *pam_env = e;
-        e = NULL;
-
-        return 0;
-
-fail:
-        if (pam_code != PAM_SUCCESS)
-                err = -EPERM;  /* PAM errors do not map to errno */
-        else
-                err = -errno;
-
-        if (handle) {
-                if (close_session)
-                        pam_code = pam_close_session(handle, PAM_DATA_SILENT);
-
-                pam_end(handle, pam_code | PAM_DATA_SILENT);
-        }
-
-        strv_free(e);
-
-        closelog();
-
-        if (pam_pid > 1) {
-                kill(pam_pid, SIGTERM);
-                kill(pam_pid, SIGCONT);
-        }
-
-        return err;
-}
-#endif
-
-static int do_capability_bounding_set_drop(uint64_t drop) {
-        unsigned long i;
-        cap_t old_cap = NULL, new_cap = NULL;
-        cap_flag_value_t fv;
-        int r;
-
-        /* If we are run as PID 1 we will lack CAP_SETPCAP by default
-         * in the effective set (yes, the kernel drops that when
-         * executing init!), so get it back temporarily so that we can
-         * call PR_CAPBSET_DROP. */
-
-        old_cap = cap_get_proc();
-        if (!old_cap)
-                return -errno;
-
-        if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (fv != CAP_SET) {
-                static const cap_value_t v = CAP_SETPCAP;
-
-                new_cap = cap_dup(old_cap);
-                if (!new_cap) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                if (cap_set_proc(new_cap) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-        }
-
-        for (i = 0; i <= cap_last_cap(); i++)
-                if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
-                        if (prctl(PR_CAPBSET_DROP, i) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-                }
-
-        r = 0;
-
-finish:
-        if (new_cap)
-                cap_free(new_cap);
-
-        if (old_cap) {
-                cap_set_proc(old_cap);
-                cap_free(old_cap);
-        }
-
-        return r;
-}
-
-static void rename_process_from_path(const char *path) {
-        char process_name[11];
-        const char *p;
-        size_t l;
-
-        /* This resulting string must fit in 10 chars (i.e. the length
-         * of "/sbin/init") to look pretty in /bin/ps */
-
-        p = file_name_from_path(path);
-        if (isempty(p)) {
-                rename_process("(...)");
-                return;
-        }
-
-        l = strlen(p);
-        if (l > 8) {
-                /* The end of the process name is usually more
-                 * interesting, since the first bit might just be
-                 * "systemd-" */
-                p = p + l - 8;
-                l = 8;
-        }
-
-        process_name[0] = '(';
-        memcpy(process_name+1, p, l);
-        process_name[1+l] = ')';
-        process_name[1+l+1] = 0;
-
-        rename_process(process_name);
-}
-
-int exec_spawn(ExecCommand *command,
-               char **argv,
-               const ExecContext *context,
-               int fds[], unsigned n_fds,
-               char **environment,
-               bool apply_permissions,
-               bool apply_chroot,
-               bool apply_tty_stdin,
-               bool confirm_spawn,
-               CGroupBonding *cgroup_bondings,
-               CGroupAttribute *cgroup_attributes,
-               pid_t *ret) {
-
-        pid_t pid;
-        int r;
-        char *line;
-        int socket_fd;
-        char **files_env = NULL;
-
-        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 ((r = exec_context_load_environment(context, &files_env)) < 0) {
-                log_error("Failed to load environment files: %s", strerror(-r));
-                return r;
-        }
-
-        if (!argv)
-                argv = command->argv;
-
-        if (!(line = exec_command_line(argv))) {
-                r = -ENOMEM;
-                goto fail_parent;
-        }
-
-        log_debug("About to execute: %s", line);
-        free(line);
-
-        r = cgroup_bonding_realize_list(cgroup_bondings);
-        if (r < 0)
-                goto fail_parent;
-
-        cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings);
-
-        if ((pid = fork()) < 0) {
-                r = -errno;
-                goto fail_parent;
-        }
-
-        if (pid == 0) {
-                int i, err;
-                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, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
-                unsigned n_env = 0;
-                int saved_stdout = -1, saved_stdin = -1;
-                bool keep_stdout = false, keep_stdin = false, set_access = false;
-
-                /* child */
-
-                rename_process_from_path(command->path);
-
-                /* We reset exactly these signals, since they are the
-                 * only ones we set to SIG_IGN in the main daemon. All
-                 * others we leave untouched because we set them to
-                 * SIG_DFL or a valid handler initially, both of which
-                 * will be demoted to SIG_DFL. */
-                default_signals(SIGNALS_CRASH_HANDLER,
-                                SIGNALS_IGNORE, -1);
-
-                if (context->ignore_sigpipe)
-                        ignore_signals(SIGPIPE, -1);
-
-                assert_se(sigemptyset(&ss) == 0);
-                if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
-                        err = -errno;
-                        r = EXIT_SIGNAL_MASK;
-                        goto fail_child;
-                }
-
-                /* Close sockets very early to make sure we don't
-                 * block init reexecution because it cannot bind its
-                 * sockets */
-                log_forget_fds();
-                err = close_all_fds(socket_fd >= 0 ? &socket_fd : fds,
-                                           socket_fd >= 0 ? 1 : n_fds);
-                if (err < 0) {
-                        r = EXIT_FDS;
-                        goto fail_child;
-                }
-
-                if (!context->same_pgrp)
-                        if (setsid() < 0) {
-                                err = -errno;
-                                r = EXIT_SETSID;
-                                goto fail_child;
-                        }
-
-                if (context->tcpwrap_name) {
-                        if (socket_fd >= 0)
-                                if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
-                                        err = -EACCES;
-                                        r = EXIT_TCPWRAP;
-                                        goto fail_child;
-                                }
-
-                        for (i = 0; i < (int) n_fds; i++) {
-                                if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) {
-                                        err = -EACCES;
-                                        r = EXIT_TCPWRAP;
-                                        goto fail_child;
-                                }
-                        }
-                }
-
-                exec_context_tty_reset(context);
-
-                /* We skip the confirmation step if we shall not apply the TTY */
-                if (confirm_spawn &&
-                    (!is_terminal_input(context->std_input) || apply_tty_stdin)) {
-                        char response;
-
-                        /* Set up terminal for the question */
-                        if ((r = setup_confirm_stdio(context,
-                                                     &saved_stdin, &saved_stdout))) {
-                                err = -errno;
-                                goto fail_child;
-                        }
-
-                        /* Now ask the question. */
-                        if (!(line = exec_command_line(argv))) {
-                                err = -ENOMEM;
-                                r = EXIT_MEMORY;
-                                goto fail_child;
-                        }
-
-                        r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line);
-                        free(line);
-
-                        if (r < 0 || response == 'n') {
-                                err = -ECANCELED;
-                                r = EXIT_CONFIRM;
-                                goto fail_child;
-                        } else if (response == 's') {
-                                err = r = 0;
-                                goto fail_child;
-                        }
-
-                        /* Release terminal for the question */
-                        if ((r = restore_confirm_stdio(context,
-                                                       &saved_stdin, &saved_stdout,
-                                                       &keep_stdin, &keep_stdout))) {
-                                err = -errno;
-                                goto fail_child;
-                        }
-                }
-
-                /* If a socket is connected to STDIN/STDOUT/STDERR, we
-                 * must sure to drop O_NONBLOCK */
-                if (socket_fd >= 0)
-                        fd_nonblock(socket_fd, false);
-
-                if (!keep_stdin) {
-                        err = setup_input(context, socket_fd, apply_tty_stdin);
-                        if (err < 0) {
-                                r = EXIT_STDIN;
-                                goto fail_child;
-                        }
-                }
-
-                if (!keep_stdout) {
-                        err = setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
-                        if (err < 0) {
-                                r = EXIT_STDOUT;
-                                goto fail_child;
-                        }
-                }
-
-                err = setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
-                if (err < 0) {
-                        r = EXIT_STDERR;
-                        goto fail_child;
-                }
-
-                if (cgroup_bondings) {
-                        err = cgroup_bonding_install_list(cgroup_bondings, 0);
-                        if (err < 0) {
-                                r = EXIT_CGROUP;
-                                goto fail_child;
-                        }
-                }
-
-                if (context->oom_score_adjust_set) {
-                        char t[16];
-
-                        snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
-                        char_array_0(t);
-
-                        if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
-                                /* Compatibility with Linux <= 2.6.35 */
-
-                                int adj;
-
-                                adj = (context->oom_score_adjust * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
-                                adj = CLAMP(adj, OOM_DISABLE, OOM_ADJUST_MAX);
-
-                                snprintf(t, sizeof(t), "%i", adj);
-                                char_array_0(t);
-
-                                if (write_one_line_file("/proc/self/oom_adj", t) < 0
-                                    && errno != EACCES) {
-                                        err = -errno;
-                                        r = EXIT_OOM_ADJUST;
-                                        goto fail_child;
-                                }
-                        }
-                }
-
-                if (context->nice_set)
-                        if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
-                                err = -errno;
-                                r = EXIT_NICE;
-                                goto fail_child;
-                        }
-
-                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) {
-                                err = -errno;
-                                r = EXIT_SETSCHEDULER;
-                                goto fail_child;
-                        }
-                }
-
-                if (context->cpuset)
-                        if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
-                                err = -errno;
-                                r = EXIT_CPUAFFINITY;
-                                goto fail_child;
-                        }
-
-                if (context->ioprio_set)
-                        if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
-                                err = -errno;
-                                r = EXIT_IOPRIO;
-                                goto fail_child;
-                        }
-
-                if (context->timer_slack_nsec_set)
-                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
-                                err = -errno;
-                                r = EXIT_TIMERSLACK;
-                                goto fail_child;
-                        }
-
-                if (context->utmp_id)
-                        utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
-
-                if (context->user) {
-                        username = context->user;
-                        err = get_user_creds(&username, &uid, &gid, &home);
-                        if (err < 0) {
-                                r = EXIT_USER;
-                                goto fail_child;
-                        }
-
-                        if (is_terminal_input(context->std_input)) {
-                                err = chown_terminal(STDIN_FILENO, uid);
-                                if (err < 0) {
-                                        r = EXIT_STDIN;
-                                        goto fail_child;
-                                }
-                        }
-
-                        if (cgroup_bondings && context->control_group_modify) {
-                                err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
-                                if (err >= 0)
-                                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid, context->control_group_persistent);
-                                if (err < 0) {
-                                        r = EXIT_CGROUP;
-                                        goto fail_child;
-                                }
-
-                                set_access = true;
-                        }
-                }
-
-                if (cgroup_bondings && !set_access && context->control_group_persistent >= 0)  {
-                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, (mode_t) -1, (uid_t) -1, (uid_t) -1, context->control_group_persistent);
-                        if (err < 0) {
-                                r = EXIT_CGROUP;
-                                goto fail_child;
-                        }
-                }
-
-                if (apply_permissions) {
-                        err = enforce_groups(context, username, gid);
-                        if (err < 0) {
-                                r = EXIT_GROUP;
-                                goto fail_child;
-                        }
-                }
-
-                umask(context->umask);
-
-#ifdef HAVE_PAM
-                if (context->pam_name && username) {
-                        err = setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds);
-                        if (err < 0) {
-                                r = EXIT_PAM;
-                                goto fail_child;
-                        }
-                }
-#endif
-                if (context->private_network) {
-                        if (unshare(CLONE_NEWNET) < 0) {
-                                err = -errno;
-                                r = EXIT_NETWORK;
-                                goto fail_child;
-                        }
-
-                        loopback_setup();
-                }
-
-                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) {
-                        err = setup_namespace(context->read_write_dirs,
-                                              context->read_only_dirs,
-                                              context->inaccessible_dirs,
-                                              context->private_tmp,
-                                              context->mount_flags);
-                        if (err < 0) {
-                                r = EXIT_NAMESPACE;
-                                goto fail_child;
-                        }
-                }
-
-                if (apply_chroot) {
-                        if (context->root_directory)
-                                if (chroot(context->root_directory) < 0) {
-                                        err = -errno;
-                                        r = EXIT_CHROOT;
-                                        goto fail_child;
-                                }
-
-                        if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
-                                err = -errno;
-                                r = EXIT_CHDIR;
-                                goto fail_child;
-                        }
-                } else {
-
-                        char *d;
-
-                        if (asprintf(&d, "%s/%s",
-                                     context->root_directory ? context->root_directory : "",
-                                     context->working_directory ? context->working_directory : "") < 0) {
-                                err = -ENOMEM;
-                                r = EXIT_MEMORY;
-                                goto fail_child;
-                        }
-
-                        if (chdir(d) < 0) {
-                                err = -errno;
-                                free(d);
-                                r = EXIT_CHDIR;
-                                goto fail_child;
-                        }
-
-                        free(d);
-                }
-
-                /* We repeat the fd closing here, to make sure that
-                 * nothing is leaked from the PAM modules */
-                err = close_all_fds(fds, n_fds);
-                if (err >= 0)
-                        err = shift_fds(fds, n_fds);
-                if (err >= 0)
-                        err = flags_fds(fds, n_fds, context->non_blocking);
-                if (err < 0) {
-                        r = EXIT_FDS;
-                        goto fail_child;
-                }
-
-                if (apply_permissions) {
-
-                        for (i = 0; i < RLIMIT_NLIMITS; i++) {
-                                if (!context->rlimit[i])
-                                        continue;
-
-                                if (setrlimit(i, context->rlimit[i]) < 0) {
-                                        err = -errno;
-                                        r = EXIT_LIMITS;
-                                        goto fail_child;
-                                }
-                        }
-
-                        if (context->capability_bounding_set_drop) {
-                                err = do_capability_bounding_set_drop(context->capability_bounding_set_drop);
-                                if (err < 0) {
-                                        r = EXIT_CAPABILITIES;
-                                        goto fail_child;
-                                }
-                        }
-
-                        if (context->user) {
-                                err = enforce_user(context, uid);
-                                if (err < 0) {
-                                        r = EXIT_USER;
-                                        goto fail_child;
-                                }
-                        }
-
-                        /* PR_GET_SECUREBITS is not privileged, 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) {
-                                        err = -errno;
-                                        r = EXIT_SECUREBITS;
-                                        goto fail_child;
-                                }
-
-                        if (context->capabilities)
-                                if (cap_set_proc(context->capabilities) < 0) {
-                                        err = -errno;
-                                        r = EXIT_CAPABILITIES;
-                                        goto fail_child;
-                                }
-                }
-
-                if (!(our_env = new0(char*, 7))) {
-                        err = -ENOMEM;
-                        r = EXIT_MEMORY;
-                        goto fail_child;
-                }
-
-                if (n_fds > 0)
-                        if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 ||
-                            asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
-                                err = -ENOMEM;
-                                r = EXIT_MEMORY;
-                                goto fail_child;
-                        }
-
-                if (home)
-                        if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
-                                err = -ENOMEM;
-                                r = EXIT_MEMORY;
-                                goto fail_child;
-                        }
-
-                if (username)
-                        if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
-                            asprintf(our_env + n_env++, "USER=%s", username) < 0) {
-                                err = -ENOMEM;
-                                r = EXIT_MEMORY;
-                                goto fail_child;
-                        }
-
-                if (is_terminal_input(context->std_input) ||
-                    context->std_output == EXEC_OUTPUT_TTY ||
-                    context->std_error == EXEC_OUTPUT_TTY)
-                        if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
-                                err = -ENOMEM;
-                                r = EXIT_MEMORY;
-                                goto fail_child;
-                        }
-
-                assert(n_env <= 7);
-
-                if (!(final_env = strv_env_merge(
-                                      5,
-                                      environment,
-                                      our_env,
-                                      context->environment,
-                                      files_env,
-                                      pam_env,
-                                      NULL))) {
-                        err = -ENOMEM;
-                        r = EXIT_MEMORY;
-                        goto fail_child;
-                }
-
-                if (!(final_argv = replace_env_argv(argv, final_env))) {
-                        err = -ENOMEM;
-                        r = EXIT_MEMORY;
-                        goto fail_child;
-                }
-
-                final_env = strv_env_clean(final_env);
-
-                execve(command->path, final_argv, final_env);
-                err = -errno;
-                r = EXIT_EXEC;
-
-        fail_child:
-                if (r != 0) {
-                        log_open();
-                        log_warning("Failed at step %s spawning %s: %s",
-                                    exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
-                                    command->path, strerror(-err));
-                }
-
-                strv_free(our_env);
-                strv_free(final_env);
-                strv_free(pam_env);
-                strv_free(files_env);
-                strv_free(final_argv);
-
-                if (saved_stdin >= 0)
-                        close_nointr_nofail(saved_stdin);
-
-                if (saved_stdout >= 0)
-                        close_nointr_nofail(saved_stdout);
-
-                _exit(r);
-        }
-
-        strv_free(files_env);
-
-        /* 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 %lu", command->path, (unsigned long) pid);
-
-        exec_status_start(&command->exec_status, pid);
-
-        *ret = pid;
-        return 0;
-
-fail_parent:
-        strv_free(files_env);
-
-        return r;
-}
-
-void exec_context_init(ExecContext *c) {
-        assert(c);
-
-        c->umask = 0022;
-        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
-        c->cpu_sched_policy = SCHED_OTHER;
-        c->syslog_priority = LOG_DAEMON|LOG_INFO;
-        c->syslog_level_prefix = true;
-        c->mount_flags = MS_SHARED;
-        c->kill_signal = SIGTERM;
-        c->send_sigkill = true;
-        c->control_group_persistent = -1;
-        c->ignore_sigpipe = true;
-}
-
-void exec_context_done(ExecContext *c) {
-        unsigned l;
-
-        assert(c);
-
-        strv_free(c->environment);
-        c->environment = NULL;
-
-        strv_free(c->environment_files);
-        c->environment_files = 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->tcpwrap_name);
-        c->tcpwrap_name = 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;
-
-        free(c->pam_name);
-        c->pam_name = 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;
-
-        if (c->cpuset)
-                CPU_FREE(c->cpuset);
-
-        free(c->utmp_id);
-        c->utmp_id = 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;
-        }
-}
-
-int exec_context_load_environment(const ExecContext *c, char ***l) {
-        char **i, **r = NULL;
-
-        assert(c);
-        assert(l);
-
-        STRV_FOREACH(i, c->environment_files) {
-                char *fn;
-                int k;
-                bool ignore = false;
-                char **p;
-
-                fn = *i;
-
-                if (fn[0] == '-') {
-                        ignore = true;
-                        fn ++;
-                }
-
-                if (!path_is_absolute(fn)) {
-
-                        if (ignore)
-                                continue;
-
-                        strv_free(r);
-                        return -EINVAL;
-                }
-
-                if ((k = load_env_file(fn, &p)) < 0) {
-
-                        if (ignore)
-                                continue;
-
-                        strv_free(r);
-                        return k;
-                }
-
-                if (r == NULL)
-                        r = p;
-                else {
-                        char **m;
-
-                        m = strv_env_merge(2, r, p);
-                        strv_free(r);
-                        strv_free(p);
-
-                        if (!m)
-                                return -ENOMEM;
-
-                        r = m;
-                }
-        }
-
-        *l = r;
-
-        return 0;
-}
-
-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"
-                "%sControlGroupModify: %s\n"
-                "%sControlGroupPersistent: %s\n"
-                "%sPrivateNetwork: %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),
-                prefix, yes_no(c->control_group_modify),
-                prefix, yes_no(c->control_group_persistent),
-                prefix, yes_no(c->private_network));
-
-        STRV_FOREACH(e, c->environment)
-                fprintf(f, "%sEnvironment: %s\n", prefix, *e);
-
-        STRV_FOREACH(e, c->environment_files)
-                fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
-
-        if (c->tcpwrap_name)
-                fprintf(f,
-                        "%sTCPWrapName: %s\n",
-                        prefix, c->tcpwrap_name);
-
-        if (c->nice_set)
-                fprintf(f,
-                        "%sNice: %i\n",
-                        prefix, c->nice);
-
-        if (c->oom_score_adjust_set)
-                fprintf(f,
-                        "%sOOMScoreAdjust: %i\n",
-                        prefix, c->oom_score_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->cpuset) {
-                fprintf(f, "%sCPUAffinity:", prefix);
-                for (i = 0; i < c->cpuset_ncpus; i++)
-                        if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
-                                fprintf(f, " %i", i);
-                fputs("\n", f);
-        }
-
-        if (c->timer_slack_nsec_set)
-                fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
-
-        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"
-                        "%sTTYReset: %s\n"
-                        "%sTTYVHangup: %s\n"
-                        "%sTTYVTDisallocate: %s\n",
-                        prefix, c->tty_path,
-                        prefix, yes_no(c->tty_reset),
-                        prefix, yes_no(c->tty_vhangup),
-                        prefix, yes_no(c->tty_vt_disallocate));
-
-        if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG || c->std_output == EXEC_OUTPUT_JOURNAL ||
-            c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE ||
-            c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG || c->std_error == EXEC_OUTPUT_JOURNAL ||
-            c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_JOURNAL_AND_CONSOLE)
-                fprintf(f,
-                        "%sSyslogFacility: %s\n"
-                        "%sSyslogLevel: %s\n",
-                        prefix, log_facility_unshifted_to_string(c->syslog_priority >> 3),
-                        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) {
-                unsigned long l;
-                fprintf(f, "%sCapabilityBoundingSet:", prefix);
-
-                for (l = 0; l <= cap_last_cap(); l++)
-                        if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
-                                char *t;
-
-                                if ((t = cap_to_name(l))) {
-                                        fprintf(f, " %s", t);
-                                        cap_free(t);
-                                }
-                        }
-
-                fputs("\n", f);
-        }
-
-        if (c->user)
-                fprintf(f, "%sUser: %s\n", prefix, c->user);
-        if (c->group)
-                fprintf(f, "%sGroup: %s\n", prefix, c->group);
-
-        if (strv_length(c->supplementary_groups) > 0) {
-                fprintf(f, "%sSupplementaryGroups:", prefix);
-                strv_fprintf(f, c->supplementary_groups);
-                fputs("\n", f);
-        }
-
-        if (c->pam_name)
-                fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
-
-        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);
-        }
-
-        fprintf(f,
-                "%sKillMode: %s\n"
-                "%sKillSignal: SIG%s\n"
-                "%sSendSIGKILL: %s\n"
-                "%sIgnoreSIGPIPE: %s\n",
-                prefix, kill_mode_to_string(c->kill_mode),
-                prefix, signal_to_string(c->kill_signal),
-                prefix, yes_no(c->send_sigkill),
-                prefix, yes_no(c->ignore_sigpipe));
-
-        if (c->utmp_id)
-                fprintf(f,
-                        "%sUtmpIdentifier: %s\n",
-                        prefix, c->utmp_id);
-}
-
-void exec_status_start(ExecStatus *s, pid_t pid) {
-        assert(s);
-
-        zero(*s);
-        s->pid = pid;
-        dual_timestamp_get(&s->start_timestamp);
-}
-
-void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) {
-        assert(s);
-
-        if (s->pid && s->pid != pid)
-                zero(*s);
-
-        s->pid = pid;
-        dual_timestamp_get(&s->exit_timestamp);
-
-        s->code = code;
-        s->status = status;
-
-        if (context) {
-                if (context->utmp_id)
-                        utmp_put_dead_process(context->utmp_id, pid, code, status);
-
-                exec_context_tty_reset(context);
-        }
-}
-
-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: %lu\n",
-                prefix, (unsigned long) s->pid);
-
-        if (s->start_timestamp.realtime > 0)
-                fprintf(f,
-                        "%sStart Timestamp: %s\n",
-                        prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
-
-        if (s->exit_timestamp.realtime > 0)
-                fprintf(f,
-                        "%sExit Timestamp: %s\n"
-                        "%sExit Code: %s\n"
-                        "%sExit Status: %i\n",
-                        prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime),
-                        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 kind of 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;
-}
-
-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"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
-
-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_SYSLOG_AND_CONSOLE] = "syslog+console",
-        [EXEC_OUTPUT_KMSG] = "kmsg",
-        [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
-        [EXEC_OUTPUT_JOURNAL] = "journal",
-        [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
-        [EXEC_OUTPUT_SOCKET] = "socket"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
-
-static const char* const kill_mode_table[_KILL_MODE_MAX] = {
-        [KILL_CONTROL_GROUP] = "control-group",
-        [KILL_PROCESS] = "process",
-        [KILL_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
-
-static const char* const kill_who_table[_KILL_WHO_MAX] = {
-        [KILL_MAIN] = "main",
-        [KILL_CONTROL] = "control",
-        [KILL_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/execute.h b/src/execute.h
deleted file mode 100644
index 0d7e7dd..0000000
--- a/src/execute.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 <linux/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/capability.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct CGroupBonding;
-struct CGroupAttribute;
-
-#include "list.h"
-#include "util.h"
-
-typedef enum KillMode {
-        KILL_CONTROL_GROUP = 0,
-        KILL_PROCESS,
-        KILL_NONE,
-        _KILL_MODE_MAX,
-        _KILL_MODE_INVALID = -1
-} KillMode;
-
-typedef enum KillWho {
-        KILL_MAIN,
-        KILL_CONTROL,
-        KILL_ALL,
-        _KILL_WHO_MAX,
-        _KILL_WHO_INVALID = -1
-} KillWho;
-
-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_SYSLOG_AND_CONSOLE,
-        EXEC_OUTPUT_KMSG,
-        EXEC_OUTPUT_KMSG_AND_CONSOLE,
-        EXEC_OUTPUT_JOURNAL,
-        EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
-        EXEC_OUTPUT_SOCKET,
-        _EXEC_OUTPUT_MAX,
-        _EXEC_OUTPUT_INVALID = -1
-} ExecOutput;
-
-struct ExecStatus {
-        dual_timestamp start_timestamp;
-        dual_timestamp 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 */
-        bool ignore;
-};
-
-struct ExecContext {
-        char **environment;
-        char **environment_files;
-
-        struct rlimit *rlimit[RLIMIT_NLIMITS];
-        char *working_directory, *root_directory;
-
-        mode_t umask;
-        int oom_score_adjust;
-        int nice;
-        int ioprio;
-        int cpu_sched_policy;
-        int cpu_sched_priority;
-
-        cpu_set_t *cpuset;
-        unsigned cpuset_ncpus;
-
-        ExecInput std_input;
-        ExecOutput std_output;
-        ExecOutput std_error;
-
-        unsigned long timer_slack_nsec;
-
-        char *tcpwrap_name;
-
-        char *tty_path;
-
-        bool tty_reset;
-        bool tty_vhangup;
-        bool tty_vt_disallocate;
-
-        bool ignore_sigpipe;
-
-        /* 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 *pam_name;
-
-        char *utmp_id;
-
-        char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
-        unsigned long mount_flags;
-
-        uint64_t capability_bounding_set_drop;
-
-        /* Not relevant for spawning processes, just for killing */
-        KillMode kill_mode;
-        int kill_signal;
-        bool send_sigkill;
-
-        cap_t capabilities;
-        int secure_bits;
-
-        int syslog_priority;
-        char *syslog_identifier;
-        bool syslog_level_prefix;
-
-        bool cpu_sched_reset_on_fork;
-        bool non_blocking;
-        bool private_tmp;
-        bool private_network;
-
-        bool control_group_modify;
-        int control_group_persistent;
-
-        /* 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 same_pgrp;
-
-        bool oom_score_adjust_set:1;
-        bool nice_set:1;
-        bool ioprio_set:1;
-        bool cpu_sched_set:1;
-        bool timer_slack_nsec_set:1;
-};
-
-int exec_spawn(ExecCommand *command,
-               char **argv,
-               const ExecContext *context,
-               int fds[], unsigned n_fds,
-               char **environment,
-               bool apply_permissions,
-               bool apply_chroot,
-               bool apply_tty_stdin,
-               bool confirm_spawn,
-               struct CGroupBonding *cgroup_bondings,
-               struct CGroupAttribute *cgroup_attributes,
-               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_context_tty_reset(const ExecContext *context);
-
-int exec_context_load_environment(const ExecContext *c, char ***l);
-
-void exec_status_start(ExecStatus *s, pid_t pid);
-void exec_status_exit(ExecStatus *s, ExecContext *context, 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);
-ExecOutput exec_output_from_string(const char *s);
-
-const char* exec_input_to_string(ExecInput i);
-ExecInput exec_input_from_string(const char *s);
-
-const char *kill_mode_to_string(KillMode k);
-KillMode kill_mode_from_string(const char *s);
-
-const char *kill_who_to_string(KillWho k);
-KillWho kill_who_from_string(const char *s);
-
-#endif
diff --git a/src/fdset.c b/src/fdset.c
deleted file mode 100644
index e67fe6f..0000000
--- a/src/fdset.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 */
-
-                /* When reloading duplicates of the private bus
-                 * connection fds and suchlike are closed here, which
-                 * has no effect at all, since they are only
-                 * duplicates. So don't be surprised about these log
-                 * messages. */
-
-                log_debug("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
deleted file mode 100644
index 044a9e6..0000000
--- a/src/fdset.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/ima-setup.c b/src/ima-setup.c
deleted file mode 100644
index 03e43dc..0000000
--- a/src/ima-setup.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-  Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
-                                     TORSEC group -- http://security.polito.it
-
-  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 <fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include "ima-setup.h"
-#include "mount-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-#include "label.h"
-
-#define IMA_SECFS_DIR "/sys/kernel/security/ima"
-#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
-#define IMA_POLICY_PATH "/etc/ima/ima-policy"
-
-int ima_setup(void) {
-
-#ifdef HAVE_IMA
-       struct stat st;
-       ssize_t policy_size = 0, written = 0;
-       char *policy;
-       int policyfd = -1, imafd = -1;
-       int result = 0;
-
-#ifndef HAVE_SELINUX
-       /* Mount the securityfs filesystem */
-       mount_setup_early();
-#endif
-
-       if (stat(IMA_POLICY_PATH, &st) < 0)
-               return 0;
-
-       policy_size = st.st_size;
-       if (stat(IMA_SECFS_DIR, &st) < 0) {
-               log_debug("IMA support is disabled in the kernel, ignoring.");
-               return 0;
-       }
-
-       if (stat(IMA_SECFS_POLICY, &st) < 0) {
-               log_error("Another IMA custom policy has already been loaded, "
-                         "ignoring.");
-               return 0;
-       }
-
-       policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
-       if (policyfd < 0) {
-               log_error("Failed to open the IMA custom policy file %s (%m), "
-                         "ignoring.", IMA_POLICY_PATH);
-               return 0;
-       }
-
-       imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
-       if (imafd < 0) {
-               log_error("Failed to open the IMA kernel interface %s (%m), "
-                         "ignoring.", IMA_SECFS_POLICY);
-               goto out;
-       }
-
-       policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
-       if (policy == MAP_FAILED) {
-               log_error("mmap() failed (%m), freezing");
-               result = -errno;
-               goto out;
-       }
-
-       written = loop_write(imafd, policy, (size_t)policy_size, false);
-       if (written != policy_size) {
-               log_error("Failed to load the IMA custom policy file %s (%m), "
-                         "ignoring.", IMA_POLICY_PATH);
-               goto out_mmap;
-       }
-
-       log_info("Successfully loaded the IMA custom policy %s.",
-                IMA_POLICY_PATH);
-out_mmap:
-       munmap(policy, policy_size);
-out:
-       if (policyfd >= 0)
-                close_nointr_nofail(policyfd);
-       if (imafd >= 0)
-                close_nointr_nofail(imafd);
-       if (result)
-                return result;
-#endif /* HAVE_IMA */
-
-       return 0;
-}
diff --git a/src/ima-setup.h b/src/ima-setup.h
deleted file mode 100644
index 7d677cf..0000000
--- a/src/ima-setup.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooimasetuphfoo
-#define fooimasetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-  Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
-                                     TORSEC group -- http://security.polito.it
-
-  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 ima_setup(void);
-
-#endif
diff --git a/src/initreq.h b/src/initreq.h
deleted file mode 100644
index 859042c..0000000
--- a/src/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 separate 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/job.c b/src/job.c
deleted file mode 100644
index bae6ab9..0000000
--- a/src/job.c
+++ /dev/null
@@ -1,701 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <sys/timerfd.h>
-#include <sys/epoll.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;
-
-        j->timer_watch.type = WATCH_INVALID;
-
-        /* 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->job == j) {
-                        j->unit->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);
-
-        if (j->timer_watch.type != WATCH_INVALID) {
-                assert(j->timer_watch.type == WATCH_JOB_TIMER);
-                assert(j->timer_watch.data.job == j);
-                assert(j->timer_watch.fd >= 0);
-
-                assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
-                close_nointr_nofail(j->timer_watch.fd);
-        }
-
-        free(j->bus_client);
-        free(j);
-}
-
-JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
-        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
-         * explicitly asked for) is the requester. */
-
-        if (!(l = new0(JobDependency, 1)))
-                return NULL;
-
-        l->subject = subject;
-        l->object = object;
-        l->matters = matters;
-        l->conflicts = conflicts;
-
-        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_dump(Job *j, FILE*f, const char *prefix) {
-        assert(j);
-        assert(f);
-
-        if (!prefix)
-                prefix = "";
-
-        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->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;
-}
-
-/*
- * Merging is commutative, so imagine the matrix as symmetric. We store only
- * its lower triangle to avoid duplication. We don't store the main diagonal,
- * because A merged with A is simply A.
- *
- * 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.
- */
-static const JobType job_merging_table[] = {
-/* What \ With       *  JOB_START         JOB_VERIFY_ACTIVE  JOB_STOP JOB_RELOAD   JOB_RELOAD_OR_START  JOB_RESTART JOB_TRY_RESTART */
-/************************************************************************************************************************************/
-/*JOB_START          */
-/*JOB_VERIFY_ACTIVE  */ JOB_START,
-/*JOB_STOP           */ -1,                  -1,
-/*JOB_RELOAD         */ JOB_RELOAD_OR_START, JOB_RELOAD,          -1,
-/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START,
-/*JOB_RESTART        */ JOB_RESTART,         JOB_RESTART,         -1, JOB_RESTART,         JOB_RESTART,
-/*JOB_TRY_RESTART    */ JOB_RESTART,         JOB_TRY_RESTART,     -1, JOB_TRY_RESTART,     JOB_RESTART, JOB_RESTART,
-};
-
-JobType job_type_lookup_merge(JobType a, JobType b) {
-        assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2);
-        assert(a >= 0 && a < _JOB_TYPE_MAX);
-        assert(b >= 0 && b < _JOB_TYPE_MAX);
-
-        if (a == b)
-                return a;
-
-        if (a < b) {
-                JobType tmp = a;
-                a = b;
-                b = tmp;
-        }
-
-        return job_merging_table[(a - 1) * a / 2 + b];
-}
-
-bool job_type_is_redundant(JobType a, UnitActiveState b) {
-        switch (a) {
-
-        case JOB_START:
-                return
-                        b == UNIT_ACTIVE ||
-                        b == UNIT_RELOADING;
-
-        case JOB_STOP:
-                return
-                        b == UNIT_INACTIVE ||
-                        b == UNIT_FAILED;
-
-        case JOB_VERIFY_ACTIVE:
-                return
-                        b == UNIT_ACTIVE ||
-                        b == UNIT_RELOADING;
-
-        case JOB_RELOAD:
-                return
-                        b == UNIT_RELOADING;
-
-        case JOB_RELOAD_OR_START:
-                return
-                        b == UNIT_ACTIVATING ||
-                        b == UNIT_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. */
-
-        /* First check if there is an override */
-        if (j->ignore_order)
-                return true;
-
-        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->dependencies[UNIT_AFTER], i)
-                        if (other->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->dependencies[UNIT_BEFORE], i)
-                if (other->job &&
-                    (other->job->type == JOB_STOP ||
-                     other->job->type == JOB_RESTART ||
-                     other->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;
-}
-
-static void job_change_type(Job *j, JobType newtype) {
-        log_debug("Converting job %s/%s -> %s/%s",
-                  j->unit->id, job_type_to_string(j->type),
-                  j->unit->id, job_type_to_string(newtype));
-
-        j->type = newtype;
-}
-
-int job_run_and_invalidate(Job *j) {
-        int r;
-        uint32_t id;
-        Manager *m;
-
-        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);
-
-        /* While we execute this operation the job might go away (for
-         * example: because it is replaced by a new, conflicting
-         * job.) To make sure we don't access a freed job later on we
-         * store the id here, so that we can verify the job is still
-         * valid. */
-        id = j->id;
-        m = j->manager;
-
-        switch (j->type) {
-
-                case JOB_RELOAD_OR_START:
-                        if (unit_active_state(j->unit) == UNIT_ACTIVE) {
-                                job_change_type(j, JOB_RELOAD);
-                                r = unit_reload(j->unit);
-                                break;
-                        }
-                        job_change_type(j, JOB_START);
-                        /* fall through */
-
-                case JOB_START:
-                        r = unit_start(j->unit);
-
-                        /* If this unit cannot be started, then simply wait */
-                        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_TRY_RESTART:
-                        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) {
-                                r = -ENOEXEC;
-                                break;
-                        }
-                        job_change_type(j, JOB_RESTART);
-                        /* fall through */
-
-                case JOB_STOP:
-                case JOB_RESTART:
-                        r = unit_stop(j->unit);
-
-                        /* If this unit cannot stopped, then simply wait. */
-                        if (r == -EBADR)
-                                r = 0;
-                        break;
-
-                case JOB_RELOAD:
-                        r = unit_reload(j->unit);
-                        break;
-
-                default:
-                        assert_not_reached("Unknown job type");
-        }
-
-        if ((j = manager_get_job(m, id))) {
-                if (r == -EALREADY)
-                        r = job_finish_and_invalidate(j, JOB_DONE);
-                else if (r == -ENOEXEC)
-                        r = job_finish_and_invalidate(j, JOB_SKIPPED);
-                else if (r == -EAGAIN)
-                        j->state = JOB_WAITING;
-                else if (r < 0)
-                        r = job_finish_and_invalidate(j, JOB_FAILED);
-        }
-
-        return r;
-}
-
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
-        assert(u);
-
-        if (t == JOB_START) {
-
-                switch (result) {
-
-                case JOB_DONE:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Started %s", unit_description(u));
-                        break;
-
-                case JOB_FAILED:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s", unit_description(u));
-                        unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
-                        break;
-
-                case JOB_DEPENDENCY:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s", unit_description(u));
-                        break;
-
-                case JOB_TIMEOUT:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s", unit_description(u));
-                        break;
-
-                default:
-                        ;
-                }
-
-        } else if (t == JOB_STOP) {
-
-                switch (result) {
-
-                case JOB_TIMEOUT:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s", unit_description(u));
-                        break;
-
-                case JOB_DONE:
-                case JOB_FAILED:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Stopped %s", unit_description(u));
-                        break;
-
-                default:
-                        ;
-                }
-        }
-}
-
-int job_finish_and_invalidate(Job *j, JobResult result) {
-        Unit *u;
-        Unit *other;
-        JobType t;
-        Iterator i;
-        bool recursed = false;
-
-        assert(j);
-        assert(j->installed);
-
-        job_add_to_dbus_queue(j);
-
-        /* Patch restart jobs so that they become normal start jobs */
-        if (result == JOB_DONE && j->type == JOB_RESTART) {
-
-                job_change_type(j, JOB_START);
-                j->state = JOB_WAITING;
-
-                job_add_to_run_queue(j);
-
-                u = j->unit;
-                goto finish;
-        }
-
-        j->result = result;
-
-        log_debug("Job %s/%s finished, result=%s", j->unit->id, job_type_to_string(j->type), job_result_to_string(result));
-
-        if (result == JOB_FAILED)
-                j->manager->n_failed_jobs ++;
-
-        u = j->unit;
-        t = j->type;
-        job_free(j);
-
-        job_print_status_message(u, t, result);
-
-        /* Fail depending jobs on failure */
-        if (result != JOB_DONE) {
-
-                if (t == JOB_START ||
-                    t == JOB_VERIFY_ACTIVE ||
-                    t == JOB_RELOAD_OR_START) {
-
-                        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
-                                if (other->job &&
-                                    (other->job->type == JOB_START ||
-                                     other->job->type == JOB_VERIFY_ACTIVE ||
-                                     other->job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
-                                        recursed = true;
-                                }
-
-                        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
-                                if (other->job &&
-                                    (other->job->type == JOB_START ||
-                                     other->job->type == JOB_VERIFY_ACTIVE ||
-                                     other->job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
-                                        recursed = true;
-                                }
-
-                        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
-                                if (other->job &&
-                                    !other->job->override &&
-                                    (other->job->type == JOB_START ||
-                                     other->job->type == JOB_VERIFY_ACTIVE ||
-                                     other->job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
-                                        recursed = true;
-                                }
-
-                } else if (t == JOB_STOP) {
-
-                        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
-                                if (other->job &&
-                                    (other->job->type == JOB_START ||
-                                     other->job->type == JOB_VERIFY_ACTIVE ||
-                                     other->job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
-                                        recursed = true;
-                                }
-                }
-        }
-
-        /* Trigger OnFailure dependencies that are not generated by
-         * the unit itself. We don't tread JOB_CANCELED as failure in
-         * this context. And JOB_FAILURE is already handled by the
-         * unit itself. */
-        if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
-                log_notice("Job %s/%s failed with result '%s'.",
-                           u->id,
-                           job_type_to_string(t),
-                           job_result_to_string(result));
-
-                unit_trigger_on_failure(u);
-        }
-
-finish:
-        /* Try to start the next jobs that can be started */
-        SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
-                if (other->job)
-                        job_add_to_run_queue(other->job);
-        SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
-                if (other->job)
-                        job_add_to_run_queue(other->job);
-
-        manager_check_finished(u->manager);
-
-        return recursed;
-}
-
-int job_start_timer(Job *j) {
-        struct itimerspec its;
-        struct epoll_event ev;
-        int fd, r;
-        assert(j);
-
-        if (j->unit->job_timeout <= 0 ||
-            j->timer_watch.type == WATCH_JOB_TIMER)
-                return 0;
-
-        assert(j->timer_watch.type == WATCH_INVALID);
-
-        if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        zero(its);
-        timespec_store(&its.it_value, j->unit->job_timeout);
-
-        if (timerfd_settime(fd, 0, &its, NULL) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        zero(ev);
-        ev.data.ptr = &j->timer_watch;
-        ev.events = EPOLLIN;
-
-        if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        j->timer_watch.type = WATCH_JOB_TIMER;
-        j->timer_watch.fd = fd;
-        j->timer_watch.data.job = j;
-
-        return 0;
-
-fail:
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
-
-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;
-
-        /* We don't check if anybody is subscribed here, since this
-         * job might just have been created and not yet assigned to a
-         * connection/client. */
-
-        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;
-}
-
-void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
-        assert(j);
-        assert(w == &j->timer_watch);
-
-        log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
-        job_finish_and_invalidate(j, JOB_TIMEOUT);
-}
-
-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",
-        [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
-        [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
-
-static const char* const job_result_table[_JOB_RESULT_MAX] = {
-        [JOB_DONE] = "done",
-        [JOB_CANCELED] = "canceled",
-        [JOB_TIMEOUT] = "timeout",
-        [JOB_FAILED] = "failed",
-        [JOB_DEPENDENCY] = "dependency",
-        [JOB_SKIPPED] = "skipped"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/job.h b/src/job.h
deleted file mode 100644
index 60a43e0..0000000
--- a/src/job.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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>
-#include <errno.h>
-
-typedef struct Job Job;
-typedef struct JobDependency JobDependency;
-typedef enum JobType JobType;
-typedef enum JobState JobState;
-typedef enum JobMode JobMode;
-typedef enum JobResult JobResult;
-
-#include "manager.h"
-#include "unit.h"
-#include "hashmap.h"
-#include "list.h"
-
-/* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */
-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,                /* Fail if a conflicting job is already queued */
-        JOB_REPLACE,             /* Replace an existing conflicting job */
-        JOB_ISOLATE,             /* Start a unit, and stop all others */
-        JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
-        JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
-        _JOB_MODE_MAX,
-        _JOB_MODE_INVALID = -1
-};
-
-enum JobResult {
-        JOB_DONE,
-        JOB_CANCELED,
-        JOB_TIMEOUT,
-        JOB_FAILED,
-        JOB_DEPENDENCY,
-        JOB_SKIPPED,
-        _JOB_RESULT_MAX,
-        _JOB_RESULT_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;
-        bool conflicts;
-};
-
-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;
-
-        Watch timer_watch;
-
-        /* Note that this bus object is not ref counted here. */
-        DBusConnection *bus;
-        char *bus_client;
-
-        JobResult result;
-
-        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;
-        bool ignore_order: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, bool conflicts);
-void job_dependency_free(JobDependency *l);
-
-bool job_is_anchor(Job *j);
-
-int job_merge(Job *j, Job *other);
-
-JobType job_type_lookup_merge(JobType a, JobType b);
-
-static inline int job_type_merge(JobType *a, JobType b) {
-        JobType t = job_type_lookup_merge(*a, b);
-        if (t < 0)
-                return -EEXIST;
-        *a = t;
-        return 0;
-}
-
-static inline bool job_type_is_mergeable(JobType a, JobType b) {
-        return job_type_lookup_merge(a, b) >= 0;
-}
-
-static inline bool job_type_is_conflicting(JobType a, JobType b) {
-        return !job_type_is_mergeable(a, b);
-}
-
-static inline bool job_type_is_superset(JobType a, JobType b) {
-        /* Checks whether operation a is a "superset" of b in its actions */
-        return a == job_type_lookup_merge(a, 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_start_timer(Job *j);
-void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w);
-
-int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, JobResult result);
-
-char *job_dbus_path(Job *j);
-
-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);
-
-const char* job_result_to_string(JobResult t);
-JobResult job_result_from_string(const char *s);
-
-#endif
diff --git a/src/kmod-setup.c b/src/kmod-setup.c
deleted file mode 100644
index debf871..0000000
--- a/src/kmod-setup.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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/wait.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <libkmod.h>
-
-#include "macro.h"
-#include "execute.h"
-
-#include "kmod-setup.h"
-
-static const char * const kmod_table[] = {
-        "autofs4", "/sys/class/misc/autofs",
-        "ipv6",    "/sys/module/ipv6",
-        "unix",    "/proc/net/unix"
-};
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-static void systemd_kmod_log(void *data, int priority, const char *file, int line,
-                             const char *fn, const char *format, va_list args)
-{
-        log_meta(priority, file, line, fn, format, args);
-}
-#pragma GCC diagnostic pop
-
-int kmod_setup(void) {
-        unsigned i;
-        struct kmod_ctx *ctx = NULL;
-        struct kmod_module *mod;
-        int err;
-
-        for (i = 0; i < ELEMENTSOF(kmod_table); i += 2) {
-
-                if (access(kmod_table[i+1], F_OK) >= 0)
-                        continue;
-
-                log_debug("Your kernel apparently lacks built-in %s support. Might be a good idea to compile it in. "
-                          "We'll now try to work around this by loading the module...",
-                          kmod_table[i]);
-
-                if (!ctx) {
-                        ctx = kmod_new(NULL, NULL);
-                        if (!ctx) {
-                                log_error("Failed to allocate memory for kmod");
-                                return -ENOMEM;
-                        }
-
-                        kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
-
-                        kmod_load_resources(ctx);
-                }
-
-                err = kmod_module_new_from_name(ctx, kmod_table[i], &mod);
-                if (err < 0) {
-                        log_error("Failed to load module '%s'", kmod_table[i]);
-                        continue;
-                }
-
-                err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
-                if (err == 0)
-                        log_info("Inserted module '%s'", kmod_module_get_name(mod));
-                else if (err == KMOD_PROBE_APPLY_BLACKLIST)
-                        log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
-                else
-                        log_error("Failed to insert '%s'", kmod_module_get_name(mod));
-
-                kmod_module_unref(mod);
-        }
-
-        if (ctx)
-                kmod_unref(ctx);
-
-        return 0;
-}
diff --git a/src/kmod-setup.h b/src/kmod-setup.h
deleted file mode 100644
index 496aef3..0000000
--- a/src/kmod-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fookmodsetuphfoo
-#define fookmodsetuphfoo
-
-/***
-  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 kmod_setup(void);
-
-#endif
diff --git a/src/load-dropin.c b/src/load-dropin.c
deleted file mode 100644
index d869ee0..0000000
--- a/src/load-dropin.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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, UnitDependency dependency) {
-        DIR *d;
-        struct dirent *de;
-        int r;
-
-        assert(u);
-        assert(path);
-
-        d = opendir(path);
-        if (!d) {
-
-                if (errno == ENOENT)
-                        return 0;
-
-                return -errno;
-        }
-
-        while ((de = readdir(d))) {
-                char *f;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                f = join(path, "/", de->d_name, NULL);
-                if (!f) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
-                free(f);
-
-                if (r < 0)
-                        log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
-        }
-
-        r = 0;
-
-finish:
-        closedir(d);
-        return r;
-}
-
-static int process_dir(Unit *u, const char *unit_path, const char *name, const char *suffix, UnitDependency dependency) {
-        int r;
-        char *path;
-
-        assert(u);
-        assert(unit_path);
-        assert(name);
-        assert(suffix);
-
-        path = join(unit_path, "/", name, suffix, NULL);
-        if (!path)
-                return -ENOMEM;
-
-        if (u->manager->unit_path_cache &&
-            !set_get(u->manager->unit_path_cache, path))
-                r = 0;
-        else
-                r = iterate_dir(u, path, dependency);
-        free(path);
-
-        if (r < 0)
-                return r;
-
-        if (u->instance) {
-                char *template;
-                /* Also try the template dir */
-
-                template = unit_name_template(name);
-                if (!template)
-                        return -ENOMEM;
-
-                path = join(unit_path, "/", template, suffix, NULL);
-                free(template);
-
-                if (!path)
-                        return -ENOMEM;
-
-                if (u->manager->unit_path_cache &&
-                    !set_get(u->manager->unit_path_cache, path))
-                        r = 0;
-                else
-                        r = iterate_dir(u, path, dependency);
-                free(path);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int unit_load_dropin(Unit *u) {
-        Iterator i;
-        char *t;
-
-        assert(u);
-
-        /* Load dependencies from supplementary drop-in directories */
-
-        SET_FOREACH(t, u->names, i) {
-                char **p;
-
-                STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
-                        int r;
-
-                        r = process_dir(u, *p, t, ".wants", UNIT_WANTS);
-                        if (r < 0)
-                                return r;
-
-                        r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        return 0;
-}
diff --git a/src/load-dropin.h b/src/load-dropin.h
deleted file mode 100644
index cf3a799..0000000
--- a/src/load-dropin.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index 637c82b..0000000
--- a/src/load-fragment.c
+++ /dev/null
@@ -1,2445 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.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"
-#include "bus-errors.h"
-#include "utf8.h"
-
-#ifndef HAVE_SYSV_COMPAT
-int config_parse_warn_compat(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
-        return 0;
-}
-#endif
-
-int config_parse_unit_deps(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        UnitDependency d = ltype;
-        Unit *u = userdata;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char *t, *k;
-                int r;
-
-                t = strndup(w, l);
-                if (!t)
-                        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);
-                if (r < 0)
-                        log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
-
-                free(k);
-        }
-
-        return 0;
-}
-
-int config_parse_unit_names(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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_QUOTED(w, l, rvalue, state) {
-                char *t, *k;
-                int r;
-
-                t = strndup(w, l);
-                if (!t)
-                        return -ENOMEM;
-
-                k = unit_name_printf(u, t);
-                free(t);
-                if (!k)
-                        return -ENOMEM;
-
-                r = unit_merge_by_name(u, k);
-                if (r < 0)
-                        log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
-
-                free(k);
-        }
-
-        return 0;
-}
-
-int config_parse_unit_string_printf(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *k;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(u);
-
-        k = unit_full_printf(u, rvalue);
-        if (!k)
-                return -ENOMEM;
-
-        r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
-        free (k);
-
-        return r;
-}
-
-int config_parse_unit_strv_printf(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *k;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(u);
-
-        k = unit_full_printf(u, rvalue);
-        if (!k)
-                return -ENOMEM;
-
-        r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
-        free(k);
-
-        return r;
-}
-
-int config_parse_unit_path_printf(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *k;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(u);
-
-        k = unit_full_printf(u, rvalue);
-        if (!k)
-                return -ENOMEM;
-
-        r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
-        free(k);
-
-        return r;
-}
-
-int config_parse_socket_listen(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        SocketPort *p, *tail;
-        Socket *s;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        s = SOCKET(data);
-
-        p = new0(SocketPort, 1);
-        if (!p)
-                return -ENOMEM;
-
-        if (streq(lvalue, "ListenFIFO")) {
-                p->type = SOCKET_FIFO;
-
-                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
-                        free(p);
-                        return -ENOMEM;
-                }
-
-                path_kill_slashes(p->path);
-
-        } else if (streq(lvalue, "ListenSpecial")) {
-                p->type = SOCKET_SPECIAL;
-
-                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
-                        free(p);
-                        return -ENOMEM;
-                }
-
-                path_kill_slashes(p->path);
-
-        } else if (streq(lvalue, "ListenMessageQueue")) {
-
-                p->type = SOCKET_MQUEUE;
-
-                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
-                        free(p);
-                        return -ENOMEM;
-                }
-
-                path_kill_slashes(p->path);
-
-        } else if (streq(lvalue, "ListenNetlink")) {
-                char  *k;
-                int r;
-
-                p->type = SOCKET_SOCKET;
-                k = unit_full_printf(UNIT(s), rvalue);
-                r = socket_address_parse_netlink(&p->address, k);
-                free(k);
-
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
-                        free(p);
-                        return 0;
-                }
-
-        } else {
-                char *k;
-                int r;
-
-                p->type = SOCKET_SOCKET;
-                k = unit_full_printf(UNIT(s), rvalue);
-                r = socket_address_parse(&p->address, k);
-                free(k);
-
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
-                        free(p);
-                        return 0;
-                }
-
-                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) {
-                        log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
-                        free(p);
-                        return 0;
-                }
-        }
-
-        p->fd = -1;
-
-        if (s->ports) {
-                LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
-                LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
-        } else
-                LIST_PREPEND(SocketPort, port, s->ports, p);
-
-        return 0;
-}
-
-int config_parse_socket_bind(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Socket *s;
-        SocketAddressBindIPv6Only b;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        s = SOCKET(data);
-
-        if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
-                int r;
-
-                if ((r = parse_boolean(rvalue)) < 0) {
-                        log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-
-                s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
-        } else
-                s->bind_ipv6_only = b;
-
-        return 0;
-}
-
-int config_parse_exec_nice(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int priority;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atoi(rvalue, &priority) < 0) {
-                log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
-                return 0;
-        }
-
-        if (priority < PRIO_MIN || priority >= PRIO_MAX) {
-                log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->nice = priority;
-        c->nice_set = true;
-
-        return 0;
-}
-
-int config_parse_exec_oom_score_adjust(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        int oa;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atoi(rvalue, &oa) < 0) {
-                log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
-                log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->oom_score_adjust = oa;
-        c->oom_score_adjust_set = true;
-
-        return 0;
-}
-
-int config_parse_exec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecCommand **e = data, *nce;
-        char *path, **n;
-        unsigned k;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(e);
-
-        /* We accept an absolute path as first argument, or
-         * alternatively an absolute prefixed with @ to allow
-         * overriding of argv[0]. */
-
-        e += ltype;
-
-        for (;;) {
-                char *w;
-                size_t l;
-                char *state;
-                bool honour_argv0 = false, ignore = false;
-
-                path = NULL;
-                nce = NULL;
-                n = NULL;
-
-                rvalue += strspn(rvalue, WHITESPACE);
-
-                if (rvalue[0] == 0)
-                        break;
-
-                if (rvalue[0] == '-') {
-                        ignore = true;
-                        rvalue ++;
-                }
-
-                if (rvalue[0] == '@') {
-                        honour_argv0 = true;
-                        rvalue ++;
-                }
-
-                if (*rvalue != '/') {
-                        log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-
-                k = 0;
-                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                        if (strncmp(w, ";", MAX(l, 1U)) == 0)
-                                break;
-
-                        k++;
-                }
-
-                n = new(char*, k + !honour_argv0);
-                if (!n)
-                        return -ENOMEM;
-
-                k = 0;
-                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                        if (strncmp(w, ";", MAX(l, 1U)) == 0)
-                                break;
-
-                        if (honour_argv0 && w == rvalue) {
-                                assert(!path);
-
-                                path = strndup(w, l);
-                                if (!path) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                if (!utf8_is_valid(path)) {
-                                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
-                                        r = 0;
-                                        goto fail;
-                                }
-
-                        } else {
-                                char *c;
-
-                                c = n[k++] = cunescape_length(w, l);
-                                if (!c) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                if (!utf8_is_valid(c)) {
-                                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
-                                        r = 0;
-                                        goto fail;
-                                }
-                        }
-                }
-
-                n[k] = NULL;
-
-                if (!n[0]) {
-                        log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
-                        r = 0;
-                        goto fail;
-                }
-
-                if (!path) {
-                        path = strdup(n[0]);
-                        if (!path) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-                }
-
-                assert(path_is_absolute(path));
-
-                nce = new0(ExecCommand, 1);
-                if (!nce) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                nce->argv = n;
-                nce->path = path;
-                nce->ignore = ignore;
-
-                path_kill_slashes(nce->path);
-
-                exec_command_append_list(e, nce);
-
-                rvalue = state;
-        }
-
-        return 0;
-
-fail:
-        n[k] = NULL;
-        strv_free(n);
-        free(path);
-        free(nce);
-
-        return r;
-}
-
-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");
-
-int config_parse_socket_bindtodevice(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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");
-
-int config_parse_facility(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-
-        int *o = data, x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((x = log_facility_unshifted_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        *o = (x << 3) | LOG_PRI(*o);
-
-        return 0;
-}
-
-int config_parse_level(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        *o = (*o & LOG_FACMASK) | x;
-        return 0;
-}
-
-int config_parse_exec_io_class(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
-        c->ioprio_set = true;
-
-        return 0;
-}
-
-int config_parse_exec_io_priority(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
-        c->ioprio_set = true;
-
-        return 0;
-}
-
-int config_parse_exec_cpu_sched_policy(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->cpu_sched_policy = x;
-        c->cpu_sched_set = true;
-
-        return 0;
-}
-
-int config_parse_exec_cpu_sched_prio(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->cpu_sched_priority = i;
-        c->cpu_sched_set = true;
-
-        return 0;
-}
-
-int config_parse_exec_cpu_affinity(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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_QUOTED(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 (!(c->cpuset))
-                        if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
-                                return -ENOMEM;
-
-                if (r < 0 || cpu >= c->cpuset_ncpus) {
-                        log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-
-                CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
-        }
-
-        return 0;
-}
-
-int config_parse_exec_capabilities(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (c->capabilities)
-                cap_free(c->capabilities);
-        c->capabilities = cap;
-
-        return 0;
-}
-
-int config_parse_exec_secure_bits(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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_QUOTED(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, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-        }
-
-        return 0;
-}
-
-int config_parse_exec_bounding_set(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        char *w;
-        size_t l;
-        char *state;
-        bool invert = false;
-        uint64_t sum = 0;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (rvalue[0] == '~') {
-                invert = true;
-                rvalue++;
-        }
-
-        /* Note that we store this inverted internally, since the
-         * kernel wants it like this. But we actually expose it
-         * non-inverted everywhere to have a fully normalized
-         * interface. */
-
-        FOREACH_WORD_QUOTED(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, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-
-                sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
-        }
-
-        if (invert)
-                c->capability_bounding_set_drop |= sum;
-        else
-                c->capability_bounding_set_drop |= ~sum;
-
-        return 0;
-}
-
-int config_parse_exec_timer_slack_nsec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ExecContext *c = data;
-        unsigned long u;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atolu(rvalue, &u) < 0) {
-                log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c->timer_slack_nsec = u;
-
-        return 0;
-}
-
-int config_parse_limit(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        struct rlimit **rl = data;
-        unsigned long long u;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        rl += ltype;
-
-        if (streq(rvalue, "infinity"))
-                u = (unsigned long long) RLIM_INFINITY;
-        else if (safe_atollu(rvalue, &u) < 0) {
-                log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (!*rl)
-                if (!(*rl = new(struct rlimit, 1)))
-                        return -ENOMEM;
-
-        (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
-        return 0;
-}
-
-int config_parse_unit_cgroup(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = userdata;
-        char *w;
-        size_t l;
-        char *state;
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char *t, *k;
-                int r;
-
-                t = strndup(w, l);
-                if (!t)
-                        return -ENOMEM;
-
-                k = unit_full_printf(u, t);
-                free(t);
-
-                if (!k)
-                        return -ENOMEM;
-
-                t = cunescape(k);
-                free(k);
-
-                if (!t)
-                        return -ENOMEM;
-
-                r = unit_add_cgroup_from_text(u, t);
-                free(t);
-
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-        }
-
-        return 0;
-}
-
-#ifdef HAVE_SYSV_COMPAT
-int config_parse_sysv_priority(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *priority = data;
-        int i;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atoi(rvalue, &i) < 0 || i < 0) {
-                log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        *priority = (int) i;
-        return 0;
-}
-#endif
-
-int config_parse_fsck_passno(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *passno = data;
-        int i;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atoi(rvalue, &i) || i < 0) {
-                log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        *passno = (int) i;
-        return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
-
-int config_parse_kill_signal(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *sig = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(sig);
-
-        if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
-                log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        *sig = r;
-        return 0;
-}
-
-int config_parse_exec_mount_flags(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                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_QUOTED(w, l, rvalue, state) {
-                if (strncmp(w, "shared", MAX(l, 6U)) == 0)
-                        flags |= MS_SHARED;
-                else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
-                        flags |= MS_SLAVE;
-                else if (strncmp(w, "private", MAX(l, 7U)) == 0)
-                        flags |= MS_PRIVATE;
-                else {
-                        log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-        }
-
-        c->mount_flags = flags;
-        return 0;
-}
-
-int config_parse_timer(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Timer *t = data;
-        usec_t u;
-        TimerValue *v;
-        TimerBase b;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((b = timer_base_from_string(lvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
-                return 0;
-        }
-
-        if (parse_usec(rvalue, &u) < 0) {
-                log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (!(v = new0(TimerValue, 1)))
-                return -ENOMEM;
-
-        v->base = b;
-        v->value = u;
-
-        LIST_PREPEND(TimerValue, value, t->values, v);
-
-        return 0;
-}
-
-int config_parse_timer_unit(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Timer *t = data;
-        int r;
-        DBusError error;
-        Unit *u;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        dbus_error_init(&error);
-
-        if (endswith(rvalue, ".timer")) {
-                log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
-        if (r < 0) {
-                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
-                dbus_error_free(&error);
-                return 0;
-        }
-
-        unit_ref_set(&t->unit, u);
-
-        return 0;
-}
-
-int config_parse_path_spec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Path *p = data;
-        PathSpec *s;
-        PathType b;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((b = path_type_from_string(lvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
-                return 0;
-        }
-
-        if (!path_is_absolute(rvalue)) {
-                log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (!(s = new0(PathSpec, 1)))
-                return -ENOMEM;
-
-        if (!(s->path = strdup(rvalue))) {
-                free(s);
-                return -ENOMEM;
-        }
-
-        path_kill_slashes(s->path);
-
-        s->type = b;
-        s->inotify_fd = -1;
-
-        LIST_PREPEND(PathSpec, spec, p->specs, s);
-
-        return 0;
-}
-
-int config_parse_path_unit(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Path *t = data;
-        int r;
-        DBusError error;
-        Unit *u;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        dbus_error_init(&error);
-
-        if (endswith(rvalue, ".path")) {
-                log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
-                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
-                dbus_error_free(&error);
-                return 0;
-        }
-
-        unit_ref_set(&t->unit, u);
-
-        return 0;
-}
-
-int config_parse_socket_service(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Socket *s = data;
-        int r;
-        DBusError error;
-        Unit *x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        dbus_error_init(&error);
-
-        if (!endswith(rvalue, ".service")) {
-                log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
-        if (r < 0) {
-                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
-                dbus_error_free(&error);
-                return 0;
-        }
-
-        unit_ref_set(&s->service, x);
-
-        return 0;
-}
-
-int config_parse_service_sockets(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Service *s = data;
-        int r;
-        char *state, *w;
-        size_t l;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char *t, *k;
-
-                t = strndup(w, l);
-                if (!t)
-                        return -ENOMEM;
-
-                k = unit_name_printf(UNIT(s), t);
-                free(t);
-
-                if (!k)
-                        return -ENOMEM;
-
-                if (!endswith(k, ".socket")) {
-                        log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
-                        free(k);
-                        continue;
-                }
-
-                r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
-                if (r < 0)
-                        log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
-
-                r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
-                if (r < 0)
-                        return r;
-
-                free(k);
-        }
-
-        return 0;
-}
-
-int config_parse_unit_env_file(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char ***env = data, **k;
-        Unit *u = userdata;
-        char *s;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        s = unit_full_printf(u, rvalue);
-        if (!s)
-                return -ENOMEM;
-
-        if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
-                log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
-                free(s);
-                return 0;
-        }
-
-        k = strv_append(*env, s);
-        free(s);
-        if (!k)
-                return -ENOMEM;
-
-        strv_free(*env);
-        *env = k;
-
-        return 0;
-}
-
-int config_parse_ip_tos(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *ip_tos = data, x;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((x = ip_tos_from_string(rvalue)) < 0)
-                if (safe_atoi(rvalue, &x) < 0) {
-                        log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
-                        return 0;
-                }
-
-        *ip_tos = x;
-        return 0;
-}
-
-int config_parse_unit_condition_path(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ConditionType cond = ltype;
-        Unit *u = data;
-        bool trigger, negate;
-        Condition *c;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        trigger = rvalue[0] == '|';
-        if (trigger)
-                rvalue++;
-
-        negate = rvalue[0] == '!';
-        if (negate)
-                rvalue++;
-
-        if (!path_is_absolute(rvalue)) {
-                log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        c = condition_new(cond, rvalue, trigger, negate);
-        if (!c)
-                return -ENOMEM;
-
-        LIST_PREPEND(Condition, conditions, u->conditions, c);
-        return 0;
-}
-
-int config_parse_unit_condition_string(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        ConditionType cond = ltype;
-        Unit *u = data;
-        bool trigger, negate;
-        Condition *c;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((trigger = rvalue[0] == '|'))
-                rvalue++;
-
-        if ((negate = rvalue[0] == '!'))
-                rvalue++;
-
-        if (!(c = condition_new(cond, rvalue, trigger, negate)))
-                return -ENOMEM;
-
-        LIST_PREPEND(Condition, conditions, u->conditions, c);
-        return 0;
-}
-
-int config_parse_unit_condition_null(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = data;
-        Condition *c;
-        bool trigger, negate;
-        int b;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((trigger = rvalue[0] == '|'))
-                rvalue++;
-
-        if ((negate = rvalue[0] == '!'))
-                rvalue++;
-
-        if ((b = parse_boolean(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (!b)
-                negate = !negate;
-
-        if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
-                return -ENOMEM;
-
-        LIST_PREPEND(Condition, conditions, u->conditions, c);
-        return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
-
-int config_parse_unit_cgroup_attr(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Unit *u = data;
-        char **l;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        l = strv_split_quoted(rvalue);
-        if (!l)
-                return -ENOMEM;
-
-        if (strv_length(l) != 2) {
-                log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
-        strv_free(l);
-
-        if (r < 0) {
-                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
-        Unit *u = data;
-        int r;
-        unsigned long ul;
-        char *t;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
-                log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (asprintf(&t, "%lu", ul) < 0)
-                return -ENOMEM;
-
-        r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
-        free(t);
-
-        if (r < 0) {
-                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
-        Unit *u = data;
-        int r;
-        off_t sz;
-        char *t;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
-                log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
-                return -ENOMEM;
-
-        r = unit_add_cgroup_attribute(u,
-                                      "memory",
-                                      streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
-                                      t, NULL);
-        free(t);
-
-        if (r < 0) {
-                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-static int device_map(const char *controller, const char *name, const char *value, char **ret) {
-        char **l;
-
-        assert(controller);
-        assert(name);
-        assert(value);
-        assert(ret);
-
-        l = strv_split_quoted(value);
-        if (!l)
-                return -ENOMEM;
-
-        assert(strv_length(l) >= 1);
-
-        if (streq(l[0], "*")) {
-
-                if (asprintf(ret, "a *:*%s%s",
-                             isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
-                        strv_free(l);
-                        return -ENOMEM;
-                }
-
-        } else {
-                struct stat st;
-
-                if (stat(l[0], &st) < 0) {
-                        log_warning("Couldn't stat device %s", l[0]);
-                        strv_free(l);
-                        return -errno;
-                }
-
-                if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
-                        log_warning("%s is not a device.", l[0]);
-                        strv_free(l);
-                        return -ENODEV;
-                }
-
-                if (asprintf(ret, "%c %u:%u%s%s",
-                             S_ISCHR(st.st_mode) ? 'c' : 'b',
-                             major(st.st_rdev), minor(st.st_rdev),
-                             isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
-
-                        strv_free(l);
-                        return -ENOMEM;
-                }
-        }
-
-        strv_free(l);
-        return 0;
-}
-
-int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
-        Unit *u = data;
-        char **l;
-        int r;
-        unsigned k;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        l = strv_split_quoted(rvalue);
-        if (!l)
-                return -ENOMEM;
-
-        k = strv_length(l);
-        if (k < 1 || k > 2) {
-                log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
-                log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
-                log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-        strv_free(l);
-
-        r = unit_add_cgroup_attribute(u, "devices",
-                                      streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
-                                      rvalue, device_map);
-
-        if (r < 0) {
-                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
-        struct stat st;
-        char **l;
-        dev_t d;
-
-        assert(controller);
-        assert(name);
-        assert(value);
-        assert(ret);
-
-        l = strv_split_quoted(value);
-        if (!l)
-                return -ENOMEM;
-
-        assert(strv_length(l) == 2);
-
-        if (stat(l[0], &st) < 0) {
-                log_warning("Couldn't stat device %s", l[0]);
-                strv_free(l);
-                return -errno;
-        }
-
-        if (S_ISBLK(st.st_mode))
-                d = st.st_rdev;
-        else if (major(st.st_dev) != 0) {
-                /* If this is not a device node then find the block
-                 * device this file is stored on */
-                d = st.st_dev;
-
-                /* If this is a partition, try to get the originating
-                 * block device */
-                block_get_whole_disk(d, &d);
-        } else {
-                log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
-                strv_free(l);
-                return -ENODEV;
-        }
-
-        if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
-                strv_free(l);
-                return -ENOMEM;
-        }
-
-        strv_free(l);
-        return 0;
-}
-
-int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
-        Unit *u = data;
-        int r;
-        unsigned long ul;
-        const char *device = NULL, *weight;
-        unsigned k;
-        char *t, **l;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        l = strv_split_quoted(rvalue);
-        if (!l)
-                return -ENOMEM;
-
-        k = strv_length(l);
-        if (k < 1 || k > 2) {
-                log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (k == 1)
-                weight = l[0];
-        else {
-                device = l[0];
-                weight = l[1];
-        }
-
-        if (device && !path_is_absolute(device)) {
-                log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
-                log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (device)
-                r = asprintf(&t, "%s %lu", device, ul);
-        else
-                r = asprintf(&t, "%lu", ul);
-        strv_free(l);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        if (device)
-                r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
-        else
-                r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
-        free(t);
-
-        if (r < 0) {
-                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
-        Unit *u = data;
-        int r;
-        off_t bytes;
-        unsigned k;
-        char *t, **l;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        l = strv_split_quoted(rvalue);
-        if (!l)
-                return -ENOMEM;
-
-        k = strv_length(l);
-        if (k != 2) {
-                log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (!path_is_absolute(l[0])) {
-                log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
-                log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
-                strv_free(l);
-                return 0;
-        }
-
-        r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
-        strv_free(l);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        r = unit_add_cgroup_attribute(u, "blkio",
-                                      streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
-                                      t, blkio_map);
-        free(t);
-
-        if (r < 0) {
-                log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        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, *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, but only if it is a valid
-                 * unit name. */
-                name = file_name_from_path(*filename);
-
-                if (unit_name_is_valid(name, true)) {
-
-                        id = set_get(names, name);
-                        if (!id) {
-                                id = strdup(name);
-                                if (!id)
-                                        return -ENOMEM;
-
-                                r = set_put(names, id);
-                                if (r < 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_and_make_absolute(*filename, &target)) < 0)
-                        return r;
-
-                free(*filename);
-                *filename = target;
-        }
-
-        if (!(f = fdopen(fd, "re"))) {
-                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)->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 int load_from_path(Unit *u, const char *path) {
-        int r;
-        Set *symlink_names;
-        FILE *f = NULL;
-        char *filename = NULL, *id = NULL;
-        Unit *merged;
-        struct stat st;
-
-        assert(u);
-        assert(path);
-
-        symlink_names = set_new(string_hash_func, string_compare_func);
-        if (!symlink_names)
-                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->manager->lookup_paths.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 (u->manager->unit_path_cache &&
-                            !set_get(u->manager->unit_path_cache, filename))
-                                r = -ENOENT;
-                        else
-                                r = open_follow(&filename, &f, symlink_names, &id);
-
-                        if (r < 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) {
-                /* Hmm, no suitable file found? */
-                r = 0;
-                goto finish;
-        }
-
-        merged = u;
-        if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
-                goto finish;
-
-        if (merged != u) {
-                u->load_state = UNIT_MERGED;
-                r = 0;
-                goto finish;
-        }
-
-        zero(st);
-        if (fstat(fileno(f), &st) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (null_or_empty(&st))
-                u->load_state = UNIT_MASKED;
-        else {
-                /* Now, parse the file contents */
-                r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
-                if (r < 0)
-                        goto finish;
-
-                u->load_state = UNIT_LOADED;
-        }
-
-        free(u->fragment_path);
-        u->fragment_path = filename;
-        filename = NULL;
-
-        u->fragment_mtime = timespec_load(&st.st_mtim);
-
-        r = 0;
-
-finish:
-        set_free_free(symlink_names);
-        free(filename);
-
-        if (f)
-                fclose(f);
-
-        return r;
-}
-
-int unit_load_fragment(Unit *u) {
-        int r;
-        Iterator i;
-        const char *t;
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-        assert(u->id);
-
-        /* First, try to find the unit under its id. We always look
-         * for unit files in the default directories, to make it easy
-         * to override things by placing things in /etc/systemd/system */
-        if ((r = load_from_path(u, u->id)) < 0)
-                return r;
-
-        /* Try to find an alias we can load this with */
-        if (u->load_state == UNIT_STUB)
-                SET_FOREACH(t, u->names, i) {
-
-                        if (t == u->id)
-                                continue;
-
-                        if ((r = load_from_path(u, t)) < 0)
-                                return r;
-
-                        if (u->load_state != UNIT_STUB)
-                                break;
-                }
-
-        /* And now, try looking for it under the suggested (originally linked) path */
-        if (u->load_state == UNIT_STUB && u->fragment_path) {
-
-                if ((r = load_from_path(u, u->fragment_path)) < 0)
-                        return r;
-
-                if (u->load_state == UNIT_STUB) {
-                        /* Hmm, this didn't work? Then let's get rid
-                         * of the fragment path stored for us, so that
-                         * we don't point to an invalid location. */
-                        free(u->fragment_path);
-                        u->fragment_path = NULL;
-                }
-        }
-
-        /* Look for a template */
-        if (u->load_state == UNIT_STUB && u->instance) {
-                char *k;
-
-                if (!(k = unit_name_template(u->id)))
-                        return -ENOMEM;
-
-                r = load_from_path(u, k);
-                free(k);
-
-                if (r < 0)
-                        return r;
-
-                if (u->load_state == UNIT_STUB)
-                        SET_FOREACH(t, u->names, i) {
-
-                                if (t == u->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->load_state != UNIT_STUB)
-                                        break;
-                        }
-        }
-
-        return 0;
-}
-
-void unit_dump_config_items(FILE *f) {
-        static const struct {
-                const ConfigParserCallback callback;
-                const char *rvalue;
-        } table[] = {
-                { config_parse_int,                   "INTEGER" },
-                { config_parse_unsigned,              "UNSIGNED" },
-                { config_parse_bytes_size,            "SIZE" },
-                { config_parse_bool,                  "BOOLEAN" },
-                { config_parse_string,                "STRING" },
-                { config_parse_path,                  "PATH" },
-                { config_parse_unit_path_printf,      "PATH" },
-                { config_parse_strv,                  "STRING [...]" },
-                { config_parse_exec_nice,             "NICE" },
-                { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
-                { config_parse_exec_io_class,         "IOCLASS" },
-                { config_parse_exec_io_priority,      "IOPRIORITY" },
-                { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
-                { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
-                { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
-                { config_parse_mode,                  "MODE" },
-                { config_parse_unit_env_file,         "FILE" },
-                { config_parse_output,                "OUTPUT" },
-                { config_parse_input,                 "INPUT" },
-                { config_parse_facility,              "FACILITY" },
-                { config_parse_level,                 "LEVEL" },
-                { config_parse_exec_capabilities,     "CAPABILITIES" },
-                { config_parse_exec_secure_bits,      "SECUREBITS" },
-                { config_parse_exec_bounding_set,     "BOUNDINGSET" },
-                { config_parse_exec_timer_slack_nsec, "TIMERSLACK" },
-                { config_parse_limit,                 "LIMIT" },
-                { config_parse_unit_cgroup,           "CGROUP [...]" },
-                { config_parse_unit_deps,             "UNIT [...]" },
-                { config_parse_unit_names,            "UNIT [...]" },
-                { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
-                { config_parse_service_type,          "SERVICETYPE" },
-                { config_parse_service_restart,       "SERVICERESTART" },
-#ifdef HAVE_SYSV_COMPAT
-                { config_parse_sysv_priority,         "SYSVPRIORITY" },
-#else
-                { config_parse_warn_compat,           "NOTSUPPORTED" },
-#endif
-                { config_parse_kill_mode,             "KILLMODE" },
-                { config_parse_kill_signal,           "SIGNAL" },
-                { config_parse_socket_listen,         "SOCKET [...]" },
-                { config_parse_socket_bind,           "SOCKETBIND" },
-                { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
-                { config_parse_usec,                  "SECONDS" },
-                { config_parse_path_strv,             "PATH [...]" },
-                { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
-                { config_parse_unit_string_printf,    "STRING" },
-                { config_parse_timer,                 "TIMER" },
-                { config_parse_timer_unit,            "NAME" },
-                { config_parse_path_spec,             "PATH" },
-                { config_parse_path_unit,             "UNIT" },
-                { config_parse_notify_access,         "ACCESS" },
-                { config_parse_ip_tos,                "TOS" },
-                { config_parse_unit_condition_path,   "CONDITION" },
-                { config_parse_unit_condition_string, "CONDITION" },
-                { config_parse_unit_condition_null,   "CONDITION" },
-        };
-
-        const char *prev = NULL;
-        const char *i;
-
-        assert(f);
-
-        NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
-                const char *rvalue = "OTHER", *lvalue;
-                unsigned j;
-                size_t prefix_len;
-                const char *dot;
-                const ConfigPerfItem *p;
-
-                assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
-
-                dot = strchr(i, '.');
-                lvalue = dot ? dot + 1 : i;
-                prefix_len = dot-i;
-
-                if (dot)
-                        if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
-                                if (prev)
-                                        fputc('\n', f);
-
-                                fprintf(f, "[%.*s]\n", (int) prefix_len, i);
-                        }
-
-                for (j = 0; j < ELEMENTSOF(table); j++)
-                        if (p->parse == table[j].callback) {
-                                rvalue = table[j].rvalue;
-                                break;
-                        }
-
-                fprintf(f, "%s=%s\n", lvalue, rvalue);
-                prev = i;
-        }
-}
diff --git a/src/load-fragment.h b/src/load-fragment.h
deleted file mode 100644
index 79fc76d..0000000
--- a/src/load-fragment.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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);
-
-int config_parse_warn_compat(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_deps(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_names(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_listen(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_bind(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_oom_score_adjust(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_restart(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_bindtodevice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_output(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_input(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_io_class(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_io_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_cpu_sched_policy(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_cpu_sched_prio(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_timer_slack_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_sysv_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_fsck_passno(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_kill_signal(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_mount_flags(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_timer(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_timer_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_path_spec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_path_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_service(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_sockets(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_env_file(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_ip_tos(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_condition_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_condition_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_notify_access(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_start_limit_action(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-
-/* gperf prototypes */
-const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
-extern const char load_fragment_gperf_nulstr[];
-
-#endif
diff --git a/src/locale-setup.c b/src/locale-setup.c
deleted file mode 100644
index 7f692e9..0000000
--- a/src/locale-setup.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <stdlib.h>
-#include <errno.h>
-
-#include "locale-setup.h"
-#include "util.h"
-#include "macro.h"
-#include "virt.h"
-
-enum {
-        /* We don't list LC_ALL here on purpose. People should be
-         * using LANG instead. */
-
-        VARIABLE_LANG,
-        VARIABLE_LANGUAGE,
-        VARIABLE_LC_CTYPE,
-        VARIABLE_LC_NUMERIC,
-        VARIABLE_LC_TIME,
-        VARIABLE_LC_COLLATE,
-        VARIABLE_LC_MONETARY,
-        VARIABLE_LC_MESSAGES,
-        VARIABLE_LC_PAPER,
-        VARIABLE_LC_NAME,
-        VARIABLE_LC_ADDRESS,
-        VARIABLE_LC_TELEPHONE,
-        VARIABLE_LC_MEASUREMENT,
-        VARIABLE_LC_IDENTIFICATION,
-        _VARIABLE_MAX
-};
-
-static const char * const variable_names[_VARIABLE_MAX] = {
-        [VARIABLE_LANG] = "LANG",
-        [VARIABLE_LANGUAGE] = "LANGUAGE",
-        [VARIABLE_LC_CTYPE] = "LC_CTYPE",
-        [VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
-        [VARIABLE_LC_TIME] = "LC_TIME",
-        [VARIABLE_LC_COLLATE] = "LC_COLLATE",
-        [VARIABLE_LC_MONETARY] = "LC_MONETARY",
-        [VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
-        [VARIABLE_LC_PAPER] = "LC_PAPER",
-        [VARIABLE_LC_NAME] = "LC_NAME",
-        [VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
-        [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
-        [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
-        [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
-};
-
-int locale_setup(void) {
-        char *variables[_VARIABLE_MAX];
-        int r = 0, i;
-
-        zero(variables);
-
-        if (detect_container(NULL) <= 0)
-                if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
-#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
-                                        "LANG",                     &variables[VARIABLE_LANG],
-#endif
-                                        "locale.LANG",              &variables[VARIABLE_LANG],
-                                        "locale.LANGUAGE",          &variables[VARIABLE_LANGUAGE],
-                                        "locale.LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
-                                        "locale.LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
-                                        "locale.LC_TIME",           &variables[VARIABLE_LC_TIME],
-                                        "locale.LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
-                                        "locale.LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
-                                        "locale.LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
-                                        "locale.LC_PAPER",          &variables[VARIABLE_LC_PAPER],
-                                        "locale.LC_NAME",           &variables[VARIABLE_LC_NAME],
-                                        "locale.LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
-                                        "locale.LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
-                                        "locale.LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
-                                        "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
-                                        NULL)) < 0) {
-
-                        if (r != -ENOENT)
-                                log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
-                }
-
-        /* Hmm, nothing set on the kernel cmd line? Then let's
-         * try /etc/locale.conf */
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/locale.conf", NEWLINE,
-                               "LANG",              &variables[VARIABLE_LANG],
-                               "LANGUAGE",          &variables[VARIABLE_LANGUAGE],
-                               "LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
-                               "LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
-                               "LC_TIME",           &variables[VARIABLE_LC_TIME],
-                               "LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
-                               "LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
-                               "LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
-                               "LC_PAPER",          &variables[VARIABLE_LC_PAPER],
-                               "LC_NAME",           &variables[VARIABLE_LC_NAME],
-                               "LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
-                               "LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
-                               "LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
-                               "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/locale.conf: %s", strerror(-r));
-        }
-
-#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MEEGO)
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
-                                "LANG", &variables[VARIABLE_LANG],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
-        }
-
-#elif defined(TARGET_SUSE)
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/sysconfig/language", NEWLINE,
-                                "RC_LANG", &variables[VARIABLE_LANG],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/sysconfig/language: %s", strerror(-r));
-        }
-
-#elif defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/default/locale", NEWLINE,
-                                "LANG",              &variables[VARIABLE_LANG],
-                                "LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
-                                "LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
-                                "LC_TIME",           &variables[VARIABLE_LC_TIME],
-                                "LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
-                                "LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
-                                "LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
-                                "LC_PAPER",          &variables[VARIABLE_LC_PAPER],
-                                "LC_NAME",           &variables[VARIABLE_LC_NAME],
-                                "LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
-                                "LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
-                                "LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
-                                "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/default/locale: %s", strerror(-r));
-        }
-
-#elif defined(TARGET_ARCH)
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/rc.conf", NEWLINE,
-                                "LOCALE", &variables[VARIABLE_LANG],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
-        }
-
-#elif defined(TARGET_GENTOO)
-        /* Gentoo's openrc expects locale variables in /etc/env.d/
-         * These files are later compiled by env-update into shell
-         * export commands at /etc/profile.env, with variables being
-         * exported by openrc's runscript (so /etc/init.d/)
-         */
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/profile.env", NEWLINE,
-                                "export LANG",              &variables[VARIABLE_LANG],
-                                "export LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
-                                "export LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
-                                "export LC_TIME",           &variables[VARIABLE_LC_TIME],
-                                "export LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
-                                "export LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
-                                "export LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
-                                "export LC_PAPER",          &variables[VARIABLE_LC_PAPER],
-                                "export LC_NAME",           &variables[VARIABLE_LC_NAME],
-                                "export LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
-                                "export LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
-                                "export LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
-                                "export LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/profile.env: %s", strerror(-r));
-        }
-#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA )
-        if (r <= 0 &&
-            (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
-                                "LANG",              &variables[VARIABLE_LANG],
-                                "LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
-                                "LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
-                                "LC_TIME",           &variables[VARIABLE_LC_TIME],
-                                "LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
-                                "LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
-                                "LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
-                                "LC_PAPER",          &variables[VARIABLE_LC_PAPER],
-                                "LC_NAME",           &variables[VARIABLE_LC_NAME],
-                                "LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
-                                "LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
-                                "LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
-                                "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
-        }
-
-#endif
-
-        if (!variables[VARIABLE_LANG]) {
-                if (!(variables[VARIABLE_LANG] = strdup("C"))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-        }
-
-        for (i = 0; i < _VARIABLE_MAX; i++) {
-
-                if (variables[i]) {
-                        if (setenv(variable_names[i], variables[i], 1) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-                } else
-                        unsetenv(variable_names[i]);
-        }
-
-        r = 0;
-
-finish:
-        for (i = 0; i < _VARIABLE_MAX; i++)
-                free(variables[i]);
-
-        return r;
-}
diff --git a/src/locale-setup.h b/src/locale-setup.h
deleted file mode 100644
index 09a6bc6..0000000
--- a/src/locale-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foolocalesetuphfoo
-#define foolocalesetuphfoo
-
-/***
-  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 locale_setup(void);
-
-#endif
diff --git a/src/manager.c b/src/manager.c
deleted file mode 100644
index 312527a..0000000
--- a/src/manager.c
+++ /dev/null
@@ -1,3235 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <sys/poll.h>
-#include <sys/reboot.h>
-#include <sys/ioctl.h>
-#include <linux/kd.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#include <systemd/sd-daemon.h>
-
-#include "manager.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "util.h"
-#include "mkdir.h"
-#include "ratelimit.h"
-#include "cgroup.h"
-#include "mount-setup.h"
-#include "unit-name.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "missing.h"
-#include "path-lookup.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "virt.h"
-#include "watchdog.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)
-
-/* Where clients shall send notification messages to */
-#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify"
-#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify"
-
-static int manager_setup_notify(Manager *m) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_un un;
-        } sa;
-        struct epoll_event ev;
-        int one = 1, r;
-        mode_t u;
-
-        assert(m);
-
-        m->notify_watch.type = WATCH_NOTIFY;
-        if ((m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
-                log_error("Failed to allocate notification socket: %m");
-                return -errno;
-        }
-
-        zero(sa);
-        sa.sa.sa_family = AF_UNIX;
-
-        if (getpid() != 1)
-                snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull());
-        else {
-                unlink(NOTIFY_SOCKET_SYSTEM);
-                strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path));
-        }
-
-        if (sa.un.sun_path[0] == '@')
-                sa.un.sun_path[0] = 0;
-
-        u = umask(0111);
-        r = bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
-        umask(u);
-
-        if (r < 0) {
-                log_error("bind() failed: %m");
-                return -errno;
-        }
-
-        if (setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
-                log_error("SO_PASSCRED failed: %m");
-                return -errno;
-        }
-
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.ptr = &m->notify_watch;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
-                return -errno;
-
-        if (sa.un.sun_path[0] == 0)
-                sa.un.sun_path[0] = '@';
-
-        if (!(m->notify_socket = strdup(sa.un.sun_path)))
-                return -ENOMEM;
-
-        log_debug("Using notification socket %s", m->notify_socket);
-
-        return 0;
-}
-
-static int enable_special_signals(Manager *m) {
-        int 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|O_CLOEXEC)) < 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);
-
-        sigset_add_many(&mask,
-                        SIGCHLD,     /* Child died */
-                        SIGTERM,     /* Reexecute daemon */
-                        SIGHUP,      /* Reload configuration */
-                        SIGUSR1,     /* systemd/upstart: reconnect to D-Bus */
-                        SIGUSR2,     /* systemd: dump status */
-                        SIGINT,      /* Kernel sends us this on control-alt-del */
-                        SIGWINCH,    /* Kernel sends us this on kbrequest (alt-arrowup) */
-                        SIGPWR,      /* Some kernel drivers and upsd send us this on power failure */
-                        SIGRTMIN+0,  /* systemd: start default.target */
-                        SIGRTMIN+1,  /* systemd: isolate rescue.target */
-                        SIGRTMIN+2,  /* systemd: isolate emergency.target */
-                        SIGRTMIN+3,  /* systemd: start halt.target */
-                        SIGRTMIN+4,  /* systemd: start poweroff.target */
-                        SIGRTMIN+5,  /* systemd: start reboot.target */
-                        SIGRTMIN+6,  /* systemd: start kexec.target */
-                        SIGRTMIN+13, /* systemd: Immediate halt */
-                        SIGRTMIN+14, /* systemd: Immediate poweroff */
-                        SIGRTMIN+15, /* systemd: Immediate reboot */
-                        SIGRTMIN+16, /* systemd: Immediate kexec */
-                        SIGRTMIN+20, /* systemd: enable status messages */
-                        SIGRTMIN+21, /* systemd: disable status messages */
-                        SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
-                        SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
-                        SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
-                        SIGRTMIN+27, /* systemd: set log target to console */
-                        SIGRTMIN+28, /* systemd: set log target to kmsg */
-                        SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
-                        -1);
-        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_SYSTEM)
-                return enable_special_signals(m);
-
-        return 0;
-}
-
-static void manager_strip_environment(Manager *m) {
-        assert(m);
-
-        /* Remove variables from the inherited set that are part of
-         * the container interface:
-         * http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface */
-        strv_remove_prefix(m->environment, "container=");
-        strv_remove_prefix(m->environment, "container_");
-
-        /* Remove variables from the inherited set that are part of
-         * the initrd interface:
-         * http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface */
-        strv_remove_prefix(m->environment, "RD_");
-}
-
-int manager_new(ManagerRunningAs running_as, 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;
-
-        dual_timestamp_get(&m->startup_timestamp);
-
-        m->running_as = running_as;
-        m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
-        m->exit_code = _MANAGER_EXIT_CODE_INVALID;
-        m->pin_cgroupfs_fd = -1;
-
-#ifdef HAVE_AUDIT
-        m->audit_fd = -1;
-#endif
-
-        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
-        m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
-
-        m->environment = strv_copy(environ);
-        if (!m->environment)
-                goto fail;
-
-        manager_strip_environment(m);
-
-        if (running_as == MANAGER_SYSTEM) {
-                m->default_controllers = strv_new("cpu", NULL);
-                if (!m->default_controllers)
-                        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 = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
-                goto fail;
-
-        if ((r = manager_setup_signals(m)) < 0)
-                goto fail;
-
-        if ((r = manager_setup_cgroup(m)) < 0)
-                goto fail;
-
-        if ((r = manager_setup_notify(m)) < 0)
-                goto fail;
-
-        /* Try to connect to the busses, if possible. */
-        if ((r = bus_init(m, running_as != MANAGER_SYSTEM)) < 0)
-                goto fail;
-
-#ifdef HAVE_AUDIT
-        if ((m->audit_fd = audit_open()) < 0 &&
-            /* If the kernel lacks netlink or audit support,
-             * don't worry about it. */
-            errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
-                log_error("Failed to connect to audit log: %m");
-#endif
-
-        m->taint_usr = dir_is_empty("/usr") > 0;
-
-        *_m = m;
-        return 0;
-
-fail:
-        manager_free(m);
-        return r;
-}
-
-static unsigned manager_dispatch_cleanup_queue(Manager *m) {
-        Unit *u;
-        unsigned n = 0;
-
-        assert(m);
-
-        while ((u = m->cleanup_queue)) {
-                assert(u->in_cleanup_queue);
-
-                unit_free(u);
-                n++;
-        }
-
-        return n;
-}
-
-enum {
-        GC_OFFSET_IN_PATH,  /* This one is on the path we were traveling */
-        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->gc_marker == gc_marker + GC_OFFSET_GOOD ||
-            u->gc_marker == gc_marker + GC_OFFSET_BAD ||
-            u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
-                return;
-
-        if (u->in_cleanup_queue)
-                goto bad;
-
-        if (unit_check_gc(u))
-                goto good;
-
-        u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
-
-        is_bad = true;
-
-        SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
-                unit_gc_sweep(other, gc_marker);
-
-                if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
-                        goto good;
-
-                if (other->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->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->gc_marker = gc_marker + GC_OFFSET_BAD;
-        unit_add_to_cleanup_queue(u);
-        return;
-
-good:
-        u->gc_marker = gc_marker + GC_OFFSET_GOOD;
-}
-
-static unsigned manager_dispatch_gc_queue(Manager *m) {
-        Unit *u;
-        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 ((u = m->gc_queue)) {
-                assert(u->in_gc_queue);
-
-                unit_gc_sweep(u, gc_marker);
-
-                LIST_REMOVE(Unit, gc_queue, m->gc_queue, u);
-                u->in_gc_queue = false;
-
-                n++;
-
-                if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
-                    u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
-                        log_debug("Collecting %s", u->id);
-                        u->gc_marker = gc_marker + GC_OFFSET_BAD;
-                        unit_add_to_cleanup_queue(u);
-                }
-        }
-
-        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);
-
-        manager_dispatch_cleanup_queue(m);
-
-        assert(!m->load_queue);
-        assert(!m->run_queue);
-        assert(!m->dbus_unit_queue);
-        assert(!m->dbus_job_queue);
-        assert(!m->cleanup_queue);
-        assert(!m->gc_queue);
-
-        assert(hashmap_isempty(m->transaction_jobs));
-        assert(hashmap_isempty(m->jobs));
-        assert(hashmap_isempty(m->units));
-}
-
-void manager_free(Manager *m) {
-        UnitType c;
-
-        assert(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);
-
-        manager_undo_generators(m);
-
-        bus_done(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);
-        if (m->notify_watch.fd >= 0)
-                close_nointr_nofail(m->notify_watch.fd);
-
-#ifdef HAVE_AUDIT
-        if (m->audit_fd >= 0)
-                audit_close(m->audit_fd);
-#endif
-
-        free(m->notify_socket);
-
-        lookup_paths_free(&m->lookup_paths);
-        strv_free(m->environment);
-
-        strv_free(m->default_controllers);
-
-        hashmap_free(m->cgroup_bondings);
-        set_free_free(m->unit_path_cache);
-
-        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->id != k)
-                        continue;
-
-                if ((q = unit_coldplug(u)) < 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-static void manager_build_unit_path_cache(Manager *m) {
-        char **i;
-        DIR *d = NULL;
-        int r;
-
-        assert(m);
-
-        set_free_free(m->unit_path_cache);
-
-        if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) {
-                log_error("Failed to allocate unit path cache.");
-                return;
-        }
-
-        /* This simply builds a list of files we know exist, so that
-         * we don't always have to go to disk */
-
-        STRV_FOREACH(i, m->lookup_paths.unit_path) {
-                struct dirent *de;
-
-                if (!(d = opendir(*i))) {
-                        log_error("Failed to open directory: %m");
-                        continue;
-                }
-
-                while ((de = readdir(d))) {
-                        char *p;
-
-                        if (ignore_file(de->d_name))
-                                continue;
-
-                        p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
-                        if (!p) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        if ((r = set_put(m->unit_path_cache, p)) < 0) {
-                                free(p);
-                                goto fail;
-                        }
-                }
-
-                closedir(d);
-                d = NULL;
-        }
-
-        return;
-
-fail:
-        log_error("Failed to build unit path cache: %s", strerror(-r));
-
-        set_free_free(m->unit_path_cache);
-        m->unit_path_cache = NULL;
-
-        if (d)
-                closedir(d);
-}
-
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
-        int r, q;
-
-        assert(m);
-
-        manager_run_generators(m);
-
-        manager_build_unit_path_cache(m);
-
-        /* If we will deserialize make sure that during enumeration
-         * this is already known, so we increase the counter here
-         * already */
-        if (serialization)
-                m->n_reloading ++;
-
-        /* 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;
-
-        if (serialization) {
-                assert(m->n_reloading > 0);
-                m->n_reloading --;
-        }
-
-        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 bool job_is_conflicted_by(Job *j) {
-        JobDependency *l;
-
-        assert(j);
-
-        /* Returns true if this job is pulled in by a least one
-         * ConflictedBy dependency. */
-
-        LIST_FOREACH(object, l, j->object_list)
-                if (l->conflicts)
-                        return true;
-
-        return false;
-}
-
-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
-         * with 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 && !k->matters_to_anchor) {
-
-                                /* Both jobs don't matter, so let's
-                                 * find the one that is smarter to
-                                 * remove. Let's think positive and
-                                 * rather remove stops then starts --
-                                 * except if something is being
-                                 * stopped because it is conflicted by
-                                 * another unit in which case we
-                                 * rather remove the start. */
-
-                                log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
-                                log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
-
-                                if (j->type == JOB_STOP) {
-
-                                        if (job_is_conflicted_by(j))
-                                                d = k;
-                                        else
-                                                d = j;
-
-                                } else if (k->type == JOB_STOP) {
-
-                                        if (job_is_conflicted_by(k))
-                                                d = j;
-                                        else
-                                                d = k;
-                                } else
-                                        d = j;
-
-                        } else 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("Fixing conflicting jobs by deleting job %s/%s", d->unit->id, job_type_to_string(d->type));
-                        transaction_delete_job(m, d, true);
-                        return 0;
-                }
-
-        return -EINVAL;
-}
-
-static int transaction_merge_jobs(Manager *m, DBusError *e) {
-        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 (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 */
-                        dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.",
-                                       job_type_to_string(t), job_type_to_string(k->type), k->unit->id);
-                        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->job)
-                        job_type_merge(&t, j->unit->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);
-                }
-
-                if (j->unit->job && !j->installed)
-                        transaction_merge_and_delete_job(m, j, j->unit->job, 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) &&
-                                    (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) &&
-                                    (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type)))
-                                        continue;
-
-                                changes_something = true;
-                                break;
-                        }
-
-                        if (changes_something)
-                                continue;
-
-                        /* log_debug("Found redundant job %s/%s, dropping.", j->unit->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, DBusError *e) {
-        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. */
-
-        /* Have we seen this before? */
-        if (j->generation == generation) {
-                Job *k, *delete;
-
-                /* If the marker is NULL we have been here already and
-                 * decided the job was loop-free from here. Hence
-                 * shortcut things and return right-away. */
-                if (!j->marker)
-                        return 0;
-
-                /* So, the marker is not NULL and 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_warning("Found ordering cycle on %s/%s", j->unit->id, job_type_to_string(j->type));
-
-                delete = NULL;
-                for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
-
-                        log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type));
-
-                        if (!delete &&
-                            !k->installed &&
-                            !unit_matters_to_anchor(k->unit, k)) {
-                                /* Ok, we can drop this one, so let's
-                                 * do so. */
-                                delete = k;
-                        }
-
-                        /* Check if this in fact was the beginning of
-                         * the cycle */
-                        if (k == j)
-                                break;
-                }
-
-
-                if (delete) {
-                        log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type));
-                        transaction_delete_unit(m, delete->unit);
-                        return -EAGAIN;
-                }
-
-                log_error("Unable to break cycle");
-
-                dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details.");
-                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. We use
-         * a special marker for the beginning: we point to
-         * ourselves. */
-        j->marker = from ? from : j;
-        j->generation = generation;
-
-        /* We assume that the the dependencies are bidirectional, and
-         * hence can ignore UNIT_AFTER */
-        SET_FOREACH(u, j->unit->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->job))
-                                continue;
-
-                if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 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, DBusError *e) {
-        Job *j;
-        int r;
-        Iterator i;
-        unsigned g;
-
-        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. */
-
-        g = (*generation)++;
-
-        HASHMAP_FOREACH(j, m->transaction_jobs, i)
-                if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 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) {
-                                /* log_debug("Keeping job %s/%s because of %s/%s", */
-                                /*           j->unit->id, job_type_to_string(j->type), */
-                                /*           j->object_list->subject ? j->object_list->subject->unit->id : "root", */
-                                /*           j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
-                                continue;
-                        }
-
-                        /* log_debug("Garbage collecting job %s/%s", j->unit->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, DBusError *e) {
-        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->job &&
-                    j->unit->job != j &&
-                    !job_type_is_superset(j->type, j->unit->job->type)) {
-
-                        dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
-                        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->job &&
-                                        job_type_is_conflicting(j->type, j->unit->job->type);
-
-                                if (!stops_running_service && !changes_existing_job)
-                                        continue;
-
-                                if (stops_running_service)
-                                        log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type));
-
-                                if (changes_existing_job)
-                                        log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type));
-
-                                /* Ok, let's get rid of this */
-                                log_debug("Deleting %s/%s to minimize impact.", j->unit->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, JobMode mode) {
-        Iterator i;
-        Job *j;
-        int r;
-
-        /* Moves the transaction jobs to the set of active jobs */
-
-        if (mode == JOB_ISOLATE) {
-
-                /* When isolating first kill all installed jobs which
-                 * aren't part of the new transaction */
-        rescan:
-                HASHMAP_FOREACH(j, m->jobs, i) {
-                        assert(j->installed);
-
-                        if (hashmap_get(m->transaction_jobs, j->unit))
-                                continue;
-
-                        /* 'j' itself is safe to remove, but if other jobs
-                           are invalidated recursively, our iterator may become
-                           invalid and we need to start over. */
-                        if (job_finish_and_invalidate(j, JOB_CANCELED) > 0)
-                                goto rescan;
-                }
-        }
-
-        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) {
-                        /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */
-                        continue;
-                }
-
-                if (j->unit->job)
-                        job_free(j->unit->job);
-
-                j->unit->job = j;
-                j->installed = true;
-                m->n_installed_jobs ++;
-
-                /* 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);
-                job_start_timer(j);
-
-                log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
-        }
-
-        /* 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, DBusError *e) {
-        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. */
-        if (mode == JOB_FAIL)
-                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. */
-                if (mode != JOB_ISOLATE)
-                        transaction_collect_garbage(m);
-
-                /* Fifth step: verify order makes sense and correct
-                 * cycles if necessary and possible */
-                if ((r = transaction_verify_order(m, &generation, e)) >= 0)
-                        break;
-
-                if (r != -EAGAIN) {
-                        log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, 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, e)) >= 0)
-                        break;
-
-                if (r != -EAGAIN) {
-                        log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
-                        goto rollback;
-                }
-
-                /* Seventh step: an entry got dropped, let's garbage
-                 * collect its dependencies. */
-                if (mode != JOB_ISOLATE)
-                        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, e)) < 0) {
-                        log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
-                        goto rollback;
-                }
-
-        /* Tenth step: apply changes */
-        if ((r = transaction_apply(m, mode)) < 0) {
-                log_warning("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;
-
-        assert(m);
-        assert(unit);
-
-        /* Looks for an existing 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->job && unit->job->type == type)
-                j = unit->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 (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->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->id, job_type_to_string(other->type),
-                                  j->unit->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,
-                bool conflicts,
-                bool ignore_requirements,
-                bool ignore_order,
-                DBusError *e,
-                Job **_ret) {
-        Job *ret;
-        Iterator i;
-        Unit *dep;
-        int r;
-        bool is_new;
-
-        assert(m);
-        assert(type < _JOB_TYPE_MAX);
-        assert(unit);
-
-        /* log_debug("Pulling in %s/%s from %s/%s", */
-        /*           unit->id, job_type_to_string(type), */
-        /*           by ? by->unit->id : "NA", */
-        /*           by ? job_type_to_string(by->type) : "NA"); */
-
-        if (unit->load_state != UNIT_LOADED &&
-            unit->load_state != UNIT_ERROR &&
-            unit->load_state != UNIT_MASKED) {
-                dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
-                return -EINVAL;
-        }
-
-        if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
-                dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
-                               "Unit %s failed to load: %s. "
-                               "See system logs and 'systemctl status %s' for details.",
-                               unit->id,
-                               strerror(-unit->load_error),
-                               unit->id);
-                return -EINVAL;
-        }
-
-        if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
-                dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
-                return -EINVAL;
-        }
-
-        if (!unit_job_is_applicable(unit, type)) {
-                dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id);
-                return -EBADR;
-        }
-
-        /* First add the job. */
-        if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
-                return -ENOMEM;
-
-        ret->ignore_order = ret->ignore_order || ignore_order;
-
-        /* Then, add a link to the job. */
-        if (!job_dependency_new(by, ret, matters, conflicts))
-                return -ENOMEM;
-
-        if (is_new && !ignore_requirements) {
-                Set *following;
-
-                /* If we are following some other unit, make sure we
-                 * add all dependencies of everybody following. */
-                if (unit_following_set(ret->unit, &following) > 0) {
-                        SET_FOREACH(dep, following, i)
-                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        set_free(following);
-                }
-
-                /* Finally, recursively add in all dependencies. */
-                if (type == JOB_START || type == JOB_RELOAD_OR_START) {
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
-                                        if (r != -EBADR)
-                                                goto fail;
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_BIND_TO], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
-
-                                        if (r != -EBADR)
-                                                goto fail;
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) {
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
-
-                                        if (r != -EBADR)
-                                                goto fail;
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) {
-
-                                        if (r != -EBADR)
-                                                goto fail;
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                }
-
-                if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
-
-                                        if (r != -EBADR)
-                                                goto fail;
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
-
-                                        if (r != -EBADR)
-                                                goto fail;
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-                }
-
-                if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START) {
-
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATE_RELOAD_TO], i) {
-                                r = transaction_add_job_and_dependencies(m, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e, NULL);
-
-                                if (r < 0) {
-                                        log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
-                                        if (e)
-                                                dbus_error_free(e);
-                                }
-                        }
-                }
-
-                /* 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->id != k)
-                        continue;
-
-                if (u->ignore_on_isolate)
-                        continue;
-
-                /* No need to stop inactive jobs */
-                if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
-                        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, false, false, false, NULL, NULL)) < 0)
-                        log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r));
-        }
-
-        return 0;
-}
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, 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) {
-                dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start.");
-                return -EINVAL;
-        }
-
-        if (mode == JOB_ISOLATE && !unit->allow_isolate) {
-                dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
-                return -EPERM;
-        }
-
-        log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
-
-        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false,
-                                                      mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
-                                                      mode == JOB_IGNORE_DEPENDENCIES, e, &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, e)) < 0)
-                return r;
-
-        log_debug("Enqueued job %s/%s as %u", unit->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, DBusError *e, 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, NULL, &unit)) < 0)
-                return r;
-
-        return manager_add_job(m, type, unit, mode, override, e, _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) {
-        Unit *u;
-        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 ((u = m->load_queue)) {
-                assert(u->in_load_queue);
-
-                unit_load(u);
-                n++;
-        }
-
-        m->dispatching_load_queue = false;
-        return n;
-}
-
-int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
-        Unit *ret;
-        UnitType t;
-        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)) {
-                dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path);
-                return -EINVAL;
-        }
-
-        if (!name)
-                name = file_name_from_path(path);
-
-        t = unit_name_to_type(name);
-
-        if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid_no_type(name, false)) {
-                dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
-                return -EINVAL;
-        }
-
-        ret = manager_get_unit(m, name);
-        if (ret) {
-                *_ret = ret;
-                return 1;
-        }
-
-        ret = unit_new(m, unit_vtable[t]->object_size);
-        if (!ret)
-                return -ENOMEM;
-
-        if (path) {
-                ret->fragment_path = strdup(path);
-                if (!ret->fragment_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, DBusError *e, 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, e, _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->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_finish_and_invalidate(j, JOB_CANCELED);
-}
-
-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;
-        Unit *u;
-        unsigned n = 0;
-
-        assert(m);
-
-        if (m->dispatching_dbus_queue)
-                return 0;
-
-        m->dispatching_dbus_queue = true;
-
-        while ((u = m->dbus_unit_queue)) {
-                assert(u->in_dbus_queue);
-
-                bus_unit_send_change_signal(u);
-                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_process_notify_fd(Manager *m) {
-        ssize_t n;
-
-        assert(m);
-
-        for (;;) {
-                char buf[4096];
-                struct msghdr msghdr;
-                struct iovec iovec;
-                struct ucred *ucred;
-                union {
-                        struct cmsghdr cmsghdr;
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-                } control;
-                Unit *u;
-                char **tags;
-
-                zero(iovec);
-                iovec.iov_base = buf;
-                iovec.iov_len = sizeof(buf)-1;
-
-                zero(control);
-                zero(msghdr);
-                msghdr.msg_iov = &iovec;
-                msghdr.msg_iovlen = 1;
-                msghdr.msg_control = &control;
-                msghdr.msg_controllen = sizeof(control);
-
-                if ((n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT)) <= 0) {
-                        if (n >= 0)
-                                return -EIO;
-
-                        if (errno == EAGAIN || errno == EINTR)
-                                break;
-
-                        return -errno;
-                }
-
-                if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
-                    control.cmsghdr.cmsg_level != SOL_SOCKET ||
-                    control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
-                    control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
-                        log_warning("Received notify message without credentials. Ignoring.");
-                        continue;
-                }
-
-                ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
-
-                if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid))))
-                        if (!(u = cgroup_unit_by_pid(m, ucred->pid))) {
-                                log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
-                                continue;
-                        }
-
-                assert((size_t) n < sizeof(buf));
-                buf[n] = 0;
-                if (!(tags = strv_split(buf, "\n\r")))
-                        return -ENOMEM;
-
-                log_debug("Got notification message for unit %s", u->id);
-
-                if (UNIT_VTABLE(u)->notify_message)
-                        UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags);
-
-                strv_free(tags);
-        }
-
-        return 0;
-}
-
-static int manager_dispatch_sigchld(Manager *m) {
-        assert(m);
-
-        for (;;) {
-                siginfo_t si;
-                Unit *u;
-                int r;
-
-                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_comm(si.si_pid, &name);
-                        log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
-                        free(name);
-                }
-
-                /* Let's flush any message the dying child might still
-                 * have queued for us. This ensures that the process
-                 * still exists in /proc so that we can figure out
-                 * which cgroup and hence unit it belongs to. */
-                if ((r = manager_process_notify_fd(m)) < 0)
-                        return r;
-
-                /* And now figure out the unit this belongs to */
-                if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid))))
-                        u = cgroup_unit_by_pid(m, si.si_pid);
-
-                /* 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 %lu died (code=%s, status=%i/%s)",
-                          (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, EXIT_STATUS_FULL)
-                                : signal_to_string(si.si_status)));
-
-                if (!u)
-                        continue;
-
-                log_debug("Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
-
-                hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
-                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
-        }
-
-        return 0;
-}
-
-static int manager_start_target(Manager *m, const char *name, JobMode mode) {
-        int r;
-        DBusError error;
-
-        dbus_error_init(&error);
-
-        log_debug("Activating special unit %s", name);
-
-        if ((r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL)) < 0)
-                log_error("Failed to enqueue %s job: %s", name, bus_error(&error, r));
-
-        dbus_error_free(&error);
-
-        return 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 == EINTR || errno == EAGAIN)
-                                break;
-
-                        return -errno;
-                }
-
-                if (sfsi.ssi_pid > 0) {
-                        char *p = NULL;
-
-                        get_process_comm(sfsi.ssi_pid, &p);
-
-                        log_debug("Received SIG%s from PID %lu (%s).",
-                                  signal_to_string(sfsi.ssi_signo),
-                                  (unsigned long) sfsi.ssi_pid, strna(p));
-                        free(p);
-                } else
-                        log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo));
-
-                switch (sfsi.ssi_signo) {
-
-                case SIGCHLD:
-                        sigchld = true;
-                        break;
-
-                case SIGTERM:
-                        if (m->running_as == MANAGER_SYSTEM) {
-                                /* This is for compatibility with the
-                                 * original sysvinit */
-                                m->exit_code = MANAGER_REEXECUTE;
-                                break;
-                        }
-
-                        /* Fall through */
-
-                case SIGINT:
-                        if (m->running_as == MANAGER_SYSTEM) {
-                                manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE);
-                                break;
-                        }
-
-                        /* Run the exit target if there is one, if not, just exit. */
-                        if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
-                                m->exit_code = MANAGER_EXIT;
-                                return 0;
-                        }
-
-                        break;
-
-                case SIGWINCH:
-                        if (m->running_as == MANAGER_SYSTEM)
-                                manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
-
-                        /* This is a nop on non-init */
-                        break;
-
-                case SIGPWR:
-                        if (m->running_as == MANAGER_SYSTEM)
-                                manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
-
-                        /* 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(m, true);
-                        }
-
-                        if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
-                                log_info("Loading D-Bus service...");
-                                manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
-                        }
-
-                        break;
-                }
-
-                case SIGUSR2: {
-                        FILE *f;
-                        char *dump = NULL;
-                        size_t size;
-
-                        if (!(f = open_memstream(&dump, &size))) {
-                                log_warning("Failed to allocate memory stream.");
-                                break;
-                        }
-
-                        manager_dump_units(m, f, "\t");
-                        manager_dump_jobs(m, f, "\t");
-
-                        if (ferror(f)) {
-                                fclose(f);
-                                free(dump);
-                                log_warning("Failed to write status stream");
-                                break;
-                        }
-
-                        fclose(f);
-                        log_dump(LOG_INFO, dump);
-                        free(dump);
-
-                        break;
-                }
-
-                case SIGHUP:
-                        m->exit_code = MANAGER_RELOAD;
-                        break;
-
-                default: {
-
-                        /* Starting SIGRTMIN+0 */
-                        static const char * const target_table[] = {
-                                [0] = SPECIAL_DEFAULT_TARGET,
-                                [1] = SPECIAL_RESCUE_TARGET,
-                                [2] = SPECIAL_EMERGENCY_TARGET,
-                                [3] = SPECIAL_HALT_TARGET,
-                                [4] = SPECIAL_POWEROFF_TARGET,
-                                [5] = SPECIAL_REBOOT_TARGET,
-                                [6] = SPECIAL_KEXEC_TARGET
-                        };
-
-                        /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
-                        static const ManagerExitCode code_table[] = {
-                                [0] = MANAGER_HALT,
-                                [1] = MANAGER_POWEROFF,
-                                [2] = MANAGER_REBOOT,
-                                [3] = MANAGER_KEXEC
-                        };
-
-                        if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
-                            (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
-                                int idx = (int) sfsi.ssi_signo - SIGRTMIN;
-                                manager_start_target(m, target_table[idx],
-                                                     (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
-                                break;
-                        }
-
-                        if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
-                            (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
-                                m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
-                                break;
-                        }
-
-                        switch (sfsi.ssi_signo - SIGRTMIN) {
-
-                        case 20:
-                                log_debug("Enabling showing of status.");
-                                manager_set_show_status(m, true);
-                                break;
-
-                        case 21:
-                                log_debug("Disabling showing of status.");
-                                manager_set_show_status(m, false);
-                                break;
-
-                        case 22:
-                                log_set_max_level(LOG_DEBUG);
-                                log_notice("Setting log level to debug.");
-                                break;
-
-                        case 23:
-                                log_set_max_level(LOG_INFO);
-                                log_notice("Setting log level to info.");
-                                break;
-
-                        case 26:
-                                log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
-                                log_notice("Setting log target to journal-or-kmsg.");
-                                break;
-
-                        case 27:
-                                log_set_target(LOG_TARGET_CONSOLE);
-                                log_notice("Setting log target to console.");
-                                break;
-
-                        case 28:
-                                log_set_target(LOG_TARGET_KMSG);
-                                log_notice("Setting log target to kmsg.");
-                                break;
-
-                        case 29:
-                                log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
-                                log_notice("Setting log target to syslog-or-kmsg.");
-                                break;
-
-                        default:
-                                log_warning("Got unhandled signal <%s>.", signal_to_string(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_se(w = ev->data.ptr);
-
-        if (w->type == WATCH_INVALID)
-                return 0;
-
-        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_NOTIFY:
-
-                /* An incoming daemon notification event? */
-                if (ev->events != EPOLLIN)
-                        return -EINVAL;
-
-                if ((r = manager_process_notify_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_UNIT_TIMER:
-        case WATCH_JOB_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;
-                }
-
-                if (w->type == WATCH_UNIT_TIMER)
-                        UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
-                else
-                        job_timer_event(w->data.job, v, w);
-                break;
-        }
-
-        case WATCH_MOUNT:
-                /* Some mount table change, intended for the mount subsystem */
-                mount_fd_event(m, ev->events);
-                break;
-
-        case WATCH_SWAP:
-                /* Some swap table change, intended for the swap subsystem */
-                swap_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:
-                log_error("event type=%i", w->type);
-                assert_not_reached("Unknown epoll event type.");
-        }
-
-        return 0;
-}
-
-int manager_loop(Manager *m) {
-        int r;
-        int wait_msec = -1;
-
-        RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
-
-        assert(m);
-        m->exit_code = MANAGER_RUNNING;
-
-        /* Release the path cache */
-        set_free_free(m->unit_path_cache);
-        m->unit_path_cache = NULL;
-
-        manager_check_finished(m);
-
-        /* There might still be some zombies hanging around from
-         * before we were exec()'ed. Leat's reap them */
-        r = manager_dispatch_sigchld(m);
-        if (r < 0)
-                return r;
-
-        /* Sleep for half the watchdog time */
-        if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)  {
-                wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
-                if (wait_msec <= 0)
-                        wait_msec = 1;
-        }
-
-        while (m->exit_code == MANAGER_RUNNING) {
-                struct epoll_event event;
-                int n;
-
-                if (wait_msec >= 0)
-                        watchdog_ping();
-
-                if (!ratelimit_test(&rl)) {
-                        /* Yay, something is going seriously wrong, pause a little */
-                        log_warning("Looping too fast. Throttling execution a little.");
-                        sleep(1);
-                        continue;
-                }
-
-                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 (swap_dispatch_reload(m) > 0)
-                        continue;
-
-                n = epoll_wait(m->epoll_fd, &event, 1, wait_msec);
-                if (n < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-                } else if (n == 0)
-                        continue;
-
-                assert(n == 1);
-
-                r = process_event(m, &event);
-                if (r < 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;
-}
-
-void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
-
-#ifdef HAVE_AUDIT
-        char *p;
-
-        if (m->audit_fd < 0)
-                return;
-
-        /* Don't generate audit events if the service was already
-         * started and we're just deserializing */
-        if (m->n_reloading > 0)
-                return;
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
-        if (u->type != UNIT_SERVICE)
-                return;
-
-        if (!(p = unit_name_to_prefix_and_instance(u->id))) {
-                log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
-                return;
-        }
-
-        if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
-                log_warning("Failed to send audit message: %m");
-
-                if (errno == EPERM) {
-                        /* We aren't allowed to send audit messages?
-                         * Then let's not retry again, to avoid
-                         * spamming the user with the same and same
-                         * messages over and over. */
-
-                        audit_close(m->audit_fd);
-                        m->audit_fd = -1;
-                }
-        }
-
-        free(p);
-#endif
-
-}
-
-void manager_send_unit_plymouth(Manager *m, Unit *u) {
-        int fd = -1;
-        union sockaddr_union sa;
-        int n = 0;
-        char *message = NULL;
-
-        /* Don't generate plymouth events if the service was already
-         * started and we're just deserializing */
-        if (m->n_reloading > 0)
-                return;
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
-        if (u->type != UNIT_SERVICE &&
-            u->type != UNIT_MOUNT &&
-            u->type != UNIT_SWAP)
-                return;
-
-        /* We set SOCK_NONBLOCK here so that we rather drop the
-         * message then wait for plymouth */
-        if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
-                log_error("socket() failed: %m");
-                return;
-        }
-
-        zero(sa);
-        sa.sa.sa_family = AF_UNIX;
-        strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
-        if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
-
-                if (errno != EPIPE &&
-                    errno != EAGAIN &&
-                    errno != ENOENT &&
-                    errno != ECONNREFUSED &&
-                    errno != ECONNRESET &&
-                    errno != ECONNABORTED)
-                        log_error("connect() failed: %m");
-
-                goto finish;
-        }
-
-        if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
-                log_error("Out of memory");
-                goto finish;
-        }
-
-        errno = 0;
-        if (write(fd, message, n + 1) != n + 1) {
-
-                if (errno != EPIPE &&
-                    errno != EAGAIN &&
-                    errno != ENOENT &&
-                    errno != ECONNREFUSED &&
-                    errno != ECONNRESET &&
-                    errno != ECONNABORTED)
-                        log_error("Failed to write Plymouth message: %m");
-
-                goto finish;
-        }
-
-finish:
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        free(message);
-}
-
-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(Manager *m, FILE **_f) {
-        char *path = NULL;
-        mode_t saved_umask;
-        int fd;
-        FILE *f;
-
-        assert(_f);
-
-        if (m->running_as == MANAGER_SYSTEM)
-                asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
-        else
-                asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
-
-        if (!path)
-                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+")))
-                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);
-
-        m->n_reloading ++;
-
-        fprintf(f, "current-job-id=%i\n", m->current_job_id);
-        fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
-
-        dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
-        dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp);
-        dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
-
-        fputc('\n', f);
-
-        HASHMAP_FOREACH_KEY(u, t, m->units, i) {
-                if (u->id != t)
-                        continue;
-
-                if (!unit_can_serialize(u))
-                        continue;
-
-                /* Start marker */
-                fputs(u->id, f);
-                fputc('\n', f);
-
-                if ((r = unit_serialize(u, f, fds)) < 0) {
-                        m->n_reloading --;
-                        return r;
-                }
-        }
-
-        assert(m->n_reloading > 0);
-        m->n_reloading --;
-
-        if (ferror(f))
-                return -EIO;
-
-        r = bus_fdset_add_all(m, fds);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
-        int r = 0;
-
-        assert(m);
-        assert(f);
-
-        log_debug("Deserializing state...");
-
-        m->n_reloading ++;
-
-        for (;;) {
-                char line[LINE_MAX], *l;
-
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                r = 0;
-                        else
-                                r = -errno;
-
-                        goto finish;
-                }
-
-                char_array_0(line);
-                l = strstrip(line);
-
-                if (l[0] == 0)
-                        break;
-
-                if (startswith(l, "current-job-id=")) {
-                        uint32_t id;
-
-                        if (safe_atou32(l+15, &id) < 0)
-                                log_debug("Failed to parse current job id value %s", l+15);
-                        else
-                                m->current_job_id = MAX(m->current_job_id, id);
-                } else if (startswith(l, "taint-usr=")) {
-                        int b;
-
-                        if ((b = parse_boolean(l+10)) < 0)
-                                log_debug("Failed to parse taint /usr flag %s", l+10);
-                        else
-                                m->taint_usr = m->taint_usr || b;
-                } else if (startswith(l, "initrd-timestamp="))
-                        dual_timestamp_deserialize(l+17, &m->initrd_timestamp);
-                else if (startswith(l, "startup-timestamp="))
-                        dual_timestamp_deserialize(l+18, &m->startup_timestamp);
-                else if (startswith(l, "finish-timestamp="))
-                        dual_timestamp_deserialize(l+17, &m->finish_timestamp);
-                else
-                        log_debug("Unknown serialization item '%s'", l);
-        }
-
-        for (;;) {
-                Unit *u;
-                char name[UNIT_NAME_MAX+2];
-
-                /* Start marker */
-                if (!fgets(name, sizeof(name), f)) {
-                        if (feof(f))
-                                r = 0;
-                        else
-                                r = -errno;
-
-                        goto finish;
-                }
-
-                char_array_0(name);
-
-                if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0)
-                        goto finish;
-
-                if ((r = unit_deserialize(u, f, fds)) < 0)
-                        goto finish;
-        }
-
-finish:
-        if (ferror(f)) {
-                r = -EIO;
-                goto finish;
-        }
-
-        assert(m->n_reloading > 0);
-        m->n_reloading --;
-
-        return r;
-}
-
-int manager_reload(Manager *m) {
-        int r, q;
-        FILE *f;
-        FDSet *fds;
-
-        assert(m);
-
-        if ((r = manager_open_serialization(m, &f)) < 0)
-                return r;
-
-        m->n_reloading ++;
-
-        if (!(fds = fdset_new())) {
-                m->n_reloading --;
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if ((r = manager_serialize(m, f, fds)) < 0) {
-                m->n_reloading --;
-                goto finish;
-        }
-
-        if (fseeko(f, 0, SEEK_SET) < 0) {
-                m->n_reloading --;
-                r = -errno;
-                goto finish;
-        }
-
-        /* From here on there is no way back. */
-        manager_clear_jobs_and_units(m);
-        manager_undo_generators(m);
-
-        /* Find new unit paths */
-        lookup_paths_free(&m->lookup_paths);
-        if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
-                r = q;
-
-        manager_run_generators(m);
-
-        manager_build_unit_path_cache(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;
-
-        assert(m->n_reloading > 0);
-        m->n_reloading--;
-
-finish:
-        if (f)
-                fclose(f);
-
-        if (fds)
-                fdset_free(fds);
-
-        return r;
-}
-
-bool manager_is_booting_or_shutting_down(Manager *m) {
-        Unit *u;
-
-        assert(m);
-
-        /* Is the initial job still around? */
-        if (manager_get_job(m, m->default_unit_job_id))
-                return true;
-
-        /* Is there a job for the shutdown target? */
-        u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
-        if (u)
-                return !!u->job;
-
-        return false;
-}
-
-void manager_reset_failed(Manager *m) {
-        Unit *u;
-        Iterator i;
-
-        assert(m);
-
-        HASHMAP_FOREACH(u, m->units, i)
-                unit_reset_failed(u);
-}
-
-bool manager_unit_pending_inactive(Manager *m, const char *name) {
-        Unit *u;
-
-        assert(m);
-        assert(name);
-
-        /* Returns true if the unit is inactive or going down */
-        if (!(u = manager_get_unit(m, name)))
-                return true;
-
-        return unit_pending_inactive(u);
-}
-
-void manager_check_finished(Manager *m) {
-        char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
-        usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0;
-
-        assert(m);
-
-        if (dual_timestamp_is_set(&m->finish_timestamp))
-                return;
-
-        if (hashmap_size(m->jobs) > 0)
-                return;
-
-        dual_timestamp_get(&m->finish_timestamp);
-
-        if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
-
-                userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
-                total_usec = m->finish_timestamp.monotonic;
-
-                if (dual_timestamp_is_set(&m->initrd_timestamp)) {
-
-                        kernel_usec = m->initrd_timestamp.monotonic;
-                        initrd_usec = m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic;
-
-                        log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
-                                 format_timespan(kernel, sizeof(kernel), kernel_usec),
-                                 format_timespan(initrd, sizeof(initrd), initrd_usec),
-                                 format_timespan(userspace, sizeof(userspace), userspace_usec),
-                                 format_timespan(sum, sizeof(sum), total_usec));
-                } else {
-                        kernel_usec = m->startup_timestamp.monotonic;
-                        initrd_usec = 0;
-
-                        log_info("Startup finished in %s (kernel) + %s (userspace) = %s.",
-                                 format_timespan(kernel, sizeof(kernel), kernel_usec),
-                                 format_timespan(userspace, sizeof(userspace), userspace_usec),
-                                 format_timespan(sum, sizeof(sum), total_usec));
-                }
-        } else {
-                userspace_usec = initrd_usec = kernel_usec = 0;
-                total_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
-
-                log_debug("Startup finished in %s.",
-                          format_timespan(sum, sizeof(sum), total_usec));
-        }
-
-        bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec);
-
-        sd_notifyf(false,
-                   "READY=1\nSTATUS=Startup finished in %s.",
-                   format_timespan(sum, sizeof(sum), total_usec));
-}
-
-void manager_run_generators(Manager *m) {
-        DIR *d = NULL;
-        const char *generator_path;
-        const char *argv[3];
-        mode_t u;
-
-        assert(m);
-
-        generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
-        if (!(d = opendir(generator_path))) {
-
-                if (errno == ENOENT)
-                        return;
-
-                log_error("Failed to enumerate generator directory: %m");
-                return;
-        }
-
-        if (!m->generator_unit_path) {
-                const char *p;
-                char user_path[] = "/tmp/systemd-generator-XXXXXX";
-
-                if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
-                        p = "/run/systemd/generator";
-
-                        if (mkdir_p(p, 0755) < 0) {
-                                log_error("Failed to create generator directory: %m");
-                                goto finish;
-                        }
-
-                } else {
-                        if (!(p = mkdtemp(user_path))) {
-                                log_error("Failed to create generator directory: %m");
-                                goto finish;
-                        }
-                }
-
-                if (!(m->generator_unit_path = strdup(p))) {
-                        log_error("Failed to allocate generator unit path.");
-                        goto finish;
-                }
-        }
-
-        argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
-        argv[1] = m->generator_unit_path;
-        argv[2] = NULL;
-
-        u = umask(0022);
-        execute_directory(generator_path, d, (char**) argv);
-        umask(u);
-
-        if (rmdir(m->generator_unit_path) >= 0) {
-                /* Uh? we were able to remove this dir? I guess that
-                 * means the directory was empty, hence let's shortcut
-                 * this */
-
-                free(m->generator_unit_path);
-                m->generator_unit_path = NULL;
-                goto finish;
-        }
-
-        if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) {
-                char **l;
-
-                if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) {
-                        log_error("Failed to add generator directory to unit search path: %m");
-                        goto finish;
-                }
-
-                strv_free(m->lookup_paths.unit_path);
-                m->lookup_paths.unit_path = l;
-
-                log_debug("Added generator unit path %s to search path.", m->generator_unit_path);
-        }
-
-finish:
-        if (d)
-                closedir(d);
-}
-
-void manager_undo_generators(Manager *m) {
-        assert(m);
-
-        if (!m->generator_unit_path)
-                return;
-
-        strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
-        rm_rf(m->generator_unit_path, false, true, false);
-
-        free(m->generator_unit_path);
-        m->generator_unit_path = NULL;
-}
-
-int manager_set_default_controllers(Manager *m, char **controllers) {
-        char **l;
-
-        assert(m);
-
-        if (!(l = strv_copy(controllers)))
-                return -ENOMEM;
-
-        strv_free(m->default_controllers);
-        m->default_controllers = l;
-
-        return 0;
-}
-
-void manager_recheck_journal(Manager *m) {
-        Unit *u;
-
-        assert(m);
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
-        u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
-        if (u && SOCKET(u)->state != SOCKET_RUNNING) {
-                log_close_journal();
-                return;
-        }
-
-        u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE);
-        if (u && SERVICE(u)->state != SERVICE_RUNNING) {
-                log_close_journal();
-                return;
-        }
-
-        /* Hmm, OK, so the socket is fully up and the service is up
-         * too, then let's make use of the thing. */
-        log_open();
-}
-
-void manager_set_show_status(Manager *m, bool b) {
-        assert(m);
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
-        m->show_status = b;
-
-        if (b)
-                touch("/run/systemd/show-status");
-        else
-                unlink("/run/systemd/show-status");
-}
-
-bool manager_get_show_status(Manager *m) {
-        assert(m);
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return false;
-
-        if (m->show_status)
-                return true;
-
-        /* If Plymouth is running make sure we show the status, so
-         * that there's something nice to see when people press Esc */
-
-        return plymouth_running();
-}
-
-static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
-        [MANAGER_SYSTEM] = "system",
-        [MANAGER_USER] = "user"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);
diff --git a/src/manager.h b/src/manager.h
deleted file mode 100644
index 9ecc926..0000000
--- a/src/manager.h
+++ /dev/null
@@ -1,304 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 131072 /* 128K */
-
-typedef struct Manager Manager;
-typedef enum WatchType WatchType;
-typedef struct Watch Watch;
-
-typedef enum ManagerExitCode {
-        MANAGER_RUNNING,
-        MANAGER_EXIT,
-        MANAGER_RELOAD,
-        MANAGER_REEXECUTE,
-        MANAGER_REBOOT,
-        MANAGER_POWEROFF,
-        MANAGER_HALT,
-        MANAGER_KEXEC,
-        _MANAGER_EXIT_CODE_MAX,
-        _MANAGER_EXIT_CODE_INVALID = -1
-} ManagerExitCode;
-
-typedef enum ManagerRunningAs {
-        MANAGER_SYSTEM,
-        MANAGER_USER,
-        _MANAGER_RUNNING_AS_MAX,
-        _MANAGER_RUNNING_AS_INVALID = -1
-} ManagerRunningAs;
-
-enum WatchType {
-        WATCH_INVALID,
-        WATCH_SIGNAL,
-        WATCH_NOTIFY,
-        WATCH_FD,
-        WATCH_UNIT_TIMER,
-        WATCH_JOB_TIMER,
-        WATCH_MOUNT,
-        WATCH_SWAP,
-        WATCH_UDEV,
-        WATCH_DBUS_WATCH,
-        WATCH_DBUS_TIMEOUT
-};
-
-struct Watch {
-        int fd;
-        WatchType type;
-        union {
-                struct Unit *unit;
-                struct Job *job;
-                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"
-#include "path-lookup.h"
-
-struct Manager {
-        /* Note that the set of units we know of is allowed to be
-         * inconsistent. 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(Unit, units_by_type[_UNIT_TYPE_MAX]);
-
-        /* Units that need to be loaded */
-        LIST_HEAD(Unit, 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(Unit, dbus_unit_queue);
-        LIST_HEAD(Job, dbus_job_queue);
-
-        /* Units to remove */
-        LIST_HEAD(Unit, cleanup_queue);
-
-        /* Units to check when doing GC */
-        LIST_HEAD(Unit, 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 */
-
-        char *notify_socket;
-
-        Watch notify_watch;
-        Watch signal_watch;
-
-        int epoll_fd;
-
-        unsigned n_snapshots;
-
-        LookupPaths lookup_paths;
-        Set *unit_path_cache;
-
-        char **environment;
-        char **default_controllers;
-
-        usec_t runtime_watchdog;
-        usec_t shutdown_watchdog;
-
-        dual_timestamp initrd_timestamp;
-        dual_timestamp startup_timestamp;
-        dual_timestamp finish_timestamp;
-
-        char *generator_unit_path;
-
-        /* Data specific to the device subsystem */
-        struct udev* udev;
-        struct udev_monitor* udev_monitor;
-        Watch udev_watch;
-        Hashmap *devices_by_sysfs;
-
-        /* Data specific to the mount subsystem */
-        FILE *proc_self_mountinfo;
-        Watch mount_watch;
-
-        /* Data specific to the swap filesystem */
-        FILE *proc_swaps;
-        Hashmap *swaps_by_proc_swaps;
-        bool request_reload;
-        Watch swap_watch;
-
-        /* Data specific to the D-Bus subsystem */
-        DBusConnection *api_bus, *system_bus;
-        DBusServer *private_bus;
-        Set *bus_connections, *bus_connections_for_dispatch;
-
-        DBusMessage *queued_message; /* This is used during reloading:
-                                      * before the reload we queue the
-                                      * reply message here, and
-                                      * afterwards we send it */
-        DBusConnection *queued_message_connection; /* The connection to send the queued message on */
-
-        Hashmap *watch_bus;  /* D-Bus names => Unit object n:1 */
-        int32_t name_data_slot;
-        int32_t conn_data_slot;
-        int32_t subscribed_data_slot;
-
-        uint32_t current_job_id;
-        uint32_t default_unit_job_id;
-
-        /* 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_hierarchy;
-
-        usec_t gc_queue_timestamp;
-        int gc_marker;
-        unsigned n_in_gc_queue;
-
-        /* Make sure the user cannot accidentally unmount our cgroup
-         * file system */
-        int pin_cgroupfs_fd;
-
-        /* Audit fd */
-#ifdef HAVE_AUDIT
-        int audit_fd;
-#endif
-
-        /* Flags */
-        ManagerRunningAs running_as;
-        ManagerExitCode exit_code:5;
-
-        bool dispatching_load_queue:1;
-        bool dispatching_run_queue:1;
-        bool dispatching_dbus_queue:1;
-
-        bool taint_usr:1;
-
-        bool show_status;
-        bool confirm_spawn;
-#ifdef HAVE_SYSV_COMPAT
-        bool sysv_console;
-#endif
-        bool mount_auto;
-        bool swap_auto;
-
-        ExecOutput default_std_output, default_std_error;
-
-        /* non-zero if we are reloading or reexecuting, */
-        int n_reloading;
-
-        unsigned n_installed_jobs;
-        unsigned n_failed_jobs;
-};
-
-int manager_new(ManagerRunningAs running_as, 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, DBusError *e, Unit **_ret);
-int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret);
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, DBusError *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, DBusError *e, 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_set_default_controllers(Manager *m, char **controllers);
-
-int manager_loop(Manager *m);
-
-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(Manager *m, 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);
-
-bool manager_is_booting_or_shutting_down(Manager *m);
-
-void manager_reset_failed(Manager *m);
-
-void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
-void manager_send_unit_plymouth(Manager *m, Unit *u);
-
-bool manager_unit_pending_inactive(Manager *m, const char *name);
-
-void manager_check_finished(Manager *m);
-
-void manager_run_generators(Manager *m);
-void manager_undo_generators(Manager *m);
-
-void manager_recheck_journal(Manager *m);
-
-void manager_set_show_status(Manager *m, bool b);
-bool manager_get_show_status(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/mount.c b/src/mount.c
deleted file mode 100644
index 7dbeaf9..0000000
--- a/src/mount.c
+++ /dev/null
@@ -1,1930 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 "mkdir.h"
-#include "mount-setup.h"
-#include "unit-name.h"
-#include "dbus-mount.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "def.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_RELOADING,
-        [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
-        [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
-        [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
-        [MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
-        [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
-        [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
-        [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
-        [MOUNT_FAILED] = UNIT_FAILED
-};
-
-static void mount_init(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        m->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        m->directory_mode = 0755;
-
-        exec_context_init(&m->exec_context);
-
-        /* The stdio/kmsg bridge socket is on /, in order to avoid a
-         * dep loop, don't use kmsg logging for -.mount */
-        if (!unit_has_name(u, "-.mount")) {
-                m->exec_context.std_output = u->manager->default_std_output;
-                m->exec_context.std_error = u->manager->default_std_error;
-        }
-
-        /* 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.same_pgrp = true;
-
-        m->timer_watch.type = WATCH_INVALID;
-
-        m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-
-        UNIT(m)->ignore_on_isolate = true;
-}
-
-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 MountParameters* get_mount_parameters_configured(Mount *m) {
-        assert(m);
-
-        if (m->from_fragment)
-                return &m->parameters_fragment;
-        else if (m->from_etc_fstab)
-                return &m->parameters_etc_fstab;
-
-        return NULL;
-}
-
-static MountParameters* get_mount_parameters(Mount *m) {
-        assert(m);
-
-        if (m->from_proc_self_mountinfo)
-                return &m->parameters_proc_self_mountinfo;
-
-        return get_mount_parameters_configured(m);
-}
-
-static int mount_add_mount_links(Mount *m) {
-        Unit *other;
-        int r;
-        MountParameters *pm;
-
-        assert(m);
-
-        pm = get_mount_parameters_configured(m);
-
-        /* Adds in links to other mount points that might lie below or
-         * above us in the hierarchy */
-
-        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_MOUNT]) {
-                Mount *n = MOUNT(other);
-                MountParameters *pn;
-
-                if (n == m)
-                        continue;
-
-                if (UNIT(n)->load_state != UNIT_LOADED)
-                        continue;
-
-                pn = get_mount_parameters_configured(n);
-
-                if (path_startswith(m->where, n->where)) {
-
-                        if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
-                                return r;
-
-                        if (pn)
-                                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(n), UNIT_AFTER, UNIT(m), true)) < 0)
-                                return r;
-
-                        if (pm)
-                                if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
-                                        return r;
-
-                } else if (pm && pm->what && path_startswith(pm->what, n->where)) {
-
-                        if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
-                                return r;
-
-                        if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
-                                return r;
-
-                } else if (pn && pn->what && path_startswith(pn->what, m->where)) {
-
-                        if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
-                                return r;
-
-                        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) {
-        Unit *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP])
-                if ((r = swap_add_one_mount_link(SWAP(other), m)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int mount_add_path_links(Mount *m) {
-        Unit *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH])
-                if ((r = path_add_one_mount_link(PATH(other), m)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int mount_add_automount_links(Mount *m) {
-        Unit *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_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) {
-        Unit *other;
-        int r;
-
-        assert(m);
-
-        LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_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 NULL;
-
-        zero(me);
-        me.mnt_opts = (char*) haystack;
-
-        return hasmntopt(&me, needle);
-}
-
-static bool mount_is_network(MountParameters *p) {
-        assert(p);
-
-        if (mount_test_option(p->options, "_netdev"))
-                return true;
-
-        if (p->fstype && fstype_is_network(p->fstype))
-                return true;
-
-        return false;
-}
-
-static bool mount_is_bind(MountParameters *p) {
-        assert(p);
-
-        if (mount_test_option(p->options, "bind"))
-                return true;
-
-        if (p->fstype && streq(p->fstype, "bind"))
-                return true;
-
-        return false;
-}
-
-static bool needs_quota(MountParameters *p) {
-        assert(p);
-
-        if (mount_is_network(p))
-                return false;
-
-        if (mount_is_bind(p))
-                return false;
-
-        return mount_test_option(p->options, "usrquota") ||
-                mount_test_option(p->options, "grpquota") ||
-                mount_test_option(p->options, "quota") ||
-                mount_test_option(p->options, "usrjquota") ||
-                mount_test_option(p->options, "grpjquota");
-}
-
-static int mount_add_fstab_links(Mount *m) {
-        const char *target, *after, *tu_wants = NULL;
-        MountParameters *p;
-        Unit *tu;
-        int r;
-        bool noauto, nofail, handle, automount;
-
-        assert(m);
-
-        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
-                return 0;
-
-        if (!(p = get_mount_parameters_configured(m)))
-                return 0;
-
-        if (p != &m->parameters_etc_fstab)
-                return 0;
-
-        noauto = !!mount_test_option(p->options, "noauto");
-        nofail = !!mount_test_option(p->options, "nofail");
-        automount =
-                mount_test_option(p->options, "comment=systemd.automount") ||
-                mount_test_option(p->options, "x-systemd-automount");
-        handle =
-                automount ||
-                mount_test_option(p->options, "comment=systemd.mount") ||
-                mount_test_option(p->options, "x-systemd-mount") ||
-                UNIT(m)->manager->mount_auto;
-
-        if (mount_is_network(p)) {
-                target = SPECIAL_REMOTE_FS_TARGET;
-                after = tu_wants = SPECIAL_REMOTE_FS_PRE_TARGET;
-        } else {
-                target = SPECIAL_LOCAL_FS_TARGET;
-                after = SPECIAL_LOCAL_FS_PRE_TARGET;
-        }
-
-        r = manager_load_unit(UNIT(m)->manager, target, NULL, NULL, &tu);
-        if (r < 0)
-                return r;
-
-        if (tu_wants) {
-                r = unit_add_dependency_by_name(tu, UNIT_WANTS, tu_wants, NULL, true);
-                if (r < 0)
-                        return r;
-        }
-
-        if (after) {
-                r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
-                if (r < 0)
-                        return r;
-        }
-
-        if (automount) {
-                Unit *am;
-
-                if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0)
-                        return r;
-
-                /* If auto is configured as well also pull in the
-                 * mount right-away, but don't rely on it. */
-                if (!noauto) /* automount + auto */
-                        if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0)
-                                return r;
-
-                /* Install automount unit */
-                if (!nofail) /* automount + fail */
-                        return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, am, true);
-                else /* automount + nofail */
-                        return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_WANTS, am, true);
-
-        } else if (handle && !noauto) {
-
-                /* Automatically add mount points that aren't natively
-                 * configured to local-fs.target */
-
-                if (!nofail) /* auto + fail */
-                        return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
-                else /* auto + nofail */
-                        return unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true);
-        }
-
-        return 0;
-}
-
-static int mount_add_device_links(Mount *m) {
-        MountParameters *p;
-        int r;
-
-        assert(m);
-
-        if (!(p = get_mount_parameters_configured(m)))
-                return 0;
-
-        if (!p->what)
-                return 0;
-
-        if (!mount_is_bind(p) &&
-            !path_equal(m->where, "/") &&
-            p == &m->parameters_etc_fstab) {
-                bool nofail, noauto;
-
-                noauto = !!mount_test_option(p->options, "noauto");
-                nofail = !!mount_test_option(p->options, "nofail");
-
-                if ((r = unit_add_node_link(UNIT(m), p->what,
-                                            !noauto && nofail &&
-                                            UNIT(m)->manager->running_as == MANAGER_SYSTEM)) < 0)
-                        return r;
-        }
-
-        if (p->passno > 0 &&
-            !mount_is_bind(p) &&
-            UNIT(m)->manager->running_as == MANAGER_SYSTEM &&
-            !path_equal(m->where, "/")) {
-                char *name;
-                Unit *fsck;
-                /* Let's add in the fsck service */
-
-                /* aka SPECIAL_FSCK_SERVICE */
-                if (!(name = unit_name_from_path_instance("fsck", p->what, ".service")))
-                        return -ENOMEM;
-
-                if ((r = manager_load_unit_prepare(UNIT(m)->manager, name, NULL, NULL, &fsck)) < 0) {
-                        log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
-                        free(name);
-                        return r;
-                }
-
-                free(name);
-
-                SERVICE(fsck)->fsck_passno = p->passno;
-
-                if ((r = unit_add_two_dependencies(UNIT(m), UNIT_AFTER, UNIT_REQUIRES, fsck, true)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int mount_add_default_dependencies(Mount *m) {
-        int r;
-        MountParameters *p;
-
-        assert(m);
-
-        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
-                return 0;
-
-        p = get_mount_parameters_configured(m);
-        if (p && needs_quota(p)) {
-                if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true)) < 0 ||
-                    (r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true)) < 0)
-                        return r;
-        }
-
-        if (!path_equal(m->where, "/"))
-                if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int mount_fix_timeouts(Mount *m) {
-        MountParameters *p;
-        const char *timeout = NULL;
-        Unit *other;
-        Iterator i;
-        usec_t u;
-        char *t;
-        int r;
-
-        assert(m);
-
-        if (!(p = get_mount_parameters_configured(m)))
-                return 0;
-
-        /* Allow configuration how long we wait for a device that
-         * backs a mount point to show up. This is useful to support
-         * endless device timeouts for devices that show up only after
-         * user input, like crypto devices. */
-
-        if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout")))
-                timeout += 31;
-        else if ((timeout = mount_test_option(p->options, "x-systemd-device-timeout")))
-                timeout += 25;
-        else
-                return 0;
-
-        t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE));
-        if (!t)
-                return -ENOMEM;
-
-        r = parse_usec(t, &u);
-        free(t);
-
-        if (r < 0) {
-                log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout);
-                return r;
-        }
-
-        SET_FOREACH(other, UNIT(m)->dependencies[UNIT_AFTER], i) {
-                if (other->type != UNIT_DEVICE)
-                        continue;
-
-                other->job_timeout = u;
-        }
-
-        return 0;
-}
-
-static int mount_verify(Mount *m) {
-        bool b;
-        char *e;
-        assert(m);
-
-        if (UNIT(m)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!m->from_etc_fstab && !m->from_fragment && !m->from_proc_self_mountinfo)
-                return -ENOENT;
-
-        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)->id);
-                return -EINVAL;
-        }
-
-        if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
-                log_error("Cannot create mount unit for API file system %s. Refusing.", m->where);
-                return -EINVAL;
-        }
-
-        if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
-                log_error("%s's What setting is missing. Refusing.", UNIT(m)->id);
-                return -EBADMSG;
-        }
-
-        if (m->exec_context.pam_name && m->exec_context.kill_mode != KILL_CONTROL_GROUP) {
-                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int mount_load(Unit *u) {
-        Mount *m = MOUNT(u);
-        int r;
-
-        assert(u);
-        assert(u->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->load_state == UNIT_LOADED) {
-                if ((r = unit_add_exec_dependencies(u, &m->exec_context)) < 0)
-                        return r;
-
-                if (UNIT(m)->fragment_path)
-                        m->from_fragment = true;
-                else if (m->from_etc_fstab)
-                        /* We always add several default dependencies to fstab mounts,
-                         * but we do not want the implicit complementing of Wants= with After=
-                         * in the target unit that this mount unit will be hooked into. */
-                        UNIT(m)->default_dependencies = false;
-
-                if (!m->where)
-                        if (!(m->where = unit_name_to_path(u->id)))
-                                return -ENOMEM;
-
-                path_kill_slashes(m->where);
-
-                if (!UNIT(m)->description)
-                        if ((r = unit_set_description(u, m->where)) < 0)
-                                return r;
-
-                if ((r = mount_add_device_links(m)) < 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_path_links(m)) < 0)
-                        return r;
-
-                if ((r = mount_add_automount_links(m)) < 0)
-                        return r;
-
-                if ((r = mount_add_fstab_links(m)) < 0)
-                        return r;
-
-                if (UNIT(m)->default_dependencies || m->from_etc_fstab)
-                        if ((r = mount_add_default_dependencies(m)) < 0)
-                                return r;
-
-                if ((r = unit_add_default_cgroups(u)) < 0)
-                        return r;
-
-                mount_fix_timeouts(m);
-        }
-
-        return mount_verify(m);
-}
-
-static int mount_notify_automount(Mount *m, int status) {
-        Unit *p;
-        int r;
-        Iterator i;
-
-        assert(m);
-
-        SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
-                if (p->type == UNIT_AUTOMOUNT) {
-                         r = automount_send_ready(AUTOMOUNT(p), status);
-                         if (r < 0)
-                                 return r;
-                }
-
-        return 0;
-}
-
-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_FAILED)
-                mount_notify_automount(m, -ENODEV);
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(m)->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], m->reload_result == MOUNT_SUCCESS);
-        m->reload_result = MOUNT_SUCCESS;
-}
-
-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);
-
-        p = get_mount_parameters(m);
-
-        fprintf(f,
-                "%sMount State: %s\n"
-                "%sResult: %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"
-                "%sDirectoryMode: %04o\n",
-                prefix, mount_state_to_string(m->state),
-                prefix, mount_result_to_string(m->result),
-                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, m->directory_mode);
-
-        if (m->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %lu\n",
-                        prefix, (unsigned 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,
-                            UNIT(m)->manager->environment,
-                            true,
-                            true,
-                            true,
-                            UNIT(m)->manager->confirm_spawn,
-                            UNIT(m)->cgroup_bondings,
-                            UNIT(m)->cgroup_attributes,
-                            &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, MountResult f) {
-        assert(m);
-
-        if (f != MOUNT_SUCCESS)
-                m->result = f;
-
-        mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
-}
-
-static void mount_enter_mounted(Mount *m, MountResult f) {
-        assert(m);
-
-        if (f != MOUNT_SUCCESS)
-                m->result = f;
-
-        mount_set_state(m, MOUNT_MOUNTED);
-}
-
-static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
-        int r;
-        Set *pid_set = NULL;
-        bool wait_for_exit = false;
-
-        assert(m);
-
-        if (f != MOUNT_SUCCESS)
-                m->result = f;
-
-        if (m->exec_context.kill_mode != KILL_NONE) {
-                int sig = (state == MOUNT_MOUNTING_SIGTERM ||
-                           state == MOUNT_UNMOUNTING_SIGTERM ||
-                           state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL;
-
-                if (m->control_pid > 0) {
-                        if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
-
-                                log_warning("Failed to kill control process %li: %m", (long) m->control_pid);
-                        else
-                                wait_for_exit = true;
-                }
-
-                if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) {
-
-                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        /* Exclude the control pid from being killed via the cgroup */
-                        if (m->control_pid > 0)
-                                if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0)
-                                        goto fail;
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, pid_set)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
-                                        log_warning("Failed to kill control group: %s", strerror(-r));
-                        } else if (r > 0)
-                                wait_for_exit = true;
-
-                        set_free(pid_set);
-                        pid_set = NULL;
-                }
-        }
-
-        if (wait_for_exit) {
-                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, MOUNT_SUCCESS);
-        else
-                mount_enter_dead(m, MOUNT_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
-
-        if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
-                mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
-        else
-                mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-
-        if (pid_set)
-                set_free(pid_set);
-}
-
-static void mount_enter_unmounting(Mount *m) {
-        int r;
-
-        assert(m);
-
-        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' task: %s", UNIT(m)->id, strerror(-r));
-        mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static void mount_enter_mounting(Mount *m) {
-        int r;
-        MountParameters *p;
-
-        assert(m);
-
-        m->control_command_id = MOUNT_EXEC_MOUNT;
-        m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
-
-        mkdir_p(m->where, m->directory_mode);
-
-        /* Create the source directory for bind-mounts if needed */
-        p = get_mount_parameters_configured(m);
-        if (p && mount_is_bind(p))
-                mkdir_p(p->what, m->directory_mode);
-
-        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.fstype : "auto",
-                                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' task: %s", UNIT(m)->id, strerror(-r));
-        mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static void mount_enter_mounting_done(Mount *m) {
-        assert(m);
-
-        mount_set_state(m, MOUNT_MOUNTING_DONE);
-}
-
-static void mount_enter_remounting(Mount *m) {
-        int r;
-
-        assert(m);
-
-        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 ? m->parameters_fragment.fstype : "auto",
-                                "-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)
-                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:
-        log_warning("%s failed to run 'remount' task: %s", UNIT(m)->id, strerror(-r));
-        m->reload_result = MOUNT_FAILURE_RESOURCES;
-        mount_enter_mounted(m, MOUNT_SUCCESS);
-}
-
-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 ||
-            m->state == MOUNT_MOUNTING_SIGTERM ||
-            m->state == MOUNT_MOUNTING_SIGKILL)
-                return -EAGAIN;
-
-        /* Already on it! */
-        if (m->state == MOUNT_MOUNTING)
-                return 0;
-
-        assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
-
-        m->result = MOUNT_SUCCESS;
-        m->reload_result = MOUNT_SUCCESS;
-
-        mount_enter_mounting(m);
-        return 0;
-}
-
-static int mount_stop(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        /* Already on it */
-        if (m->state == MOUNT_UNMOUNTING ||
-            m->state == MOUNT_UNMOUNTING_SIGKILL ||
-            m->state == MOUNT_UNMOUNTING_SIGTERM ||
-            m->state == MOUNT_MOUNTING_SIGTERM ||
-            m->state == MOUNT_MOUNTING_SIGKILL)
-                return 0;
-
-        assert(m->state == MOUNT_MOUNTING ||
-               m->state == MOUNT_MOUNTING_DONE ||
-               m->state == MOUNT_MOUNTED ||
-               m->state == MOUNT_REMOUNTING ||
-               m->state == MOUNT_REMOUNTING_SIGTERM ||
-               m->state == MOUNT_REMOUNTING_SIGKILL);
-
-        mount_enter_unmounting(m);
-        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);
-        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, "result", mount_result_to_string(m->result));
-        unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result));
-
-        if (m->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) 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);
-
-        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, "result")) {
-                MountResult f;
-
-                f = mount_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != MOUNT_SUCCESS)
-                        m->result = f;
-
-        } else if (streq(key, "reload-result")) {
-                MountResult f;
-
-                f = mount_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse reload result value %s", value);
-                else if (f != MOUNT_SUCCESS)
-                        m->reload_result = f;
-
-        } else if (streq(key, "control-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        m->control_pid = 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);
-        MountResult f;
-
-        assert(m);
-        assert(pid >= 0);
-
-        if (pid != m->control_pid)
-                return;
-
-        m->control_pid = 0;
-
-        if (is_clean_exit(code, status))
-                f = MOUNT_SUCCESS;
-        else if (code == CLD_EXITED)
-                f = MOUNT_FAILURE_EXIT_CODE;
-        else if (code == CLD_KILLED)
-                f = MOUNT_FAILURE_SIGNAL;
-        else if (code == CLD_DUMPED)
-                f = MOUNT_FAILURE_CORE_DUMP;
-        else
-                assert_not_reached("Unknown code");
-
-        if (f != MOUNT_SUCCESS)
-                m->result = f;
-
-        if (m->control_command) {
-                exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status);
-
-                m->control_command = NULL;
-                m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-        }
-
-        log_full(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
-                 "%s mount process exited, code=%s status=%i", u->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:
-
-                if (f == MOUNT_SUCCESS)
-                        mount_enter_mounted(m, f);
-                else if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, f);
-                else
-                        mount_enter_dead(m, f);
-                break;
-
-        case MOUNT_REMOUNTING:
-        case MOUNT_REMOUNTING_SIGKILL:
-        case MOUNT_REMOUNTING_SIGTERM:
-
-                m->reload_result = f;
-                if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, MOUNT_SUCCESS);
-                else
-                        mount_enter_dead(m, MOUNT_SUCCESS);
-
-                break;
-
-        case MOUNT_UNMOUNTING:
-        case MOUNT_UNMOUNTING_SIGKILL:
-        case MOUNT_UNMOUNTING_SIGTERM:
-
-                if (f == MOUNT_SUCCESS)
-                        mount_enter_dead(m, f);
-                else if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, f);
-                else
-                        mount_enter_dead(m, f);
-                break;
-
-        default:
-                assert_not_reached("Uh, control process died at wrong time.");
-        }
-
-        /* Notify clients about changed exit status */
-        unit_add_to_dbus_queue(u);
-}
-
-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->id);
-                mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
-                break;
-
-        case MOUNT_REMOUNTING:
-                log_warning("%s remounting timed out. Stopping.", u->id);
-                m->reload_result = MOUNT_FAILURE_TIMEOUT;
-                mount_enter_mounted(m, MOUNT_SUCCESS);
-                break;
-
-        case MOUNT_UNMOUNTING:
-                log_warning("%s unmounting timed out. Stopping.", u->id);
-                mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
-                break;
-
-        case MOUNT_MOUNTING_SIGTERM:
-                if (m->exec_context.send_sigkill) {
-                        log_warning("%s mounting timed out. Killing.", u->id);
-                        mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->id);
-
-                        if (m->from_proc_self_mountinfo)
-                                mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
-                        else
-                                mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case MOUNT_REMOUNTING_SIGTERM:
-                if (m->exec_context.send_sigkill) {
-                        log_warning("%s remounting timed out. Killing.", u->id);
-                        mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->id);
-
-                        if (m->from_proc_self_mountinfo)
-                                mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
-                        else
-                                mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case MOUNT_UNMOUNTING_SIGTERM:
-                if (m->exec_context.send_sigkill) {
-                        log_warning("%s unmounting timed out. Killing.", u->id);
-                        mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->id);
-
-                        if (m->from_proc_self_mountinfo)
-                                mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
-                        else
-                                mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case MOUNT_MOUNTING_SIGKILL:
-        case MOUNT_REMOUNTING_SIGKILL:
-        case MOUNT_UNMOUNTING_SIGKILL:
-                log_warning("%s mount process still around after SIGKILL. Ignoring.", u->id);
-
-                if (m->from_proc_self_mountinfo)
-                        mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
-                else
-                        mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
-                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,
-                int passno,
-                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) || mount_point_ignore(where))
-                return 0;
-
-        if (streq(fstype, "autofs"))
-                return 0;
-
-        /* probably some kind of swap, ignore */
-        if (!is_path(where))
-                return 0;
-
-        e = unit_name_from_path(where, ".mount");
-        if (!e)
-                return -ENOMEM;
-
-        u = manager_get_unit(m, e);
-        if (!u) {
-                delete = true;
-
-                u = unit_new(m, sizeof(Mount));
-                if (!u) {
-                        free(e);
-                        return -ENOMEM;
-                }
-
-                r = unit_add_name(u, e);
-                free(e);
-
-                if (r < 0)
-                        goto fail;
-
-                MOUNT(u)->where = strdup(where);
-                if (!MOUNT(u)->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;
-
-        p->passno = passno;
-
-        unit_add_to_dbus_queue(u);
-
-        return 0;
-
-fail:
-        free(w);
-        free(o);
-        free(f);
-
-        if (delete && u)
-                unit_free(u);
-
-        return r;
-}
-
-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 = 0;
-        struct mntent* me;
-
-        assert(m);
-
-        errno = 0;
-        if (!(f = setmntent("/etc/fstab", "r")))
-                return -errno;
-
-        while ((me = getmntent(f))) {
-                char *where, *what;
-                int k;
-
-                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)
-                                k = pri;
-                        else
-                                k = swap_add_one(m,
-                                                 what,
-                                                 NULL,
-                                                 pri,
-                                                 !!mount_test_option(me->mnt_opts, "noauto"),
-                                                 !!mount_test_option(me->mnt_opts, "nofail"),
-                                                 !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"),
-                                                 false);
-                } else
-                        k = mount_add_one(m, what, where, me->mnt_opts, me->mnt_type, me->mnt_passno, false, false);
-
-                free(what);
-                free(where);
-
-                if (k < 0)
-                        r = k;
-        }
-
-finish:
-
-        endmntent(f);
-        return r;
-}
-
-static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
-        int r = 0;
-        unsigned i;
-        char *device, *path, *options, *options2, *fstype, *d, *p, *o;
-
-        assert(m);
-
-        rewind(m->proc_self_mountinfo);
-
-        for (i = 1;; i++) {
-                int k;
-
-                device = path = options = options2 = fstype = d = p = o = 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) separator */
-                                "%ms "       /* (9) file system type */
-                                "%ms"        /* (10) mount source */
-                                "%ms"        /* (11) mount options 2 */
-                                "%*[^\n]",   /* some rubbish at the end */
-                                &path,
-                                &options,
-                                &fstype,
-                                &device,
-                                &options2)) != 5) {
-
-                        if (k == EOF)
-                                break;
-
-                        log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
-                        goto clean_up;
-                }
-
-                if (asprintf(&o, "%s,%s", options, options2) < 0) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(d = cunescape(device)) ||
-                    !(p = cunescape(path))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if ((k = mount_add_one(m, d, p, o, fstype, 0, true, set_flags)) < 0)
-                        r = k;
-
-clean_up:
-                free(device);
-                free(path);
-                free(options);
-                free(options2);
-                free(fstype);
-                free(d);
-                free(p);
-                free(o);
-        }
-
-finish:
-        free(device);
-        free(path);
-        free(options);
-        free(options2);
-        free(fstype);
-        free(d);
-        free(p);
-        free(o);
-
-        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 = EPOLLPRI;
-                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) {
-        Unit *u;
-        int r;
-
-        assert(m);
-        assert(events & EPOLLPRI);
-
-        /* 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(-r));
-
-                /* Reset flags, just in case, for later calls */
-                LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
-                        Mount *mount = MOUNT(u);
-
-                        mount->is_mounted = mount->just_mounted = mount->just_changed = false;
-                }
-
-                return;
-        }
-
-        manager_dispatch_load_queue(m);
-
-        LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
-                Mount *mount = MOUNT(u);
-
-                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, MOUNT_SUCCESS);
-                                break;
-
-                        default:
-                                mount_set_state(mount, mount->state);
-                                break;
-
-                        }
-
-                } else if (mount->just_mounted || mount->just_changed) {
-
-                        /* New or changed mount entry */
-
-                        switch (mount->state) {
-
-                        case MOUNT_DEAD:
-                        case MOUNT_FAILED:
-                                mount_enter_mounted(mount, MOUNT_SUCCESS);
-                                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;
-        }
-}
-
-static void mount_reset_failed(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        if (m->state == MOUNT_FAILED)
-                mount_set_state(m, MOUNT_DEAD);
-
-        m->result = MOUNT_SUCCESS;
-        m->reload_result = MOUNT_SUCCESS;
-}
-
-static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
-        Mount *m = MOUNT(u);
-        int r = 0;
-        Set *pid_set = NULL;
-
-        assert(m);
-
-        if (who == KILL_MAIN) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes");
-                return -ESRCH;
-        }
-
-        if (m->control_pid <= 0 && who == KILL_CONTROL) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
-                return -ESRCH;
-        }
-
-        if (who == KILL_CONTROL || who == KILL_ALL)
-                if (m->control_pid > 0)
-                        if (kill(m->control_pid, signo) < 0)
-                                r = -errno;
-
-        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
-                int q;
-
-                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
-                        return -ENOMEM;
-
-                /* Exclude the control pid from being killed via the cgroup */
-                if (m->control_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) {
-                                r = q;
-                                goto finish;
-                        }
-
-                if ((q = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, signo, false, pid_set)) < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
-        }
-
-finish:
-        if (pid_set)
-                set_free(pid_set);
-
-        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_FAILED] = "failed"
-};
-
-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);
-
-static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
-        [MOUNT_SUCCESS] = "success",
-        [MOUNT_FAILURE_RESOURCES] = "resources",
-        [MOUNT_FAILURE_TIMEOUT] = "timeout",
-        [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
-        [MOUNT_FAILURE_SIGNAL] = "signal",
-        [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
-
-const UnitVTable mount_vtable = {
-        .suffix = ".mount",
-        .object_size = sizeof(Mount),
-        .sections =
-                "Unit\0"
-                "Mount\0"
-                "Install\0",
-
-        .no_alias = true,
-        .no_instances = true,
-        .show_status = 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,
-
-        .kill = mount_kill,
-
-        .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,
-
-        .reset_failed = mount_reset_failed,
-
-        .bus_interface = "org.freedesktop.systemd1.Mount",
-        .bus_message_handler = bus_mount_message_handler,
-        .bus_invalidating_properties =  bus_mount_invalidating_properties,
-
-        .enumerate = mount_enumerate,
-        .shutdown = mount_shutdown
-};
diff --git a/src/mount.h b/src/mount.h
deleted file mode 100644
index 9318444..0000000
--- a/src/mount.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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_FAILED,
-        _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;
-        int passno;
-} MountParameters;
-
-typedef enum MountResult {
-        MOUNT_SUCCESS,
-        MOUNT_FAILURE_RESOURCES,
-        MOUNT_FAILURE_TIMEOUT,
-        MOUNT_FAILURE_EXIT_CODE,
-        MOUNT_FAILURE_SIGNAL,
-        MOUNT_FAILURE_CORE_DUMP,
-        _MOUNT_RESULT_MAX,
-        _MOUNT_RESULT_INVALID = -1
-} MountResult;
-
-struct Mount {
-        Unit 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;
-
-        MountResult result;
-        MountResult reload_result;
-
-        mode_t directory_mode;
-
-        usec_t timeout_usec;
-
-        ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        MountState state, deserialized_state;
-
-        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);
-
-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);
-
-const char* mount_result_to_string(MountResult i);
-MountResult mount_result_from_string(const char *s);
-
-#endif
diff --git a/src/namespace.c b/src/namespace.c
deleted file mode 100644
index 09bc829..0000000
--- a/src/namespace.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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;
-
-        default:
-                assert_not_reached("Unknown mode");
-        }
-
-        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 independent step. */
-                if (flags)
-                        r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_REC|flags, NULL);
-
-                /* Avoid exponential 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) {
-                mode_t u;
-
-                memcpy(private_dir, tmp_dir, sizeof(tmp_dir)-1);
-
-                u = umask(0000);
-                if (mkdir(private_dir, 0777 + S_ISVTX) < 0) {
-                        umask(u);
-
-                        r = -errno;
-                        goto fail;
-                }
-
-                umask(u);
-                remove_private = true;
-        }
-
-        if (unshare(CLONE_NEWNS) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* Remount / as SLAVE so that nothing mounted in the namespace
-           shows up in the parent */
-        if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        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
deleted file mode 100644
index 7cf1ded..0000000
--- a/src/namespace.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/path.c b/src/path.c
deleted file mode 100644
index 1d50885..0000000
--- a/src/path.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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/inotify.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "unit.h"
-#include "unit-name.h"
-#include "path.h"
-#include "mkdir.h"
-#include "dbus-path.h"
-#include "special.h"
-#include "bus-errors.h"
-
-static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
-        [PATH_DEAD] = UNIT_INACTIVE,
-        [PATH_WAITING] = UNIT_ACTIVE,
-        [PATH_RUNNING] = UNIT_ACTIVE,
-        [PATH_FAILED] = UNIT_FAILED
-};
-
-int path_spec_watch(PathSpec *s, Unit *u) {
-
-        static const int flags_table[_PATH_TYPE_MAX] = {
-                [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
-                [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
-                [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
-                [PATH_MODIFIED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO|IN_MODIFY,
-                [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
-        };
-
-        bool exists = false;
-        char *k, *slash;
-        int r;
-
-        assert(u);
-        assert(s);
-
-        path_spec_unwatch(s, u);
-
-        if (!(k = strdup(s->path)))
-                return -ENOMEM;
-
-        if ((s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if (unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if ((s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type])) >= 0)
-                exists = true;
-
-        do {
-                int flags;
-
-                /* This assumes the path was passed through path_kill_slashes()! */
-                if (!(slash = strrchr(k, '/')))
-                        break;
-
-                /* Trim the path at the last slash. Keep the slash if it's the root dir. */
-                slash[slash == k] = 0;
-
-                flags = IN_MOVE_SELF;
-                if (!exists)
-                        flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
-
-                if (inotify_add_watch(s->inotify_fd, k, flags) >= 0)
-                        exists = true;
-        } while (slash != k);
-
-        return 0;
-
-fail:
-        free(k);
-
-        path_spec_unwatch(s, u);
-        return r;
-}
-
-void path_spec_unwatch(PathSpec *s, Unit *u) {
-
-        if (s->inotify_fd < 0)
-                return;
-
-        unit_unwatch_fd(u, &s->watch);
-
-        close_nointr_nofail(s->inotify_fd);
-        s->inotify_fd = -1;
-}
-
-int path_spec_fd_event(PathSpec *s, uint32_t events) {
-        uint8_t *buf = NULL;
-        struct inotify_event *e;
-        ssize_t k;
-        int l;
-        int r = 0;
-
-        if (events != EPOLLIN) {
-                log_error("Got Invalid poll event on inotify.");
-                r = -EINVAL;
-                goto out;
-        }
-
-        if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) {
-                log_error("FIONREAD failed: %m");
-                r = -errno;
-                goto out;
-        }
-
-        assert(l > 0);
-
-        if (!(buf = malloc(l))) {
-                log_error("Failed to allocate buffer: %m");
-                r = -errno;
-                goto out;
-        }
-
-        if ((k = read(s->inotify_fd, buf, l)) < 0) {
-                log_error("Failed to read inotify event: %m");
-                r = -errno;
-                goto out;
-        }
-
-        e = (struct inotify_event*) buf;
-
-        while (k > 0) {
-                size_t step;
-
-                if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
-                    s->primary_wd == e->wd)
-                        r = 1;
-
-                step = sizeof(struct inotify_event) + e->len;
-                assert(step <= (size_t) k);
-
-                e = (struct inotify_event*) ((uint8_t*) e + step);
-                k -= step;
-        }
-out:
-        free(buf);
-        return r;
-}
-
-static bool path_spec_check_good(PathSpec *s, bool initial) {
-        bool good = false;
-
-        switch (s->type) {
-
-        case PATH_EXISTS:
-                good = access(s->path, F_OK) >= 0;
-                break;
-
-        case PATH_EXISTS_GLOB:
-                good = glob_exists(s->path) > 0;
-                break;
-
-        case PATH_DIRECTORY_NOT_EMPTY: {
-                int k;
-
-                k = dir_is_empty(s->path);
-                good = !(k == -ENOENT || k > 0);
-                break;
-        }
-
-        case PATH_CHANGED:
-        case PATH_MODIFIED: {
-                bool b;
-
-                b = access(s->path, F_OK) >= 0;
-                good = !initial && b != s->previous_exists;
-                s->previous_exists = b;
-                break;
-        }
-
-        default:
-                ;
-        }
-
-        return good;
-}
-
-static bool path_spec_startswith(PathSpec *s, const char *what) {
-        return path_startswith(s->path, what);
-}
-
-static void path_spec_mkdir(PathSpec *s, mode_t mode) {
-        int r;
-
-        if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
-                return;
-
-        if ((r = mkdir_p(s->path, mode)) < 0)
-                log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
-}
-
-static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
-        fprintf(f,
-                "%s%s: %s\n",
-                prefix,
-                path_type_to_string(s->type),
-                s->path);
-}
-
-void path_spec_done(PathSpec *s) {
-        assert(s);
-        assert(s->inotify_fd == -1);
-
-        free(s->path);
-}
-
-static void path_init(Unit *u) {
-        Path *p = PATH(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        p->directory_mode = 0755;
-}
-
-static void path_done(Unit *u) {
-        Path *p = PATH(u);
-        PathSpec *s;
-
-        assert(p);
-
-        unit_ref_unset(&p->unit);
-
-        while ((s = p->specs)) {
-                path_spec_unwatch(s, u);
-                LIST_REMOVE(PathSpec, spec, p->specs, s);
-                path_spec_done(s);
-                free(s);
-        }
-}
-
-int path_add_one_mount_link(Path *p, Mount *m) {
-        PathSpec *s;
-        int r;
-
-        assert(p);
-        assert(m);
-
-        if (UNIT(p)->load_state != UNIT_LOADED ||
-            UNIT(m)->load_state != UNIT_LOADED)
-                return 0;
-
-        LIST_FOREACH(spec, s, p->specs) {
-
-                if (!path_spec_startswith(s, m->where))
-                        continue;
-
-                if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int path_add_mount_links(Path *p) {
-        Unit *other;
-        int r;
-
-        assert(p);
-
-        LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT])
-                if ((r = path_add_one_mount_link(p, MOUNT(other))) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int path_verify(Path *p) {
-        assert(p);
-
-        if (UNIT(p)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!p->specs) {
-                log_error("%s lacks path setting. Refusing.", UNIT(p)->id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int path_add_default_dependencies(Path *p) {
-        int r;
-
-        assert(p);
-
-        if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
-                if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
-                        return r;
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
-                        return r;
-        }
-
-        return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int path_load(Unit *u) {
-        Path *p = PATH(u);
-        int r;
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        if ((r = unit_load_fragment_and_dropin(u)) < 0)
-                return r;
-
-        if (u->load_state == UNIT_LOADED) {
-
-                if (!UNIT_DEREF(p->unit)) {
-                        Unit *x;
-
-                        r = unit_load_related_unit(u, ".service", &x);
-                        if (r < 0)
-                                return r;
-
-                        unit_ref_set(&p->unit, x);
-                }
-
-                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
-                if (r < 0)
-                        return r;
-
-                if ((r = path_add_mount_links(p)) < 0)
-                        return r;
-
-                if (UNIT(p)->default_dependencies)
-                        if ((r = path_add_default_dependencies(p)) < 0)
-                                return r;
-        }
-
-        return path_verify(p);
-}
-
-static void path_dump(Unit *u, FILE *f, const char *prefix) {
-        Path *p = PATH(u);
-        PathSpec *s;
-
-        assert(p);
-        assert(f);
-
-        fprintf(f,
-                "%sPath State: %s\n"
-                "%sResult: %s\n"
-                "%sUnit: %s\n"
-                "%sMakeDirectory: %s\n"
-                "%sDirectoryMode: %04o\n",
-                prefix, path_state_to_string(p->state),
-                prefix, path_result_to_string(p->result),
-                prefix, UNIT_DEREF(p->unit)->id,
-                prefix, yes_no(p->make_directory),
-                prefix, p->directory_mode);
-
-        LIST_FOREACH(spec, s, p->specs)
-                path_spec_dump(s, f, prefix);
-}
-
-static void path_unwatch(Path *p) {
-        PathSpec *s;
-
-        assert(p);
-
-        LIST_FOREACH(spec, s, p->specs)
-                path_spec_unwatch(s, UNIT(p));
-}
-
-static int path_watch(Path *p) {
-        int r;
-        PathSpec *s;
-
-        assert(p);
-
-        LIST_FOREACH(spec, s, p->specs)
-                if ((r = path_spec_watch(s, UNIT(p))) < 0)
-                        return r;
-
-        return 0;
-}
-
-static void path_set_state(Path *p, PathState state) {
-        PathState old_state;
-        assert(p);
-
-        old_state = p->state;
-        p->state = state;
-
-        if (state != PATH_WAITING &&
-            (state != PATH_RUNNING || p->inotify_triggered))
-                path_unwatch(p);
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(p)->id,
-                          path_state_to_string(old_state),
-                          path_state_to_string(state));
-
-        unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck);
-
-static int path_coldplug(Unit *u) {
-        Path *p = PATH(u);
-
-        assert(p);
-        assert(p->state == PATH_DEAD);
-
-        if (p->deserialized_state != p->state) {
-
-                if (p->deserialized_state == PATH_WAITING ||
-                    p->deserialized_state == PATH_RUNNING)
-                        path_enter_waiting(p, true, true);
-                else
-                        path_set_state(p, p->deserialized_state);
-        }
-
-        return 0;
-}
-
-static void path_enter_dead(Path *p, PathResult f) {
-        assert(p);
-
-        if (f != PATH_SUCCESS)
-                p->result = f;
-
-        path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
-}
-
-static void path_enter_running(Path *p) {
-        int r;
-        DBusError error;
-
-        assert(p);
-        dbus_error_init(&error);
-
-        /* Don't start job if we are supposed to go down */
-        if (UNIT(p)->job && UNIT(p)->job->type == JOB_STOP)
-                return;
-
-        if ((r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
-                goto fail;
-
-        p->inotify_triggered = false;
-
-        if ((r = path_watch(p)) < 0)
-                goto fail;
-
-        path_set_state(p, PATH_RUNNING);
-        return;
-
-fail:
-        log_warning("%s failed to queue unit startup job: %s", UNIT(p)->id, bus_error(&error, r));
-        path_enter_dead(p, PATH_FAILURE_RESOURCES);
-
-        dbus_error_free(&error);
-}
-
-static bool path_check_good(Path *p, bool initial) {
-        PathSpec *s;
-        bool good = false;
-
-        assert(p);
-
-        LIST_FOREACH(spec, s, p->specs) {
-                good = path_spec_check_good(s, initial);
-
-                if (good)
-                        break;
-        }
-
-        return good;
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck) {
-        int r;
-
-        if (recheck)
-                if (path_check_good(p, initial)) {
-                        log_debug("%s got triggered.", UNIT(p)->id);
-                        path_enter_running(p);
-                        return;
-                }
-
-        if ((r = path_watch(p)) < 0)
-                goto fail;
-
-        /* Hmm, so now we have created inotify watches, but the file
-         * might have appeared/been removed by now, so we must
-         * recheck */
-
-        if (recheck)
-                if (path_check_good(p, false)) {
-                        log_debug("%s got triggered.", UNIT(p)->id);
-                        path_enter_running(p);
-                        return;
-                }
-
-        path_set_state(p, PATH_WAITING);
-        return;
-
-fail:
-        log_warning("%s failed to enter waiting state: %s", UNIT(p)->id, strerror(-r));
-        path_enter_dead(p, PATH_FAILURE_RESOURCES);
-}
-
-static void path_mkdir(Path *p) {
-        PathSpec *s;
-
-        assert(p);
-
-        if (!p->make_directory)
-                return;
-
-        LIST_FOREACH(spec, s, p->specs)
-                path_spec_mkdir(s, p->directory_mode);
-}
-
-static int path_start(Unit *u) {
-        Path *p = PATH(u);
-
-        assert(p);
-        assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
-
-        if (UNIT_DEREF(p->unit)->load_state != UNIT_LOADED)
-                return -ENOENT;
-
-        path_mkdir(p);
-
-        p->result = PATH_SUCCESS;
-        path_enter_waiting(p, true, true);
-
-        return 0;
-}
-
-static int path_stop(Unit *u) {
-        Path *p = PATH(u);
-
-        assert(p);
-        assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
-
-        path_enter_dead(p, PATH_SUCCESS);
-        return 0;
-}
-
-static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Path *p = PATH(u);
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", path_state_to_string(p->state));
-        unit_serialize_item(u, f, "result", path_result_to_string(p->result));
-
-        return 0;
-}
-
-static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Path *p = PATH(u);
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                PathState state;
-
-                if ((state = path_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        p->deserialized_state = state;
-
-        } else if (streq(key, "result")) {
-                PathResult f;
-
-                f = path_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != PATH_SUCCESS)
-                        p->result = f;
-
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState path_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[PATH(u)->state];
-}
-
-static const char *path_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return path_state_to_string(PATH(u)->state);
-}
-
-static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
-        Path *p = PATH(u);
-        PathSpec *s;
-        int changed;
-
-        assert(p);
-        assert(fd >= 0);
-
-        if (p->state != PATH_WAITING &&
-            p->state != PATH_RUNNING)
-                return;
-
-        /* log_debug("inotify wakeup on %s.", u->id); */
-
-        LIST_FOREACH(spec, s, p->specs)
-                if (path_spec_owns_inotify_fd(s, fd))
-                        break;
-
-        if (!s) {
-                log_error("Got event on unknown fd.");
-                goto fail;
-        }
-
-        changed = path_spec_fd_event(s, events);
-        if (changed < 0)
-                goto fail;
-
-        /* If we are already running, then remember that one event was
-         * dispatched so that we restart the service only if something
-         * actually changed on disk */
-        p->inotify_triggered = true;
-
-        if (changed)
-                path_enter_running(p);
-        else
-                path_enter_waiting(p, false, true);
-
-        return;
-
-fail:
-        path_enter_dead(p, PATH_FAILURE_RESOURCES);
-}
-
-void path_unit_notify(Unit *u, UnitActiveState new_state) {
-        Iterator i;
-        Unit *k;
-
-        if (u->type == UNIT_PATH)
-                return;
-
-        SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
-                Path *p;
-
-                if (k->type != UNIT_PATH)
-                        continue;
-
-                if (k->load_state != UNIT_LOADED)
-                        continue;
-
-                p = PATH(k);
-
-                if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
-                        log_debug("%s got notified about unit deactivation.", UNIT(p)->id);
-
-                        /* Hmm, so inotify was triggered since the
-                         * last activation, so I guess we need to
-                         * recheck what is going on. */
-                        path_enter_waiting(p, false, p->inotify_triggered);
-                }
-        }
-}
-
-static void path_reset_failed(Unit *u) {
-        Path *p = PATH(u);
-
-        assert(p);
-
-        if (p->state == PATH_FAILED)
-                path_set_state(p, PATH_DEAD);
-
-        p->result = PATH_SUCCESS;
-}
-
-static const char* const path_state_table[_PATH_STATE_MAX] = {
-        [PATH_DEAD] = "dead",
-        [PATH_WAITING] = "waiting",
-        [PATH_RUNNING] = "running",
-        [PATH_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
-
-static const char* const path_type_table[_PATH_TYPE_MAX] = {
-        [PATH_EXISTS] = "PathExists",
-        [PATH_EXISTS_GLOB] = "PathExistsGlob",
-        [PATH_CHANGED] = "PathChanged",
-        [PATH_MODIFIED] = "PathModified",
-        [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
-
-static const char* const path_result_table[_PATH_RESULT_MAX] = {
-        [PATH_SUCCESS] = "success",
-        [PATH_FAILURE_RESOURCES] = "resources"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
-
-const UnitVTable path_vtable = {
-        .suffix = ".path",
-        .object_size = sizeof(Path),
-        .sections =
-                "Unit\0"
-                "Path\0"
-                "Install\0",
-
-        .init = path_init,
-        .done = path_done,
-        .load = path_load,
-
-        .coldplug = path_coldplug,
-
-        .dump = path_dump,
-
-        .start = path_start,
-        .stop = path_stop,
-
-        .serialize = path_serialize,
-        .deserialize_item = path_deserialize_item,
-
-        .active_state = path_active_state,
-        .sub_state_to_string = path_sub_state_to_string,
-
-        .fd_event = path_fd_event,
-
-        .reset_failed = path_reset_failed,
-
-        .bus_interface = "org.freedesktop.systemd1.Path",
-        .bus_message_handler = bus_path_message_handler,
-        .bus_invalidating_properties = bus_path_invalidating_properties
-};
diff --git a/src/path.h b/src/path.h
deleted file mode 100644
index efb6b5e..0000000
--- a/src/path.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foopathhfoo
-#define foopathhfoo
-
-/***
-  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 Path Path;
-
-#include "unit.h"
-#include "mount.h"
-
-typedef enum PathState {
-        PATH_DEAD,
-        PATH_WAITING,
-        PATH_RUNNING,
-        PATH_FAILED,
-        _PATH_STATE_MAX,
-        _PATH_STATE_INVALID = -1
-} PathState;
-
-typedef enum PathType {
-        PATH_EXISTS,
-        PATH_EXISTS_GLOB,
-        PATH_DIRECTORY_NOT_EMPTY,
-        PATH_CHANGED,
-        PATH_MODIFIED,
-        _PATH_TYPE_MAX,
-        _PATH_TYPE_INVALID = -1
-} PathType;
-
-typedef struct PathSpec {
-        char *path;
-
-        Watch watch;
-
-        LIST_FIELDS(struct PathSpec, spec);
-
-        PathType type;
-        int inotify_fd;
-        int primary_wd;
-
-        bool previous_exists;
-} PathSpec;
-
-int path_spec_watch(PathSpec *s, Unit *u);
-void path_spec_unwatch(PathSpec *s, Unit *u);
-int path_spec_fd_event(PathSpec *s, uint32_t events);
-void path_spec_done(PathSpec *s);
-
-static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
-        return s->inotify_fd == fd;
-}
-
-typedef enum PathResult {
-        PATH_SUCCESS,
-        PATH_FAILURE_RESOURCES,
-        _PATH_RESULT_MAX,
-        _PATH_RESULT_INVALID = -1
-} PathResult;
-
-struct Path {
-        Unit meta;
-
-        LIST_HEAD(PathSpec, specs);
-
-        UnitRef unit;
-
-        PathState state, deserialized_state;
-
-        bool inotify_triggered;
-
-        bool make_directory;
-        mode_t directory_mode;
-
-        PathResult result;
-};
-
-void path_unit_notify(Unit *u, UnitActiveState new_state);
-
-/* Called from the mount code figure out if a mount is a dependency of
- * any of the paths of this path object */
-int path_add_one_mount_link(Path *p, Mount *m);
-
-extern const UnitVTable path_vtable;
-
-const char* path_state_to_string(PathState i);
-PathState path_state_from_string(const char *s);
-
-const char* path_type_to_string(PathType i);
-PathType path_type_from_string(const char *s);
-
-const char* path_result_to_string(PathResult i);
-PathResult path_result_from_string(const char *s);
-
-#endif
diff --git a/src/polkit.h b/src/polkit.h
deleted file mode 100644
index 0d08194..0000000
--- a/src/polkit.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foopolkithfoo
-#define foopolkithfoo
-
-/***
-  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 <dbus/dbus.h>
-
-int verify_polkit(
-                DBusConnection *c,
-                DBusMessage *request,
-                const char *action,
-                bool interactive,
-                bool *challenge,
-                DBusError *error);
-
-#endif
diff --git a/src/securebits.h b/src/securebits.h
deleted file mode 100644
index ba0bba5..0000000
--- a/src/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 compatibility 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/selinux-setup.c b/src/selinux-setup.c
deleted file mode 100644
index a7e1fa4..0000000
--- a/src/selinux-setup.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#include "selinux-setup.h"
-#include "mount-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-#include "label.h"
-
-int selinux_setup(bool *loaded_policy) {
-
-#ifdef HAVE_SELINUX
-       int enforce = 0;
-       usec_t before_load, after_load;
-       security_context_t con;
-       int r;
-
-       assert(loaded_policy);
-
-       /* Make sure getcon() works, which needs /proc and /sys */
-       mount_setup_early();
-
-       /* Already initialized by somebody else? */
-       r = getcon_raw(&con);
-       if (r == 0) {
-               bool initialized;
-
-               initialized = !streq(con, "kernel");
-               freecon(con);
-
-               if (initialized)
-                       return 0;
-       }
-
-       /* Make sure we have no fds open while loading the policy and
-        * transitioning */
-       log_close();
-
-       /* Now load the policy */
-       before_load = now(CLOCK_MONOTONIC);
-       r = selinux_init_load_policy(&enforce);
-
-       if (r == 0) {
-               char timespan[FORMAT_TIMESPAN_MAX];
-               char *label;
-
-               label_retest_selinux();
-
-               /* Transition to the new context */
-               r = label_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
-               if (r < 0 || label == NULL) {
-                       log_open();
-                       log_error("Failed to compute init label, ignoring.");
-               } else {
-                       r = setcon(label);
-
-                       log_open();
-                       if (r < 0)
-                               log_error("Failed to transition into init label '%s', ignoring.", label);
-
-                       label_free(label);
-               }
-
-               after_load = now(CLOCK_MONOTONIC);
-
-               log_info("Successfully loaded SELinux policy in %s.",
-                         format_timespan(timespan, sizeof(timespan), after_load - before_load));
-
-               *loaded_policy = true;
-
-       } else {
-               log_open();
-
-               if (enforce > 0) {
-                       log_error("Failed to load SELinux policy. Freezing.");
-                       return -EIO;
-               } else
-                       log_debug("Unable to load SELinux policy. Ignoring.");
-       }
-#endif
-
-       return 0;
-}
diff --git a/src/selinux-setup.h b/src/selinux-setup.h
deleted file mode 100644
index 6b8fe00..0000000
--- a/src/selinux-setup.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooselinuxsetuphfoo
-#define fooselinuxsetuphfoo
-
-/***
-  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 selinux_setup(bool *loaded_policy);
-
-#endif
diff --git a/src/service.c b/src/service.c
deleted file mode 100644
index bf2e0a9..0000000
--- a/src/service.c
+++ /dev/null
@@ -1,3797 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <sys/reboot.h>
-
-#include "manager.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"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "def.h"
-#include "util.h"
-#include "utf8.h"
-
-#ifdef HAVE_SYSV_COMPAT
-
-#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE)
-
-typedef enum RunlevelType {
-        RUNLEVEL_UP,
-        RUNLEVEL_DOWN,
-        RUNLEVEL_SYSINIT
-} RunlevelType;
-
-static const struct {
-        const char *path;
-        const char *target;
-        const RunlevelType type;
-} rcnd_table[] = {
-        /* Standard SysV runlevels for start-up */
-        { "rc1.d",  SPECIAL_RESCUE_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 },
-
-#ifdef TARGET_SUSE
-        /* SUSE style boot.d */
-        { "boot.d", SPECIAL_SYSINIT_TARGET,   RUNLEVEL_SYSINIT },
-#endif
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
-        /* Debian style rcS.d */
-        { "rcS.d",  SPECIAL_SYSINIT_TARGET,   RUNLEVEL_SYSINIT },
-#endif
-
-        /* Standard SysV runlevels for shutdown */
-        { "rc0.d",  SPECIAL_POWEROFF_TARGET,  RUNLEVEL_DOWN },
-        { "rc6.d",  SPECIAL_REBOOT_TARGET,    RUNLEVEL_DOWN }
-
-        /* Note that the order here matters, as we read the
-           directories in this order, and we want to make sure that
-           sysv_start_priority is known when we first load the
-           unit. And that value we only know from S links. Hence
-           UP/SYSINIT must be read before DOWN */
-};
-
-#define RUNLEVELS_UP "12345"
-/* #define RUNLEVELS_DOWN "06" */
-#define RUNLEVELS_BOOT "bBsS"
-#endif
-
-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_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_FAILED] = UNIT_FAILED,
-        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
-};
-
-static void service_init(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        s->restart_usec = DEFAULT_RESTART_USEC;
-
-        s->watchdog_watch.type = WATCH_INVALID;
-
-        s->timer_watch.type = WATCH_INVALID;
-#ifdef HAVE_SYSV_COMPAT
-        s->sysv_start_priority = -1;
-        s->sysv_start_priority_from_rcnd = -1;
-#endif
-        s->socket_fd = -1;
-        s->guess_main_pid = true;
-
-        exec_context_init(&s->exec_context);
-
-        RATELIMIT_INIT(s->start_limit, 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_unwatch_pid_file(Service *s) {
-        if (!s->pid_file_pathspec)
-                return;
-
-        log_debug("Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
-        path_spec_unwatch(s->pid_file_pathspec, UNIT(s));
-        path_spec_done(s->pid_file_pathspec);
-        free(s->pid_file_pathspec);
-        s->pid_file_pathspec = NULL;
-}
-
-static int service_set_main_pid(Service *s, pid_t pid) {
-        pid_t ppid;
-
-        assert(s);
-
-        if (pid <= 1)
-                return -EINVAL;
-
-        if (pid == getpid())
-                return -EINVAL;
-
-        s->main_pid = pid;
-        s->main_pid_known = true;
-
-        if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
-                log_warning("%s: Supervising process %lu which is not our child. We'll most likely not notice when it exits.",
-                            UNIT(s)->id, (unsigned long) pid);
-
-                s->main_pid_alien = true;
-        } else
-                s->main_pid_alien = false;
-
-        exec_status_start(&s->main_exec_status, pid);
-
-        return 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_connection_unref(Service *s) {
-        assert(s);
-
-        if (!UNIT_DEREF(s->accept_socket))
-                return;
-
-        socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
-        unit_ref_unset(&s->accept_socket);
-}
-
-static void service_stop_watchdog(Service *s) {
-        assert(s);
-
-        unit_unwatch_timer(UNIT(s), &s->watchdog_watch);
-        s->watchdog_timestamp.realtime = 0;
-        s->watchdog_timestamp.monotonic = 0;
-}
-
-static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart);
-
-static void service_handle_watchdog(Service *s) {
-        usec_t offset;
-        int r;
-
-        assert(s);
-
-        if (s->watchdog_usec == 0)
-                return;
-
-        offset = now(CLOCK_MONOTONIC) - s->watchdog_timestamp.monotonic;
-        if (offset >= s->watchdog_usec) {
-                log_error("%s watchdog timeout!", UNIT(s)->id);
-                service_enter_dead(s, SERVICE_FAILURE_WATCHDOG, true);
-                return;
-        }
-
-        r = unit_watch_timer(UNIT(s), s->watchdog_usec - offset, &s->watchdog_watch);
-        if (r < 0)
-                log_warning("%s failed to install watchdog timer: %s", UNIT(s)->id, strerror(-r));
-}
-
-static void service_reset_watchdog(Service *s) {
-        assert(s);
-
-        dual_timestamp_get(&s->watchdog_timestamp);
-        service_handle_watchdog(s);
-}
-
-static void service_done(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        free(s->pid_file);
-        s->pid_file = NULL;
-
-#ifdef HAVE_SYSV_COMPAT
-        free(s->sysv_path);
-        s->sysv_path = NULL;
-
-        free(s->sysv_runlevels);
-        s->sysv_runlevels = NULL;
-#endif
-
-        free(s->status_text);
-        s->status_text = NULL;
-
-        exec_context_done(&s->exec_context);
-        exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
-        s->control_command = NULL;
-        s->main_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);
-        service_unwatch_pid_file(s);
-
-        if (s->bus_name)  {
-                unit_unwatch_bus_name(u, s->bus_name);
-                free(s->bus_name);
-                s->bus_name = NULL;
-        }
-
-        service_close_socket_fd(s);
-        service_connection_unref(s);
-
-        unit_ref_unset(&s->accept_socket);
-
-        service_stop_watchdog(s);
-
-        unit_unwatch_timer(u, &s->timer_watch);
-}
-
-#ifdef HAVE_SYSV_COMPAT
-static char *sysv_translate_name(const char *name) {
-        char *r;
-
-        if (!(r = new(char, strlen(name) + sizeof(".service"))))
-                return NULL;
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
-        if (endswith(name, ".sh"))
-                /* Drop Debian-style .sh suffix */
-                strcpy(stpcpy(r, name) - 3, ".service");
-#endif
-#ifdef TARGET_SUSE
-        if (startswith(name, "boot."))
-                /* Drop SuSE-style boot. prefix */
-                strcpy(stpcpy(r, name + 5), ".service");
-#endif
-#ifdef TARGET_FRUGALWARE
-        if (startswith(name, "rc."))
-                /* Drop Frugalware-style rc. prefix */
-                strcpy(stpcpy(r, name + 3), ".service");
-#endif
-        else
-                /* Normal init scripts */
-                strcpy(stpcpy(r, name), ".service");
-
-        return r;
-}
-
-static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
-
-        /* We silently ignore the $ prefix here. According to the LSB
-         * spec it simply indicates whether something is a
-         * standardized name or a distribution-specific one. Since we
-         * just follow what already exists and do not introduce new
-         * uses or names we don't care who introduced a new name. */
-
-        static const char * const table[] = {
-                /* LSB defined facilities */
-                "local_fs",             SPECIAL_LOCAL_FS_TARGET,
-#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
-#else
-                /* Due to unfortunate name selection in Mandriva,
-                 * $network is provided by network-up which is ordered
-                 * after network which actually starts interfaces.
-                 * To break the loop, just ignore it */
-                "network",              SPECIAL_NETWORK_TARGET,
-#endif
-                "named",                SPECIAL_NSS_LOOKUP_TARGET,
-                "portmap",              SPECIAL_RPCBIND_TARGET,
-                "remote_fs",            SPECIAL_REMOTE_FS_TARGET,
-                "syslog",               SPECIAL_SYSLOG_TARGET,
-                "time",                 SPECIAL_TIME_SYNC_TARGET,
-
-                /* common extensions */
-                "mail-transfer-agent",  SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-                "x-display-manager",    SPECIAL_DISPLAY_MANAGER_SERVICE,
-                "null",                 NULL,
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
-                "mail-transport-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-#endif
-
-#ifdef TARGET_FEDORA
-                "MTA",                  SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-                "smtpdaemon",           SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-                "httpd",                SPECIAL_HTTP_DAEMON_TARGET,
-#endif
-
-#ifdef TARGET_SUSE
-                "smtp",                 SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-#endif
-        };
-
-        unsigned i;
-        char *r;
-        const char *n;
-
-        assert(name);
-        assert(_r);
-
-        n = *name == '$' ? name + 1 : name;
-
-        for (i = 0; i < ELEMENTSOF(table); i += 2) {
-
-                if (!streq(table[i], n))
-                        continue;
-
-                if (!table[i+1])
-                        return 0;
-
-                if (!(r = strdup(table[i+1])))
-                        return -ENOMEM;
-
-                goto finish;
-        }
-
-        /* If we don't know this name, fallback heuristics to figure
-         * out whether something is a target or a service alias. */
-
-        if (*name == '$') {
-                if (!unit_prefix_is_valid(n))
-                        return -EINVAL;
-
-                /* Facilities starting with $ are most likely targets */
-                r = unit_name_build(n, NULL, ".target");
-        } else if (filename && streq(name, filename))
-                /* Names equaling the file name of the services are redundant */
-                return 0;
-        else
-                /* Everything else we assume to be normal service names */
-                r = sysv_translate_name(n);
-
-        if (!r)
-                return -ENOMEM;
-
-finish:
-        *_r = r;
-
-        return 1;
-}
-
-static int sysv_fix_order(Service *s) {
-        Unit *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_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) {
-                Service *t;
-                UnitDependency d;
-                bool special_s, special_t;
-
-                t = SERVICE(other);
-
-                if (s == t)
-                        continue;
-
-                if (UNIT(t)->load_state != UNIT_LOADED)
-                        continue;
-
-                if (t->sysv_start_priority < 0)
-                        continue;
-
-                /* If both units have modern headers we don't care
-                 * about the priorities */
-                if ((UNIT(s)->fragment_path || s->sysv_has_lsb) &&
-                    (UNIT(t)->fragment_path || t->sysv_has_lsb))
-                        continue;
-
-                special_s = s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels);
-                special_t = t->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, t->sysv_runlevels);
-
-                if (special_t && !special_s)
-                        d = UNIT_AFTER;
-                else if (special_s && !special_t)
-                        d = UNIT_BEFORE;
-                else 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;
-        char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description;
-        struct stat st;
-
-        assert(s);
-        assert(path);
-
-        u = UNIT(s);
-
-        if (!(f = fopen(path, "re"))) {
-                r = errno == ENOENT ? 0 : -errno;
-                goto finish;
-        }
-
-        zero(st);
-        if (fstat(fileno(f), &st) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        free(s->sysv_path);
-        if (!(s->sysv_path = strdup(path))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        s->sysv_mtime = timespec_load(&st.st_mtim);
-
-        if (null_or_empty(&st)) {
-                u->load_state = UNIT_MASKED;
-                r = 0;
-                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_no_case(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
-                                        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_no_case(t, "description:")) {
-
-                                size_t k = strlen(t);
-                                char *d;
-                                const char *j;
-
-                                if (t[k-1] == '\\') {
-                                        state = DESCRIPTION;
-                                        t[k-1] = 0;
-                                }
-
-                                if ((j = strstrip(t+12)) && *j) {
-                                        if (!(d = strdup(j))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-                                } else
-                                        d = NULL;
-
-                                free(chkconfig_description);
-                                chkconfig_description = d;
-
-                        } else if (startswith_no_case(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 *j;
-
-                        if (t[k-1] == '\\')
-                                t[k-1] = 0;
-                        else
-                                state = NORMAL;
-
-                        if ((j = strstrip(t)) && *j) {
-                                char *d = NULL;
-
-                                if (chkconfig_description)
-                                        d = join(chkconfig_description, " ", j, NULL);
-                                else
-                                        d = strdup(j);
-
-                                if (!d) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                free(chkconfig_description);
-                                chkconfig_description = d;
-                        }
-
-                } else if (state == LSB || state == LSB_DESCRIPTION) {
-
-                        if (startswith_no_case(t, "Provides:")) {
-                                char *i, *w;
-                                size_t z;
-
-                                state = LSB;
-
-                                FOREACH_WORD_QUOTED(w, z, t+9, i) {
-                                        char *n, *m;
-
-                                        if (!(n = strndup(w, z))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        r = sysv_translate_facility(n, file_name_from_path(path), &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
-                                                /* NB: SysV targets
-                                                 * which are provided
-                                                 * by a service are
-                                                 * pulled in by the
-                                                 * services, as an
-                                                 * indication that the
-                                                 * generic service is
-                                                 * now available. This
-                                                 * is strictly
-                                                 * one-way. The
-                                                 * targets do NOT pull
-                                                 * in the SysV
-                                                 * services! */
-                                                r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true);
-
-                                        if (r < 0)
-                                                log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r));
-
-                                        free(m);
-                                }
-
-                        } else if (startswith_no_case(t, "Required-Start:") ||
-                                   startswith_no_case(t, "Should-Start:") ||
-                                   startswith_no_case(t, "X-Start-Before:") ||
-                                   startswith_no_case(t, "X-Start-After:")) {
-                                char *i, *w;
-                                size_t z;
-
-                                state = LSB;
-
-                                FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) {
-                                        char *n, *m;
-
-                                        if (!(n = strndup(w, z))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-
-                                        r = sysv_translate_facility(n, file_name_from_path(path), &m);
-
-                                        if (r < 0) {
-                                                log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
-                                                free(n);
-                                                continue;
-                                        }
-
-                                        free(n);
-
-                                        if (r == 0)
-                                                continue;
-
-                                        r = unit_add_dependency_by_name(u, startswith_no_case(t, "X-Start-Before:") ? UNIT_BEFORE : UNIT_AFTER, m, NULL, true);
-
-                                        if (r < 0)
-                                                log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", path, line, m, strerror(-r));
-
-                                        free(m);
-                                }
-                        } else if (startswith_no_case(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_no_case(t, "Description:")) {
-                                char *d, *j;
-
-                                state = LSB_DESCRIPTION;
-
-                                if ((j = strstrip(t+12)) && *j) {
-                                        if (!(d = strdup(j))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-                                } else
-                                        d = NULL;
-
-                                free(long_description);
-                                long_description = d;
-
-                        } else if (startswith_no_case(t, "Short-Description:")) {
-                                char *d, *j;
-
-                                state = LSB;
-
-                                if ((j = strstrip(t+18)) && *j) {
-                                        if (!(d = strdup(j))) {
-                                                r = -ENOMEM;
-                                                goto finish;
-                                        }
-                                } else
-                                        d = NULL;
-
-                                free(short_description);
-                                short_description = d;
-
-                        } else if (state == LSB_DESCRIPTION) {
-
-                                if (startswith(l, "#\t") || startswith(l, "#  ")) {
-                                        char *j;
-
-                                        if ((j = strstrip(t)) && *j) {
-                                                char *d = NULL;
-
-                                                if (long_description)
-                                                        d = join(long_description, " ", t, NULL);
-                                                else
-                                                        d = strdup(j);
-
-                                                if (!d) {
-                                                        r = -ENOMEM;
-                                                        goto finish;
-                                                }
-
-                                                free(long_description);
-                                                long_description = d;
-                                        }
-
-                                } else
-                                        state = LSB;
-                        }
-                }
-        }
-
-        if ((r = sysv_exec_commands(s)) < 0)
-                goto finish;
-        if (s->sysv_runlevels &&
-            chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) &&
-            chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
-                /* Service has both boot and "up" runlevels
-                   configured.  Kill the "up" ones. */
-                delete_chars(s->sysv_runlevels, RUNLEVELS_UP);
-        }
-
-        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. */
-
-                UNIT(s)->default_dependencies = false;
-
-                /* Don't timeout special services during boot (like fsck) */
-                s->timeout_usec = 0;
-        } else
-                s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC;
-
-        /* Special setting for all SysV services */
-        s->type = SERVICE_FORKING;
-        s->remain_after_exit = !s->pid_file;
-        s->guess_main_pid = false;
-        s->restart = SERVICE_RESTART_NO;
-        s->exec_context.ignore_sigpipe = false;
-
-        if (UNIT(s)->manager->sysv_console)
-                s->exec_context.std_output = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
-
-        s->exec_context.kill_mode = KILL_PROCESS;
-
-        /* We use the long description only if
-         * no short description is set. */
-
-        if (short_description)
-                description = short_description;
-        else if (chkconfig_description)
-                description = chkconfig_description;
-        else if (long_description)
-                description = long_description;
-        else
-                description = NULL;
-
-        if (description) {
-                char *d;
-
-                if (!(d = strappend(s->sysv_has_lsb ? "LSB: " : "SYSV: ", description))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                u->description = d;
-        }
-
-        /* The priority that has been set in /etc/rcN.d/ hierarchies
-         * takes precedence over what is stored as default in the LSB
-         * header */
-        if (s->sysv_start_priority_from_rcnd >= 0)
-                s->sysv_start_priority = s->sysv_start_priority_from_rcnd;
-
-        u->load_state = UNIT_LOADED;
-        r = 0;
-
-finish:
-
-        if (f)
-                fclose(f);
-
-        free(short_description);
-        free(long_description);
-        free(chkconfig_description);
-
-        return r;
-}
-
-static int service_load_sysv_name(Service *s, const char *name) {
-        char **p;
-
-        assert(s);
-        assert(name);
-
-        /* For SysV services we strip the boot.*, rc.* and *.sh
-         * prefixes/suffixes. */
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
-        if (endswith(name, ".sh.service"))
-                return -ENOENT;
-#endif
-
-#ifdef TARGET_SUSE
-        if (startswith(name, "boot."))
-                return -ENOENT;
-#endif
-
-#ifdef TARGET_FRUGALWARE
-        if (startswith(name, "rc."))
-                return -ENOENT;
-#endif
-
-        STRV_FOREACH(p, UNIT(s)->manager->lookup_paths.sysvinit_path) {
-                char *path;
-                int r;
-
-                path = join(*p, "/", name, NULL);
-                if (!path)
-                        return -ENOMEM;
-
-                assert(endswith(path, ".service"));
-                path[strlen(path)-8] = 0;
-
-                r = service_load_sysv_path(s, path);
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
-                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
-                        /* Try Debian style *.sh source'able init scripts */
-                        strcat(path, ".sh");
-                        r = service_load_sysv_path(s, path);
-                }
-#endif
-                free(path);
-
-#ifdef TARGET_SUSE
-                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
-                        /* Try SUSE style boot.* init scripts */
-
-                        path = join(*p, "/boot.", name, NULL);
-                        if (!path)
-                                return -ENOMEM;
-
-                        /* Drop .service suffix */
-                        path[strlen(path)-8] = 0;
-                        r = service_load_sysv_path(s, path);
-                        free(path);
-                }
-#endif
-
-#ifdef TARGET_FRUGALWARE
-                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
-                        /* Try Frugalware style rc.* init scripts */
-
-                        path = join(*p, "/rc.", name, NULL);
-                        if (!path)
-                                return -ENOMEM;
-
-                        /* Drop .service suffix */
-                        path[strlen(path)-8] = 0;
-                        r = service_load_sysv_path(s, path);
-                        free(path);
-                }
-#endif
-
-                if (r < 0)
-                        return r;
-
-                if ((UNIT(s)->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)->manager->lookup_paths.sysvinit_path))
-                return 0;
-
-        if ((t = UNIT(s)->id))
-                if ((r = service_load_sysv_name(s, t)) < 0)
-                        return r;
-
-        if (UNIT(s)->load_state == UNIT_STUB)
-                SET_FOREACH(t, UNIT(s)->names, i) {
-                        if (t == UNIT(s)->id)
-                                continue;
-
-                        if ((r = service_load_sysv_name(s, t)) < 0)
-                                return r;
-
-                        if (UNIT(s)->load_state != UNIT_STUB)
-                                break;
-                }
-
-        return 0;
-}
-#endif
-
-static int fsck_fix_order(Service *s) {
-        Unit *other;
-        int r;
-
-        assert(s);
-
-        if (s->fsck_passno <= 0)
-                return 0;
-
-        /* For each pair of services where both have an fsck priority
-         * we order things based on it. */
-
-        LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) {
-                Service *t;
-                UnitDependency d;
-
-                t = SERVICE(other);
-
-                if (s == t)
-                        continue;
-
-                if (UNIT(t)->load_state != UNIT_LOADED)
-                        continue;
-
-                if (t->fsck_passno <= 0)
-                        continue;
-
-                if (t->fsck_passno < s->fsck_passno)
-                        d = UNIT_AFTER;
-                else if (t->fsck_passno > s->fsck_passno)
-                        d = UNIT_BEFORE;
-                else
-                        continue;
-
-                if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int service_verify(Service *s) {
-        assert(s);
-
-        if (UNIT(s)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!s->exec_command[SERVICE_EXEC_START]) {
-                log_error("%s lacks ExecStart setting. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        if (s->type != SERVICE_ONESHOT &&
-            s->exec_command[SERVICE_EXEC_START]->command_next) {
-                log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        if (s->type == SERVICE_ONESHOT &&
-            s->exec_command[SERVICE_EXEC_RELOAD]) {
-                log_error("%s has an ExecReload setting, which is not allowed for Type=oneshot services. Refusing.", UNIT(s)->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)->id);
-                return -EINVAL;
-        }
-
-        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
-                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int service_add_default_dependencies(Service *s) {
-        int r;
-
-        assert(s);
-
-        /* Add a number of automatic dependencies useful for the
-         * majority of services. */
-
-        /* First, pull in base system */
-        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
-                        return r;
-
-        } else if (UNIT(s)->manager->running_as == MANAGER_USER) {
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
-                        return r;
-        }
-
-        /* Second, activate normal shutdown */
-        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static void service_fix_output(Service *s) {
-        assert(s);
-
-        /* If nothing has been explicitly configured, patch default
-         * output in. If input is socket/tty we avoid this however,
-         * since in that case we want output to default to the same
-         * place as we read input from. */
-
-        if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
-            s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
-            s->exec_context.std_input == EXEC_INPUT_NULL)
-                s->exec_context.std_error = UNIT(s)->manager->default_std_error;
-
-        if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
-            s->exec_context.std_input == EXEC_INPUT_NULL)
-                s->exec_context.std_output = UNIT(s)->manager->default_std_output;
-}
-
-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;
-
-#ifdef HAVE_SYSV_COMPAT
-        /* Load a classic init script as a fallback, if we couldn't find anything */
-        if (u->load_state == UNIT_STUB)
-                if ((r = service_load_sysv(s)) < 0)
-                        return r;
-#endif
-
-        /* Still nothing found? Then let's give up */
-        if (u->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->load_state == UNIT_LOADED) {
-                service_fix_output(s);
-
-                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
-                        return r;
-
-                if ((r = unit_add_default_cgroups(u)) < 0)
-                        return r;
-
-#ifdef HAVE_SYSV_COMPAT
-                if ((r = sysv_fix_order(s)) < 0)
-                        return r;
-#endif
-
-                if ((r = fsck_fix_order(s)) < 0)
-                        return r;
-
-                if (s->bus_name)
-                        if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
-                                return r;
-
-                if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
-                        s->notify_access = NOTIFY_MAIN;
-
-                if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
-                        s->notify_access = NOTIFY_MAIN;
-
-                if (s->type == SERVICE_DBUS || s->bus_name)
-                        if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
-                                return r;
-
-                if (UNIT(s)->default_dependencies)
-                        if ((r = service_add_default_dependencies(s)) < 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"
-                "%sResult: %s\n"
-                "%sReload Result: %s\n"
-                "%sPermissionsStartOnly: %s\n"
-                "%sRootDirectoryStartOnly: %s\n"
-                "%sRemainAfterExit: %s\n"
-                "%sGuessMainPID: %s\n"
-                "%sType: %s\n"
-                "%sRestart: %s\n"
-                "%sNotifyAccess: %s\n",
-                prefix, service_state_to_string(s->state),
-                prefix, service_result_to_string(s->result),
-                prefix, service_result_to_string(s->reload_result),
-                prefix, yes_no(s->permissions_start_only),
-                prefix, yes_no(s->root_directory_start_only),
-                prefix, yes_no(s->remain_after_exit),
-                prefix, yes_no(s->guess_main_pid),
-                prefix, service_type_to_string(s->type),
-                prefix, service_restart_to_string(s->restart),
-                prefix, notify_access_to_string(s->notify_access));
-
-        if (s->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %lu\n",
-                        prefix, (unsigned long) s->control_pid);
-
-        if (s->main_pid > 0)
-                fprintf(f,
-                        "%sMain PID: %lu\n"
-                        "%sMain PID Known: %s\n"
-                        "%sMain PID Alien: %s\n",
-                        prefix, (unsigned long) s->main_pid,
-                        prefix, yes_no(s->main_pid_known),
-                        prefix, yes_no(s->main_pid_alien));
-
-        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);
-        }
-
-#ifdef HAVE_SYSV_COMPAT
-        if (s->sysv_path)
-                fprintf(f,
-                        "%sSysV Init Script Path: %s\n"
-                        "%sSysV Init Script has LSB Header: %s\n"
-                        "%sSysVEnabled: %s\n",
-                        prefix, s->sysv_path,
-                        prefix, yes_no(s->sysv_has_lsb),
-                        prefix, yes_no(s->sysv_enabled));
-
-        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);
-#endif
-
-        if (s->fsck_passno > 0)
-                fprintf(f,
-                        "%sFsckPassNo: %i\n",
-                        prefix, s->fsck_passno);
-
-        if (s->status_text)
-                fprintf(f, "%sStatus Text: %s\n",
-                        prefix, s->status_text);
-
-        free(p2);
-}
-
-static int service_load_pid_file(Service *s, bool may_warn) {
-        char *k;
-        int r;
-        pid_t pid;
-
-        assert(s);
-
-        if (!s->pid_file)
-                return -ENOENT;
-
-        if ((r = read_one_line_file(s->pid_file, &k)) < 0) {
-                if (may_warn)
-                        log_info("PID file %s not readable (yet?) after %s.",
-                                 s->pid_file, service_state_to_string(s->state));
-                return r;
-        }
-
-        r = parse_pid(k, &pid);
-        free(k);
-
-        if (r < 0)
-                return r;
-
-        if (kill(pid, 0) < 0 && errno != EPERM) {
-                if (may_warn)
-                        log_info("PID %lu read from file %s does not exist.",
-                                 (unsigned long) pid, s->pid_file);
-                return -ESRCH;
-        }
-
-        if (s->main_pid_known) {
-                if (pid == s->main_pid)
-                        return 0;
-
-                log_debug("Main PID changing: %lu -> %lu",
-                          (unsigned long) s->main_pid, (unsigned long) pid);
-                service_unwatch_main_pid(s);
-                s->main_pid_known = false;
-        } else
-                log_debug("Main PID loaded: %lu", (unsigned long) pid);
-
-        if ((r = service_set_main_pid(s, pid)) < 0)
-                return r;
-
-        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
-                /* FIXME: we need to do something here */
-                return r;
-
-        return 0;
-}
-
-static int service_search_main_pid(Service *s) {
-        pid_t pid;
-        int r;
-
-        assert(s);
-
-        /* If we know it anyway, don't ever fallback to unreliable
-         * heuristics */
-        if (s->main_pid_known)
-                return 0;
-
-        if (!s->guess_main_pid)
-                return 0;
-
-        assert(s->main_pid <= 0);
-
-        if ((pid = cgroup_bonding_search_main_pid_list(UNIT(s)->cgroup_bondings)) <= 0)
-                return -ENOENT;
-
-        log_debug("Main PID guessed: %lu", (unsigned long) pid);
-        if ((r = service_set_main_pid(s, pid)) < 0)
-                return r;
-
-        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
-                /* FIXME: we need to do something here */
-                return r;
-
-        return 0;
-}
-
-static void service_notify_sockets_dead(Service *s, bool failed_permanent) {
-        Iterator i;
-        Unit *u;
-
-        assert(s);
-
-        /* Notifies all our sockets when we die */
-
-        if (s->socket_fd >= 0)
-                return;
-
-        SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i)
-                if (u->type == UNIT_SOCKET)
-                        socket_notify_service_dead(SOCKET(u), failed_permanent);
-
-        return;
-}
-
-static void service_set_state(Service *s, ServiceState state) {
-        ServiceState old_state;
-        assert(s);
-
-        old_state = s->state;
-        s->state = state;
-
-        service_unwatch_pid_file(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 &&
-            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);
-                s->main_command = NULL;
-        }
-
-        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_FAILED ||
-            state == SERVICE_AUTO_RESTART)
-                service_notify_sockets_dead(s, false);
-
-        if (state != SERVICE_START_PRE &&
-            state != SERVICE_START &&
-            state != SERVICE_START_POST &&
-            state != SERVICE_RUNNING &&
-            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_DEAD && UNIT(s)->job)) {
-                service_close_socket_fd(s);
-                service_connection_unref(s);
-        }
-
-        if (state == SERVICE_STOP)
-                service_stop_watchdog(s);
-
-        /* For the inactive states unit_notify() will trim the cgroup,
-         * but for exit we have to do that ourselves... */
-        if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
-                cgroup_bonding_trim_list(UNIT(s)->cgroup_bondings, true);
-
-        if (old_state != state)
-                log_debug("%s changed %s -> %s", UNIT(s)->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], s->reload_result == SERVICE_SUCCESS);
-        s->reload_result = SERVICE_SUCCESS;
-}
-
-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->type == SERVICE_ONESHOT ||
-                      s->type == SERVICE_NOTIFY)) ||
-                    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;
-
-                if (s->deserialized_state == SERVICE_START_POST ||
-                    s->deserialized_state == SERVICE_RUNNING)
-                        service_handle_watchdog(s);
-
-                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;
-        Unit *u;
-
-        assert(s);
-        assert(fds);
-        assert(n_fds);
-
-        if (s->socket_fd >= 0)
-                return 0;
-
-        SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
-                int *cfds;
-                unsigned cn_fds;
-                Socket *sock;
-
-                if (u->type != UNIT_SOCKET)
-                        continue;
-
-                sock = SOCKET(u);
-
-                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 * sizeof(int));
-                        memcpy(t+rn_fds, cfds, cn_fds * sizeof(int));
-                        free(rfds);
-                        free(cfds);
-
-                        rfds = t;
-                        rn_fds = rn_fds+cn_fds;
-                }
-        }
-
-        *fds = rfds;
-        *n_fds = rn_fds;
-
-        return 0;
-
-fail:
-        free(rfds);
-
-        return r;
-}
-
-static int service_spawn(
-                Service *s,
-                ExecCommand *c,
-                bool timeout,
-                bool pass_fds,
-                bool apply_permissions,
-                bool apply_chroot,
-                bool apply_tty_stdin,
-                bool set_notify_socket,
-                pid_t *_pid) {
-
-        pid_t pid;
-        int r;
-        int *fds = NULL, *fdsbuf = NULL;
-        unsigned n_fds = 0, n_env = 0;
-        char **argv = NULL, **final_env = NULL, **our_env = NULL;
-
-        assert(s);
-        assert(c);
-        assert(_pid);
-
-        if (pass_fds ||
-            s->exec_context.std_input == EXEC_INPUT_SOCKET ||
-            s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
-            s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
-
-                if (s->socket_fd >= 0) {
-                        fds = &s->socket_fd;
-                        n_fds = 1;
-                } else {
-                        if ((r = service_collect_fds(s, &fdsbuf, &n_fds)) < 0)
-                                goto fail;
-
-                        fds = fdsbuf;
-                }
-        }
-
-        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;
-        }
-
-        if (!(our_env = new0(char*, 4))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (set_notify_socket)
-                if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-        if (s->main_pid > 0)
-                if (asprintf(our_env + n_env++, "MAINPID=%lu", (unsigned long) s->main_pid) < 0) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-        if (s->watchdog_usec > 0)
-                if (asprintf(our_env + n_env++, "WATCHDOG_USEC=%llu", (unsigned long long) s->watchdog_usec) < 0) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-        if (!(final_env = strv_env_merge(2,
-                                         UNIT(s)->manager->environment,
-                                         our_env,
-                                         NULL))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        r = exec_spawn(c,
-                       argv,
-                       &s->exec_context,
-                       fds, n_fds,
-                       final_env,
-                       apply_permissions,
-                       apply_chroot,
-                       apply_tty_stdin,
-                       UNIT(s)->manager->confirm_spawn,
-                       UNIT(s)->cgroup_bondings,
-                       UNIT(s)->cgroup_attributes,
-                       &pid);
-
-        if (r < 0)
-                goto fail;
-
-
-        if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
-                /* FIXME: we need to do something here */
-                goto fail;
-
-        free(fdsbuf);
-        strv_free(argv);
-        strv_free(our_env);
-        strv_free(final_env);
-
-        *_pid = pid;
-
-        return 0;
-
-fail:
-        free(fdsbuf);
-        strv_free(argv);
-        strv_free(our_env);
-        strv_free(final_env);
-
-        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) {
-
-                /* If it's an alien child let's check if it is still
-                 * alive ... */
-                if (s->main_pid_alien)
-                        return kill(s->main_pid, 0) >= 0 || errno != ESRCH;
-
-                /* .. otherwise assume we'll get a SIGCHLD for it,
-                 * which we really should wait for to collect exit
-                 * status and code */
-                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 ((r = cgroup_bonding_is_empty_list(UNIT(s)->cgroup_bondings)) < 0)
-                return r;
-
-        return !r;
-}
-
-static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
-        int r;
-        assert(s);
-
-        if (f != SERVICE_SUCCESS)
-                s->result = f;
-
-        if (allow_restart &&
-            !s->forbid_restart &&
-            (s->restart == SERVICE_RESTART_ALWAYS ||
-             (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
-             (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
-             (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL ||
-                                                         s->result == SERVICE_FAILURE_CORE_DUMP)))) {
-
-                r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
-                if (r < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_AUTO_RESTART);
-        } else
-                service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
-
-        s->forbid_restart = false;
-
-        return;
-
-fail:
-        log_warning("%s failed to run install restart timer: %s", UNIT(s)->id, strerror(-r));
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
-
-static void service_enter_stop_post(Service *s, ServiceResult f) {
-        int r;
-        assert(s);
-
-        if (f != SERVICE_SUCCESS)
-                s->result = f;
-
-        service_unwatch_control_pid(s);
-
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
-                s->control_command_id = SERVICE_EXEC_STOP_POST;
-
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       true,
-                                       false,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-
-                service_set_state(s, SERVICE_STOP_POST);
-        } else
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
-        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
-        int r;
-        Set *pid_set = NULL;
-        bool wait_for_exit = false;
-
-        assert(s);
-
-        if (f != SERVICE_SUCCESS)
-                s->result = f;
-
-        if (s->exec_context.kill_mode != KILL_NONE) {
-                int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
-
-                if (s->main_pid > 0) {
-                        if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH)
-                                log_warning("Failed to kill main process %li: %m", (long) s->main_pid);
-                        else
-                                wait_for_exit = !s->main_pid_alien;
-                }
-
-                if (s->control_pid > 0) {
-                        if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
-                                log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
-                        else
-                                wait_for_exit = true;
-                }
-
-                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
-
-                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        /* Exclude the main/control pids from being killed via the cgroup */
-                        if (s->main_pid > 0)
-                                if ((r = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0)
-                                        goto fail;
-
-                        if (s->control_pid > 0)
-                                if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
-                                        goto fail;
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
-                                        log_warning("Failed to kill control group: %s", strerror(-r));
-                        } else if (r > 0)
-                                wait_for_exit = true;
-
-                        set_free(pid_set);
-                        pid_set = NULL;
-                }
-        }
-
-        if (wait_for_exit) {
-                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, SERVICE_SUCCESS);
-        else
-                service_enter_dead(s, SERVICE_SUCCESS, true);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
-        if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
-                service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
-        else
-                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-
-        if (pid_set)
-                set_free(pid_set);
-}
-
-static void service_enter_stop(Service *s, ServiceResult f) {
-        int r;
-
-        assert(s);
-
-        if (f != SERVICE_SUCCESS)
-                s->result = f;
-
-        service_unwatch_control_pid(s);
-
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
-                s->control_command_id = SERVICE_EXEC_STOP;
-
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       false,
-                                       false,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_STOP);
-        } else
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r));
-        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_running(Service *s, ServiceResult f) {
-        int main_pid_ok, cgroup_ok;
-        assert(s);
-
-        if (f != SERVICE_SUCCESS)
-                s->result = f;
-
-        main_pid_ok = main_pid_good(s);
-        cgroup_ok = cgroup_good(s);
-
-        if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) &&
-            (s->bus_name_good || s->type != SERVICE_DBUS))
-                service_set_state(s, SERVICE_RUNNING);
-        else if (s->remain_after_exit)
-                service_set_state(s, SERVICE_EXITED);
-        else
-                service_enter_stop(s, SERVICE_SUCCESS);
-}
-
-static void service_enter_start_post(Service *s) {
-        int r;
-        assert(s);
-
-        service_unwatch_control_pid(s);
-
-        if (s->watchdog_usec > 0)
-                service_reset_watchdog(s);
-
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
-                s->control_command_id = SERVICE_EXEC_START_POST;
-
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       false,
-                                       false,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_START_POST);
-        } else
-                service_enter_running(s, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
-        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_start(Service *s) {
-        pid_t pid;
-        int r;
-        ExecCommand *c;
-
-        assert(s);
-
-        assert(s->exec_command[SERVICE_EXEC_START]);
-        assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
-
-        if (s->type == SERVICE_FORKING)
-                service_unwatch_control_pid(s);
-        else
-                service_unwatch_main_pid(s);
-
-        /* We want to ensure that nobody leaks processes from
-         * START_PRE here, so let's go on a killing spree, People
-         * should not spawn long running processes from START_PRE. */
-        cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
-
-        if (s->type == SERVICE_FORKING) {
-                s->control_command_id = SERVICE_EXEC_START;
-                c = s->control_command = s->exec_command[SERVICE_EXEC_START];
-
-                s->main_command = NULL;
-        } else {
-                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-                s->control_command = NULL;
-
-                c = s->main_command = s->exec_command[SERVICE_EXEC_START];
-        }
-
-        if ((r = service_spawn(s,
-                               c,
-                               s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
-                               true,
-                               true,
-                               true,
-                               true,
-                               s->notify_access != NOTIFY_NONE,
-                               &pid)) < 0)
-                goto fail;
-
-        if (s->type == SERVICE_SIMPLE) {
-                /* For simple services we immediately start
-                 * the START_POST binaries. */
-
-                service_set_main_pid(s, pid);
-                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;
-                service_set_state(s, SERVICE_START);
-
-        } else if (s->type == SERVICE_ONESHOT ||
-                   s->type == SERVICE_DBUS ||
-                   s->type == SERVICE_NOTIFY) {
-
-                /* For oneshot 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. Notify services are similar. */
-
-                service_set_main_pid(s, pid);
-                service_set_state(s, SERVICE_START);
-        } else
-                assert_not_reached("Unknown service type");
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r));
-        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_start_pre(Service *s) {
-        int r;
-
-        assert(s);
-
-        service_unwatch_control_pid(s);
-
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
-
-                /* Before we start anything, let's clear up what might
-                 * be left from previous runs. */
-                cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
-
-                s->control_command_id = SERVICE_EXEC_START_PRE;
-
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       true,
-                                       false,
-                                       &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' task: %s", UNIT(s)->id, strerror(-r));
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-}
-
-static void service_enter_restart(Service *s) {
-        int r;
-        DBusError error;
-
-        assert(s);
-        dbus_error_init(&error);
-
-        if (UNIT(s)->job) {
-                log_info("Job pending for unit, delaying automatic restart.");
-
-                if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0)
-                        goto fail;
-        }
-
-        /* Any units that are bound to this service must also be
-         * restarted. We use JOB_RESTART (instead of the more obvious
-         * JOB_START) here so that those dependency jobs will be added
-         * as well. */
-        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, false, &error, NULL);
-        if (r < 0)
-                goto fail;
-
-        log_debug("%s scheduled restart job.", UNIT(s)->id);
-        return;
-
-fail:
-        log_warning("%s failed to schedule restart job: %s", UNIT(s)->id, bus_error(&error, -r));
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-
-        dbus_error_free(&error);
-}
-
-static void service_enter_reload(Service *s) {
-        int r;
-
-        assert(s);
-
-        service_unwatch_control_pid(s);
-
-        if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
-                s->control_command_id = SERVICE_EXEC_RELOAD;
-
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       false,
-                                       false,
-                                       &s->control_pid)) < 0)
-                        goto fail;
-
-                service_set_state(s, SERVICE_RELOAD);
-        } else
-                service_enter_running(s, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'reload' task: %s", UNIT(s)->id, strerror(-r));
-        s->reload_result = SERVICE_FAILURE_RESOURCES;
-        service_enter_running(s, SERVICE_SUCCESS);
-}
-
-static void service_run_next_control(Service *s) {
-        int r;
-
-        assert(s);
-        assert(s->control_command);
-        assert(s->control_command->command_next);
-
-        assert(s->control_command_id != SERVICE_EXEC_START);
-
-        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_command_id == SERVICE_EXEC_START_PRE ||
-                               s->control_command_id == SERVICE_EXEC_STOP_POST,
-                               false,
-                               &s->control_pid)) < 0)
-                goto fail;
-
-        return;
-
-fail:
-        log_warning("%s failed to run next control task: %s", UNIT(s)->id, strerror(-r));
-
-        if (s->state == SERVICE_START_PRE)
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-        else if (s->state == SERVICE_STOP)
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-        else if (s->state == SERVICE_STOP_POST)
-                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-        else if (s->state == SERVICE_RELOAD) {
-                s->reload_result = SERVICE_FAILURE_RESOURCES;
-                service_enter_running(s, SERVICE_SUCCESS);
-        } else
-                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_run_next_main(Service *s) {
-        pid_t pid;
-        int r;
-
-        assert(s);
-        assert(s->main_command);
-        assert(s->main_command->command_next);
-        assert(s->type == SERVICE_ONESHOT);
-
-        s->main_command = s->main_command->command_next;
-        service_unwatch_main_pid(s);
-
-        if ((r = service_spawn(s,
-                               s->main_command,
-                               false,
-                               true,
-                               true,
-                               true,
-                               true,
-                               s->notify_access != NOTIFY_NONE,
-                               &pid)) < 0)
-                goto fail;
-
-        service_set_main_pid(s, pid);
-
-        return;
-
-fail:
-        log_warning("%s failed to run next main task: %s", UNIT(s)->id, strerror(-r));
-        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static int service_start_limit_test(Service *s) {
-        assert(s);
-
-        if (ratelimit_test(&s->start_limit))
-                return 0;
-
-        switch (s->start_limit_action) {
-
-        case SERVICE_START_LIMIT_NONE:
-                log_warning("%s start request repeated too quickly, refusing to start.", UNIT(s)->id);
-                break;
-
-        case SERVICE_START_LIMIT_REBOOT: {
-                DBusError error;
-                int r;
-
-                dbus_error_init(&error);
-
-                log_warning("%s start request repeated too quickly, rebooting.", UNIT(s)->id);
-
-                r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
-                if (r < 0) {
-                        log_error("Failed to reboot: %s.", bus_error(&error, r));
-                        dbus_error_free(&error);
-                }
-
-                break;
-        }
-
-        case SERVICE_START_LIMIT_REBOOT_FORCE:
-                log_warning("%s start request repeated too quickly, forcibly rebooting.", UNIT(s)->id);
-                UNIT(s)->manager->exit_code = MANAGER_REBOOT;
-                break;
-
-        case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
-                log_warning("%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
-                reboot(RB_AUTOBOOT);
-                break;
-
-        default:
-                log_error("start limit action=%i", s->start_limit_action);
-                assert_not_reached("Unknown StartLimitAction.");
-        }
-
-        return -ECANCELED;
-}
-
-static int service_start(Unit *u) {
-        Service *s = SERVICE(u);
-        int r;
-
-        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_FAILED || s->state == SERVICE_AUTO_RESTART);
-
-        /* Make sure we don't enter a busy loop of some kind. */
-        r = service_start_limit_test(s);
-        if (r < 0) {
-                service_notify_sockets_dead(s, true);
-                return r;
-        }
-
-        s->result = SERVICE_SUCCESS;
-        s->reload_result = SERVICE_SUCCESS;
-        s->main_pid_known = false;
-        s->main_pid_alien = false;
-        s->forbid_restart = false;
-
-        service_enter_start_pre(s);
-        return 0;
-}
-
-static int service_stop(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        /* This is a user request, so don't do restarts on this
-         * shutdown. */
-        s->forbid_restart = true;
-
-        /* 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;
-
-        /* Don't allow a restart */
-        if (s->state == SERVICE_AUTO_RESTART) {
-                service_set_state(s, SERVICE_DEAD);
-                return 0;
-        }
-
-        /* If there's already something running we go directly into
-         * kill mode. */
-        if (s->state == SERVICE_START_PRE ||
-            s->state == SERVICE_START ||
-            s->state == SERVICE_START_POST ||
-            s->state == SERVICE_RELOAD) {
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
-                return 0;
-        }
-
-        assert(s->state == SERVICE_RUNNING ||
-               s->state == SERVICE_EXITED);
-
-        service_enter_stop(s, SERVICE_SUCCESS);
-        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, "result", service_result_to_string(s->result));
-        unit_serialize_item(u, f, "reload-result", service_result_to_string(s->reload_result));
-
-        if (s->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid);
-
-        if (s->main_pid_known && s->main_pid > 0)
-                unit_serialize_item_format(u, f, "main-pid", "%lu", (unsigned long) s->main_pid);
-
-        unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
-
-        if (s->status_text)
-                unit_serialize_item(u, f, "status-text", s->status_text);
-
-        /* FIXME: 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);
-        }
-
-        if (s->main_exec_status.pid > 0) {
-                unit_serialize_item_format(u, f, "main-exec-status-pid", "%lu", (unsigned long) s->main_exec_status.pid);
-                dual_timestamp_serialize(f, "main-exec-status-start", &s->main_exec_status.start_timestamp);
-                dual_timestamp_serialize(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp);
-
-                if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
-                        unit_serialize_item_format(u, f, "main-exec-status-code", "%i", s->main_exec_status.code);
-                        unit_serialize_item_format(u, f, "main-exec-status-status", "%i", s->main_exec_status.status);
-                }
-        }
-        if (dual_timestamp_is_set(&s->watchdog_timestamp))
-                dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
-
-        return 0;
-}
-
-static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Service *s = SERVICE(u);
-
-        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, "result")) {
-                ServiceResult f;
-
-                f = service_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != SERVICE_SUCCESS)
-                        s->result = f;
-
-        } else if (streq(key, "reload-result")) {
-                ServiceResult f;
-
-                f = service_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse reload result value %s", value);
-                else if (f != SERVICE_SUCCESS)
-                        s->reload_result = f;
-
-        } else if (streq(key, "control-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        s->control_pid = pid;
-        } else if (streq(key, "main-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_debug("Failed to parse main-pid value %s", value);
-                else
-                        service_set_main_pid(s, (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, "status-text")) {
-                char *t;
-
-                if ((t = strdup(value))) {
-                        free(s->status_text);
-                        s->status_text = t;
-                }
-
-        } 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 if (streq(key, "main-exec-status-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_debug("Failed to parse main-exec-status-pid value %s", value);
-                else
-                        s->main_exec_status.pid = pid;
-        } else if (streq(key, "main-exec-status-code")) {
-                int i;
-
-                if (safe_atoi(value, &i) < 0)
-                        log_debug("Failed to parse main-exec-status-code value %s", value);
-                else
-                        s->main_exec_status.code = i;
-        } else if (streq(key, "main-exec-status-status")) {
-                int i;
-
-                if (safe_atoi(value, &i) < 0)
-                        log_debug("Failed to parse main-exec-status-status value %s", value);
-                else
-                        s->main_exec_status.status = i;
-        } else if (streq(key, "main-exec-status-start"))
-                dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp);
-        else if (streq(key, "main-exec-status-exit"))
-                dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp);
-        else if (streq(key, "watchdog-timestamp"))
-                dual_timestamp_deserialize(value, &s->watchdog_timestamp);
-        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);
-
-        /* Never clean up services that still have a process around,
-         * even if the service is formally dead. */
-        if (cgroup_good(s) > 0 ||
-            main_pid_good(s) > 0 ||
-            control_pid_good(s) > 0)
-                return true;
-
-#ifdef HAVE_SYSV_COMPAT
-        if (s->sysv_path)
-                return true;
-#endif
-
-        return false;
-}
-
-static bool service_check_snapshot(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return !s->got_socket_fd;
-}
-
-static int service_retry_pid_file(Service *s) {
-        int r;
-
-        assert(s->pid_file);
-        assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
-
-        r = service_load_pid_file(s, false);
-        if (r < 0)
-                return r;
-
-        service_unwatch_pid_file(s);
-
-        service_enter_running(s, SERVICE_SUCCESS);
-        return 0;
-}
-
-static int service_watch_pid_file(Service *s) {
-        int r;
-
-        log_debug("Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
-        r = path_spec_watch(s->pid_file_pathspec, UNIT(s));
-        if (r < 0)
-                goto fail;
-
-        /* the pidfile might have appeared just before we set the watch */
-        service_retry_pid_file(s);
-
-        return 0;
-fail:
-        log_error("Failed to set a watch for %s's PID file %s: %s",
-                  UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r));
-        service_unwatch_pid_file(s);
-        return r;
-}
-
-static int service_demand_pid_file(Service *s) {
-        PathSpec *ps;
-
-        assert(s->pid_file);
-        assert(!s->pid_file_pathspec);
-
-        ps = new0(PathSpec, 1);
-        if (!ps)
-                return -ENOMEM;
-
-        ps->path = strdup(s->pid_file);
-        if (!ps->path) {
-                free(ps);
-                return -ENOMEM;
-        }
-
-        path_kill_slashes(ps->path);
-
-        /* PATH_CHANGED would not be enough. There are daemons (sendmail) that
-         * keep their PID file open all the time. */
-        ps->type = PATH_MODIFIED;
-        ps->inotify_fd = -1;
-
-        s->pid_file_pathspec = ps;
-
-        return service_watch_pid_file(s);
-}
-
-static void service_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-        assert(fd >= 0);
-        assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
-        assert(s->pid_file_pathspec);
-        assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
-
-        log_debug("inotify event for %s", u->id);
-
-        if (path_spec_fd_event(s->pid_file_pathspec, events) < 0)
-                goto fail;
-
-        if (service_retry_pid_file(s) == 0)
-                return;
-
-        if (service_watch_pid_file(s) < 0)
-                goto fail;
-
-        return;
-fail:
-        service_unwatch_pid_file(s);
-        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-        Service *s = SERVICE(u);
-        ServiceResult f;
-
-        assert(s);
-        assert(pid >= 0);
-
-        if (UNIT(s)->fragment_path ? is_clean_exit(code, status) : is_clean_exit_lsb(code, status))
-                f = SERVICE_SUCCESS;
-        else if (code == CLD_EXITED)
-                f = SERVICE_FAILURE_EXIT_CODE;
-        else if (code == CLD_KILLED)
-                f = SERVICE_FAILURE_SIGNAL;
-        else if (code == CLD_DUMPED)
-                f = SERVICE_FAILURE_CORE_DUMP;
-        else
-                assert_not_reached("Unknown code");
-
-        if (s->main_pid == pid) {
-                /* Forking services may occasionally move to a new PID.
-                 * As long as they update the PID file before exiting the old
-                 * PID, they're fine. */
-                if (service_load_pid_file(s, false) == 0)
-                        return;
-
-                s->main_pid = 0;
-                exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
-
-                /* If this is not a forking service than the main
-                 * process got started and hence we copy the exit
-                 * status so that it is recorded both as main and as
-                 * control process exit status */
-                if (s->main_command) {
-                        s->main_command->exec_status = s->main_exec_status;
-
-                        if (s->main_command->ignore)
-                                f = SERVICE_SUCCESS;
-                }
-
-                log_full(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
-                         "%s: main process exited, code=%s, status=%i", u->id, sigchld_code_to_string(code), status);
-
-                if (f != SERVICE_SUCCESS)
-                        s->result = f;
-
-                if (s->main_command &&
-                    s->main_command->command_next &&
-                    f == SERVICE_SUCCESS) {
-
-                        /* There is another command to *
-                         * execute, so let's do that. */
-
-                        log_debug("%s running next main command for state %s", u->id, service_state_to_string(s->state));
-                        service_run_next_main(s);
-
-                } else {
-
-                        /* The service exited, so the service is officially
-                         * gone. */
-                        s->main_command = NULL;
-
-                        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:
-                                if (s->type == SERVICE_ONESHOT) {
-                                        /* This was our main goal, so let's go on */
-                                        if (f == SERVICE_SUCCESS)
-                                                service_enter_start_post(s);
-                                        else
-                                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
-                                        break;
-                                } else {
-                                        assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
-
-                                        /* Fall through */
-                                }
-
-                        case SERVICE_RUNNING:
-                                service_enter_running(s, f);
-                                break;
-
-                        case SERVICE_STOP_SIGTERM:
-                        case SERVICE_STOP_SIGKILL:
-
-                                if (!control_pid_good(s))
-                                        service_enter_stop_post(s, f);
-
-                                /* 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) {
-
-                s->control_pid = 0;
-
-                if (s->control_command) {
-                        exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
-
-                        if (s->control_command->ignore)
-                                f = SERVICE_SUCCESS;
-                }
-
-                log_full(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
-                         "%s: control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
-                if (f != SERVICE_SUCCESS)
-                        s->result = f;
-
-                if (s->control_command &&
-                    s->control_command->command_next &&
-                    f == SERVICE_SUCCESS) {
-
-                        /* There is another command to *
-                         * execute, so let's do that. */
-
-                        log_debug("%s running next control command for state %s", u->id, service_state_to_string(s->state));
-                        service_run_next_control(s);
-
-                } 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->id, service_state_to_string(s->state));
-
-                        switch (s->state) {
-
-                        case SERVICE_START_PRE:
-                                if (f == SERVICE_SUCCESS)
-                                        service_enter_start(s);
-                                else
-                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
-                                break;
-
-                        case SERVICE_START:
-                                assert(s->type == SERVICE_FORKING);
-
-                                if (f != SERVICE_SUCCESS) {
-                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
-                                        break;
-                                }
-
-                                if (s->pid_file) {
-                                        bool has_start_post;
-                                        int r;
-
-                                        /* Let's try to load the pid file here if we can.
-                                         * The PID file might actually be created by a START_POST
-                                         * script. In that case don't worry if the loading fails. */
-
-                                        has_start_post = !!s->exec_command[SERVICE_EXEC_START_POST];
-                                        r = service_load_pid_file(s, !has_start_post);
-                                        if (!has_start_post && r < 0) {
-                                                r = service_demand_pid_file(s);
-                                                if (r < 0 || !cgroup_good(s))
-                                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-                                                break;
-                                        }
-                                } else
-                                        service_search_main_pid(s);
-
-                                service_enter_start_post(s);
-                                break;
-
-                        case SERVICE_START_POST:
-                                if (f != SERVICE_SUCCESS) {
-                                        service_enter_stop(s, f);
-                                        break;
-                                }
-
-                                if (s->pid_file) {
-                                        int r;
-
-                                        r = service_load_pid_file(s, true);
-                                        if (r < 0) {
-                                                r = service_demand_pid_file(s);
-                                                if (r < 0 || !cgroup_good(s))
-                                                        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-                                                break;
-                                        }
-                                } else
-                                        service_search_main_pid(s);
-
-                                service_enter_running(s, SERVICE_SUCCESS);
-                                break;
-
-                        case SERVICE_RELOAD:
-                                if (f == SERVICE_SUCCESS) {
-                                        service_load_pid_file(s, true);
-                                        service_search_main_pid(s);
-                                }
-
-                                s->reload_result = f;
-                                service_enter_running(s, SERVICE_SUCCESS);
-                                break;
-
-                        case SERVICE_STOP:
-                                service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
-                                break;
-
-                        case SERVICE_STOP_SIGTERM:
-                        case SERVICE_STOP_SIGKILL:
-                                if (main_pid_good(s) <= 0)
-                                        service_enter_stop_post(s, f);
-
-                                /* 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, f, true);
-                                break;
-
-                        default:
-                                assert_not_reached("Uh, control process died at wrong time.");
-                        }
-                }
-        }
-
-        /* Notify clients about changed exit status */
-        unit_add_to_dbus_queue(u);
-}
-
-static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-        assert(elapsed == 1);
-
-        if (w == &s->watchdog_watch) {
-                service_handle_watchdog(s);
-                return;
-        }
-
-        assert(w == &s->timer_watch);
-
-        switch (s->state) {
-
-        case SERVICE_START_PRE:
-        case SERVICE_START:
-                log_warning("%s operation timed out. Terminating.", u->id);
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
-                break;
-
-        case SERVICE_START_POST:
-                log_warning("%s operation timed out. Stopping.", u->id);
-                service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
-                break;
-
-        case SERVICE_RELOAD:
-                log_warning("%s operation timed out. Stopping.", u->id);
-                s->reload_result = SERVICE_FAILURE_TIMEOUT;
-                service_enter_running(s, SERVICE_SUCCESS);
-                break;
-
-        case SERVICE_STOP:
-                log_warning("%s stopping timed out. Terminating.", u->id);
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
-                break;
-
-        case SERVICE_STOP_SIGTERM:
-                if (s->exec_context.send_sigkill) {
-                        log_warning("%s stopping timed out. Killing.", u->id);
-                        service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s stopping timed out. Skipping SIGKILL.", u->id);
-                        service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
-                }
-
-                break;
-
-        case SERVICE_STOP_SIGKILL:
-                /* Uh, we 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->id);
-                service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
-                break;
-
-        case SERVICE_STOP_POST:
-                log_warning("%s stopping timed out (2). Terminating.", u->id);
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
-                break;
-
-        case SERVICE_FINAL_SIGTERM:
-                if (s->exec_context.send_sigkill) {
-                        log_warning("%s stopping timed out (2). Killing.", u->id);
-                        service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->id);
-                        service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
-                }
-
-                break;
-
-        case SERVICE_FINAL_SIGKILL:
-                log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id);
-                service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
-                break;
-
-        case SERVICE_AUTO_RESTART:
-                log_info("%s holdoff time over, scheduling restart.", u->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->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_START:
-        case SERVICE_START_POST:
-                /* If we were hoping for the daemon to write its PID file,
-                 * we can give up now. */
-                if (s->pid_file_pathspec) {
-                        log_warning("%s never wrote its PID file. Failing.", UNIT(s)->id);
-                        service_unwatch_pid_file(s);
-                        if (s->state == SERVICE_START)
-                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-                        else
-                                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-                }
-                break;
-
-        case SERVICE_RUNNING:
-                /* service_enter_running() will figure out what to do */
-                service_enter_running(s, SERVICE_SUCCESS);
-                break;
-
-        case SERVICE_STOP_SIGTERM:
-        case SERVICE_STOP_SIGKILL:
-
-                if (main_pid_good(s) <= 0 && !control_pid_good(s))
-                        service_enter_stop_post(s, SERVICE_SUCCESS);
-
-                break;
-
-        case SERVICE_FINAL_SIGTERM:
-        case SERVICE_FINAL_SIGKILL:
-                if (main_pid_good(s) <= 0 && !control_pid_good(s))
-                        service_enter_dead(s, SERVICE_SUCCESS, SERVICE_SUCCESS);
-
-                break;
-
-        default:
-                ;
-        }
-}
-
-static void service_notify_message(Unit *u, pid_t pid, char **tags) {
-        Service *s = SERVICE(u);
-        const char *e;
-
-        assert(u);
-
-        if (s->notify_access == NOTIFY_NONE) {
-                log_warning("%s: Got notification message from PID %lu, but reception is disabled.",
-                            u->id, (unsigned long) pid);
-                return;
-        }
-
-        if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
-                log_warning("%s: Got notification message from PID %lu, but reception only permitted for PID %lu",
-                            u->id, (unsigned long) pid, (unsigned long) s->main_pid);
-                return;
-        }
-
-        log_debug("%s: Got message", u->id);
-
-        /* Interpret MAINPID= */
-        if ((e = strv_find_prefix(tags, "MAINPID=")) &&
-            (s->state == SERVICE_START ||
-             s->state == SERVICE_START_POST ||
-             s->state == SERVICE_RUNNING ||
-             s->state == SERVICE_RELOAD)) {
-
-                if (parse_pid(e + 8, &pid) < 0)
-                        log_warning("Failed to parse notification message %s", e);
-                else {
-                        log_debug("%s: got %s", u->id, e);
-                        service_set_main_pid(s, pid);
-                }
-        }
-
-        /* Interpret READY= */
-        if (s->type == SERVICE_NOTIFY &&
-            s->state == SERVICE_START &&
-            strv_find(tags, "READY=1")) {
-                log_debug("%s: got READY=1", u->id);
-
-                service_enter_start_post(s);
-        }
-
-        /* Interpret STATUS= */
-        e = strv_find_prefix(tags, "STATUS=");
-        if (e) {
-                char *t;
-
-                if (e[7]) {
-
-                        if (!utf8_is_valid(e+7)) {
-                                log_warning("Status message in notification is not UTF-8 clean.");
-                                return;
-                        }
-
-                        t = strdup(e+7);
-                        if (!t) {
-                                log_error("Failed to allocate string.");
-                                return;
-                        }
-
-                        log_debug("%s: got %s", u->id, e);
-
-                        free(s->status_text);
-                        s->status_text = t;
-                } else {
-                        free(s->status_text);
-                        s->status_text = NULL;
-                }
-
-        }
-        if (strv_find(tags, "WATCHDOG=1")) {
-                log_debug("%s: got WATCHDOG=1", u->id);
-                service_reset_watchdog(s);
-        }
-
-        /* Notify clients about changed status or main pid */
-        unit_add_to_dbus_queue(u);
-}
-
-#ifdef HAVE_SYSV_COMPAT
-
-#ifdef TARGET_SUSE
-static void sysv_facility_in_insserv_conf(Manager *mgr) {
-        FILE *f=NULL;
-        int r;
-
-        if (!(f = fopen("/etc/insserv.conf", "re"))) {
-                r = errno == ENOENT ? 0 : -errno;
-                goto finish;
-        }
-
-        while (!feof(f)) {
-                char l[LINE_MAX], *t;
-                char **parsed = NULL;
-
-                if (!fgets(l, sizeof(l), f)) {
-                        if (feof(f))
-                                break;
-
-                        r = -errno;
-                        log_error("Failed to read configuration file '/etc/insserv.conf': %s", strerror(-r));
-                        goto finish;
-                }
-
-                t = strstrip(l);
-                if (*t != '$' && *t != '<')
-                        continue;
-
-                parsed = strv_split(t,WHITESPACE);
-                /* we ignore <interactive>, not used, equivalent to X-Interactive */
-                if (parsed && !startswith_no_case (parsed[0], "<interactive>")) {
-                        char *facility;
-                        Unit *u;
-                        if (sysv_translate_facility(parsed[0], NULL, &facility) < 0)
-                                continue;
-                        if ((u = manager_get_unit(mgr, facility)) && (u->type == UNIT_TARGET)) {
-                                UnitDependency e;
-                                char *dep = NULL, *name, **j;
-
-                                STRV_FOREACH (j, parsed+1) {
-                                        if (*j[0]=='+') {
-                                                e = UNIT_WANTS;
-                                                name = *j+1;
-                                        }
-                                        else {
-                                                e = UNIT_REQUIRES;
-                                                name = *j;
-                                        }
-                                        if (sysv_translate_facility(name, NULL, &dep) < 0)
-                                                continue;
-
-                                        r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, e, dep, NULL, true);
-                                        free(dep);
-                                }
-                        }
-                        free(facility);
-                }
-                strv_free(parsed);
-        }
-finish:
-        if (f)
-                fclose(f);
-
-}
-#endif
-
-static int service_enumerate(Manager *m) {
-        char **p;
-        unsigned i;
-        DIR *d = NULL;
-        char *path = NULL, *fpath = NULL, *name = NULL;
-        Set *runlevel_services[ELEMENTSOF(rcnd_table)], *shutdown_services = NULL;
-        Unit *service;
-        Iterator j;
-        int r;
-
-        assert(m);
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return 0;
-
-        zero(runlevel_services);
-
-        STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path)
-                for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
-                        struct dirent *de;
-
-                        free(path);
-                        path = join(*p, "/", rcnd_table[i].path, NULL);
-                        if (!path) {
-                                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))) {
-                                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 = join(path, "/", de->d_name, NULL);
-                                if (!fpath) {
-                                        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 = sysv_translate_name(de->d_name + 3))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                if ((r = manager_load_unit_prepare(m, name, NULL, NULL, &service)) < 0) {
-                                        log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
-                                        continue;
-                                }
-
-                                if (de->d_name[0] == 'S')  {
-
-                                        if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) {
-                                                SERVICE(service)->sysv_start_priority_from_rcnd =
-                                                        MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd);
-
-                                                SERVICE(service)->sysv_enabled = true;
-                                        }
-
-                                        if ((r = set_ensure_allocated(&runlevel_services[i], trivial_hash_func, trivial_compare_func)) < 0)
-                                                goto finish;
-
-                                        if ((r = set_put(runlevel_services[i], service)) < 0)
-                                                goto finish;
-
-                                } else if (de->d_name[0] == 'K' &&
-                                           (rcnd_table[i].type == RUNLEVEL_DOWN ||
-                                            rcnd_table[i].type == RUNLEVEL_SYSINIT)) {
-
-                                        if ((r = set_ensure_allocated(&shutdown_services, trivial_hash_func, trivial_compare_func)) < 0)
-                                                goto finish;
-
-                                        if ((r = set_put(shutdown_services, service)) < 0)
-                                                goto finish;
-                                }
-                        }
-                }
-
-        /* Now we loaded all stubs and are aware of the lowest
-        start-up priority for all services, not let's actually load
-        the services, this will also tell us which services are
-        actually native now */
-        manager_dispatch_load_queue(m);
-
-        /* If this is a native service, rely on native ways to pull in
-         * a service, don't pull it in via sysv rcN.d links. */
-        for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
-                SET_FOREACH(service, runlevel_services[i], j) {
-                        service = unit_follow_merge(service);
-
-                        if (service->fragment_path)
-                                continue;
-
-                        if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0)
-                                goto finish;
-                }
-
-        /* 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 distinguish here
-         * between the runlevels 0 and 6 and just add them to the
-         * special shutdown target. On SUSE the boot.d/ runlevel is
-         * also used for shutdown, so we add links for that too to the
-         * shutdown target.*/
-        SET_FOREACH(service, shutdown_services, j) {
-                service = unit_follow_merge(service);
-
-                if (service->fragment_path)
-                        continue;
-
-                if ((r = unit_add_two_dependencies_by_name(service, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-#ifdef TARGET_SUSE
-        sysv_facility_in_insserv_conf (m);
-#endif
-
-finish:
-        free(path);
-        free(fpath);
-        free(name);
-
-        for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
-                set_free(runlevel_services[i]);
-        set_free(shutdown_services);
-
-        if (d)
-                closedir(d);
-
-        return r;
-}
-#endif
-
-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->id, name, old_owner, new_owner);
-        else if (old_owner)
-                log_debug("%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
-        else
-                log_debug("%s's D-Bus name %s now registered by %s", u->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, SERVICE_SUCCESS);
-                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->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->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))
-                service_set_main_pid(s, pid);
-}
-
-int service_set_socket_fd(Service *s, int fd, Socket *sock) {
-
-        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)->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;
-
-        unit_ref_set(&s->accept_socket, UNIT(sock));
-
-        return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
-}
-
-static void service_reset_failed(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        if (s->state == SERVICE_FAILED)
-                service_set_state(s, SERVICE_DEAD);
-
-        s->result = SERVICE_SUCCESS;
-        s->reload_result = SERVICE_SUCCESS;
-}
-
-static bool service_need_daemon_reload(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-#ifdef HAVE_SYSV_COMPAT
-        if (s->sysv_path) {
-                struct stat st;
-
-                zero(st);
-                if (stat(s->sysv_path, &st) < 0)
-                        /* What, cannot access this anymore? */
-                        return true;
-
-                if (s->sysv_mtime > 0 &&
-                    timespec_load(&st.st_mtim) != s->sysv_mtime)
-                        return true;
-        }
-#endif
-
-        return false;
-}
-
-static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
-        Service *s = SERVICE(u);
-        int r = 0;
-        Set *pid_set = NULL;
-
-        assert(s);
-
-        if (s->main_pid <= 0 && who == KILL_MAIN) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
-                return -ESRCH;
-        }
-
-        if (s->control_pid <= 0 && who == KILL_CONTROL) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
-                return -ESRCH;
-        }
-
-        if (who == KILL_CONTROL || who == KILL_ALL)
-                if (s->control_pid > 0)
-                        if (kill(s->control_pid, signo) < 0)
-                                r = -errno;
-
-        if (who == KILL_MAIN || who == KILL_ALL)
-                if (s->main_pid > 0)
-                        if (kill(s->main_pid, signo) < 0)
-                                r = -errno;
-
-        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
-                int q;
-
-                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
-                        return -ENOMEM;
-
-                /* Exclude the control/main pid from being killed via the cgroup */
-                if (s->control_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
-                                r = q;
-                                goto finish;
-                        }
-
-                if (s->main_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) {
-                                r = q;
-                                goto finish;
-                        }
-
-                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
-        }
-
-finish:
-        if (pid_set)
-                set_free(pid_set);
-
-        return r;
-}
-
-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_FAILED] = "failed",
-        [SERVICE_AUTO_RESTART] = "auto-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
-
-static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
-        [SERVICE_RESTART_NO] = "no",
-        [SERVICE_RESTART_ON_SUCCESS] = "on-success",
-        [SERVICE_RESTART_ON_FAILURE] = "on-failure",
-        [SERVICE_RESTART_ON_ABORT] = "on-abort",
-        [SERVICE_RESTART_ALWAYS] = "always"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
-
-static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
-        [SERVICE_SIMPLE] = "simple",
-        [SERVICE_FORKING] = "forking",
-        [SERVICE_ONESHOT] = "oneshot",
-        [SERVICE_DBUS] = "dbus",
-        [SERVICE_NOTIFY] = "notify"
-};
-
-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);
-
-static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
-        [NOTIFY_NONE] = "none",
-        [NOTIFY_MAIN] = "main",
-        [NOTIFY_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
-
-static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
-        [SERVICE_SUCCESS] = "success",
-        [SERVICE_FAILURE_RESOURCES] = "resources",
-        [SERVICE_FAILURE_TIMEOUT] = "timeout",
-        [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
-        [SERVICE_FAILURE_SIGNAL] = "signal",
-        [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
-        [SERVICE_FAILURE_WATCHDOG] = "watchdog"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
-
-static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = {
-        [SERVICE_START_LIMIT_NONE] = "none",
-        [SERVICE_START_LIMIT_REBOOT] = "reboot",
-        [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force",
-        [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate"
-};
-DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
-
-const UnitVTable service_vtable = {
-        .suffix = ".service",
-        .object_size = sizeof(Service),
-        .sections =
-                "Unit\0"
-                "Service\0"
-                "Install\0",
-        .show_status = true,
-
-        .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,
-
-        .kill = service_kill,
-
-        .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,
-        .fd_event = service_fd_event,
-
-        .reset_failed = service_reset_failed,
-
-        .need_daemon_reload = service_need_daemon_reload,
-
-        .cgroup_notify_empty = service_cgroup_notify_event,
-        .notify_message = service_notify_message,
-
-        .bus_name_owner_change = service_bus_name_owner_change,
-        .bus_query_pid_done = service_bus_query_pid_done,
-
-        .bus_interface = "org.freedesktop.systemd1.Service",
-        .bus_message_handler = bus_service_message_handler,
-        .bus_invalidating_properties =  bus_service_invalidating_properties,
-
-#ifdef HAVE_SYSV_COMPAT
-        .enumerate = service_enumerate
-#endif
-};
diff --git a/src/service.h b/src/service.h
deleted file mode 100644
index 60b1051..0000000
--- a/src/service.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "path.h"
-#include "ratelimit.h"
-#include "service.h"
-
-typedef enum ServiceState {
-        SERVICE_DEAD,
-        SERVICE_START_PRE,
-        SERVICE_START,
-        SERVICE_START_POST,
-        SERVICE_RUNNING,
-        SERVICE_EXITED,            /* Nothing is running anymore, but RemainAfterExit is true hence 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_FAILED,
-        SERVICE_AUTO_RESTART,
-        _SERVICE_STATE_MAX,
-        _SERVICE_STATE_INVALID = -1
-} ServiceState;
-
-typedef enum ServiceRestart {
-        SERVICE_RESTART_NO,
-        SERVICE_RESTART_ON_SUCCESS,
-        SERVICE_RESTART_ON_FAILURE,
-        SERVICE_RESTART_ON_ABORT,
-        SERVICE_RESTART_ALWAYS,
-        _SERVICE_RESTART_MAX,
-        _SERVICE_RESTART_INVALID = -1
-} ServiceRestart;
-
-typedef enum ServiceType {
-        SERVICE_SIMPLE,   /* we fork and go on right-away (i.e. modern socket activated daemons) */
-        SERVICE_FORKING,  /* forks by itself (i.e. traditional daemons) */
-        SERVICE_ONESHOT,  /* 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_NOTIFY,   /* we fork and wait until a daemon sends us a ready message with sd_notify() */
-        _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;
-
-typedef enum NotifyAccess {
-        NOTIFY_NONE,
-        NOTIFY_ALL,
-        NOTIFY_MAIN,
-        _NOTIFY_ACCESS_MAX,
-        _NOTIFY_ACCESS_INVALID = -1
-} NotifyAccess;
-
-typedef enum ServiceResult {
-        SERVICE_SUCCESS,
-        SERVICE_FAILURE_RESOURCES,
-        SERVICE_FAILURE_TIMEOUT,
-        SERVICE_FAILURE_EXIT_CODE,
-        SERVICE_FAILURE_SIGNAL,
-        SERVICE_FAILURE_CORE_DUMP,
-        SERVICE_FAILURE_WATCHDOG,
-        _SERVICE_RESULT_MAX,
-        _SERVICE_RESULT_INVALID = -1
-} ServiceResult;
-
-typedef enum StartLimitAction {
-        SERVICE_START_LIMIT_NONE,
-        SERVICE_START_LIMIT_REBOOT,
-        SERVICE_START_LIMIT_REBOOT_FORCE,
-        SERVICE_START_LIMIT_REBOOT_IMMEDIATE,
-        _SERVICE_START_LIMIT_MAX,
-        _SERVICE_START_LIMIT_INVALID = -1
-} StartLimitAction;
-
-struct Service {
-        Unit 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;
-
-        dual_timestamp watchdog_timestamp;
-        usec_t watchdog_usec;
-        Watch watchdog_watch;
-
-        ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        ServiceState state, deserialized_state;
-
-        /* The exit status of the real main process */
-        ExecStatus main_exec_status;
-
-        /* The currently executed control process */
-        ExecCommand *control_command;
-
-        /* The currently executed main process, which may be NULL if
-         * the main process got started via forking mode and not by
-         * us */
-        ExecCommand *main_command;
-
-        /* The ID of the control command currently being executed */
-        ServiceExecCommand control_command_id;
-
-        pid_t main_pid, control_pid;
-        int socket_fd;
-
-        int fsck_passno;
-
-        bool permissions_start_only;
-        bool root_directory_start_only;
-        bool remain_after_exit;
-        bool guess_main_pid;
-
-        /* If we shut down, remember why */
-        ServiceResult result;
-        ServiceResult reload_result;
-
-        bool main_pid_known:1;
-        bool main_pid_alien:1;
-        bool bus_name_good:1;
-        bool forbid_restart:1;
-        bool got_socket_fd:1;
-#ifdef HAVE_SYSV_COMPAT
-        bool sysv_has_lsb:1;
-        bool sysv_enabled:1;
-        int sysv_start_priority_from_rcnd;
-        int sysv_start_priority;
-
-        char *sysv_path;
-        char *sysv_runlevels;
-        usec_t sysv_mtime;
-#endif
-
-        char *bus_name;
-
-        char *status_text;
-
-        RateLimit start_limit;
-        StartLimitAction start_limit_action;
-
-
-        UnitRef accept_socket;
-
-        Watch timer_watch;
-        PathSpec *pid_file_pathspec;
-
-        NotifyAccess notify_access;
-};
-
-extern const UnitVTable service_vtable;
-
-struct Socket;
-
-int service_set_socket_fd(Service *s, int fd, struct Socket *socket);
-
-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);
-
-const char* notify_access_to_string(NotifyAccess i);
-NotifyAccess notify_access_from_string(const char *s);
-
-const char* service_result_to_string(ServiceResult i);
-ServiceResult service_result_from_string(const char *s);
-
-const char* start_limit_action_to_string(StartLimitAction i);
-StartLimitAction start_limit_action_from_string(const char *s);
-
-#endif
diff --git a/src/snapshot.c b/src/snapshot.c
deleted file mode 100644
index 82ec510..0000000
--- a/src/snapshot.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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"
-#include "bus-errors.h"
-
-static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
-        [SNAPSHOT_DEAD] = UNIT_INACTIVE,
-        [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
-};
-
-static void snapshot_init(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(UNIT(s)->load_state == UNIT_STUB);
-
-        UNIT(s)->ignore_on_isolate = true;
-        UNIT(s)->ignore_on_snapshot = true;
-}
-
-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)->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], true);
-}
-
-static int snapshot_load(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        /* Make sure that only snapshots created via snapshot_create()
-         * can be loaded */
-        if (!s->by_snapshot_create && UNIT(s)->manager->n_reloading <= 0)
-                return -ENOENT;
-
-        u->load_state = UNIT_LOADED;
-        return 0;
-}
-
-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->dependencies[UNIT_WANTS], i)
-                unit_serialize_item(u, f, "wants", other->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, "wants")) {
-
-                if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, 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, DBusError *e, 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, false)) {
-                        dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
-                        return -EINVAL;
-                }
-
-                if (unit_name_to_type(name) != UNIT_SNAPSHOT) {
-                        dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name);
-                        return -EINVAL;
-                }
-
-                if (manager_get_unit(m, name)) {
-                        dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", 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_prepare(m, name, NULL, e, &u);
-        free(n);
-
-        if (r < 0)
-                goto fail;
-
-        SNAPSHOT(u)->by_snapshot_create = true;
-        manager_dispatch_load_queue(m);
-        assert(u->load_state == UNIT_LOADED);
-
-        HASHMAP_FOREACH_KEY(other, k, m->units, i) {
-
-                if (other->ignore_on_snapshot)
-                        continue;
-
-                if (k != other->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_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, 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",
-        .object_size = sizeof(Snapshot),
-
-        .no_alias = true,
-        .no_instances = true,
-        .no_gc = true,
-
-        .init = snapshot_init,
-
-        .load = snapshot_load,
-        .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_interface = "org.freedesktop.systemd1.Snapshot",
-        .bus_message_handler = bus_snapshot_message_handler
-};
diff --git a/src/snapshot.h b/src/snapshot.h
deleted file mode 100644
index bf92e99..0000000
--- a/src/snapshot.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 {
-        Unit meta;
-
-        SnapshotState state, deserialized_state;
-
-        bool cleanup;
-        bool by_snapshot_create:1;
-};
-
-extern const UnitVTable snapshot_vtable;
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, 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.c b/src/socket.c
deleted file mode 100644
index 5b24b34..0000000
--- a/src/socket.c
+++ /dev/null
@@ -1,2218 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <mqueue.h>
-
-#include "unit.h"
-#include "socket.h"
-#include "netinet/tcp.h"
-#include "log.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "unit-name.h"
-#include "dbus-socket.h"
-#include "missing.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "label.h"
-#include "exit-status.h"
-#include "def.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_FAILED] = UNIT_FAILED
-};
-
-static void socket_init(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        s->backlog = SOMAXCONN;
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        s->directory_mode = 0755;
-        s->socket_mode = 0666;
-
-        s->max_connections = 64;
-
-        s->priority = -1;
-        s->ip_tos = -1;
-        s->ip_ttl = -1;
-        s->mark = -1;
-
-        exec_context_init(&s->exec_context);
-        s->exec_context.std_output = u->manager->default_std_output;
-        s->exec_context.std_error = u->manager->default_std_error;
-
-        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);
-
-        unit_ref_unset(&s->service);
-
-        free(s->tcp_congestion);
-        s->tcp_congestion = NULL;
-
-        free(s->bind_to_device);
-        s->bind_to_device = NULL;
-
-        unit_unwatch_timer(u, &s->timer_watch);
-}
-
-static int socket_instantiate_service(Socket *s) {
-        char *prefix, *name;
-        int r;
-        Unit *u;
-
-        assert(s);
-
-        /* This fills in s->service if it isn't filled in yet. For
-         * Accept=yes sockets we create the next connection service
-         * here. For Accept=no this is mostly a NOP since the service
-         * is figured out at load time anyway. */
-
-        if (UNIT_DEREF(s->service))
-                return 0;
-
-        assert(s->accept);
-
-        if (!(prefix = unit_name_to_prefix(UNIT(s)->id)))
-                return -ENOMEM;
-
-        r = asprintf(&name, "%s@%u.service", prefix, s->n_accepted);
-        free(prefix);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        r = manager_load_unit(UNIT(s)->manager, name, NULL, NULL, &u);
-        free(name);
-
-        if (r < 0)
-                return r;
-
-#ifdef HAVE_SYSV_COMPAT
-        if (SERVICE(u)->sysv_path) {
-                log_error("Using SysV services for socket activation is not supported. Refusing.");
-                return -ENOENT;
-        }
-#endif
-
-        u->no_gc = true;
-        unit_ref_set(&s->service, u);
-
-        return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
-}
-
-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)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!s->ports) {
-                log_error("%s lacks Listen setting. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        if (s->accept && have_non_accept_socket(s)) {
-                log_error("%s configured for accepting sockets, but sockets are non-accepting. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        if (s->accept && s->max_connections <= 0) {
-                log_error("%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        if (s->accept && UNIT_DEREF(s->service)) {
-                log_error("Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
-                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->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 if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) {
-                        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 (UNIT(s)->load_state != UNIT_LOADED ||
-            UNIT(m)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!socket_needs_mount(s, m->where))
-                return 0;
-
-        if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
-                return r;
-
-        return 0;
-}
-
-static int socket_add_mount_links(Socket *s) {
-        Unit *other;
-        int r;
-
-        assert(s);
-
-        LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_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_add_default_dependencies(Socket *s) {
-        int r;
-        assert(s);
-
-        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
-                if ((r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
-                        return r;
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
-                        return r;
-        }
-
-        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static bool socket_has_exec(Socket *s) {
-        unsigned i;
-        assert(s);
-
-        for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++)
-                if (s->exec_command[i])
-                        return true;
-
-        return false;
-}
-
-static int socket_load(Unit *u) {
-        Socket *s = SOCKET(u);
-        int r;
-
-        assert(u);
-        assert(u->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->load_state == UNIT_LOADED) {
-
-                if (have_non_accept_socket(s)) {
-
-                        if (!UNIT_DEREF(s->service)) {
-                                Unit *x;
-
-                                r = unit_load_related_unit(u, ".service", &x);
-                                if (r < 0)
-                                        return r;
-
-                                unit_ref_set(&s->service, x);
-                        }
-
-                        r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true);
-                        if (r < 0)
-                                return r;
-                }
-
-                if ((r = socket_add_mount_links(s)) < 0)
-                        return r;
-
-                if ((r = socket_add_device_link(s)) < 0)
-                        return r;
-
-                if (socket_has_exec(s))
-                        if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
-                                return r;
-
-                if ((r = unit_add_default_cgroups(u)) < 0)
-                        return r;
-
-                if (UNIT(s)->default_dependencies)
-                        if ((r = socket_add_default_dependencies(s)) < 0)
-                                return r;
-        }
-
-        return socket_verify(s);
-}
-
-static const char* listen_lookup(int family, int type) {
-
-        if (family == AF_NETLINK)
-                return "ListenNetlink";
-
-        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"
-                "%sResult: %s\n"
-                "%sBindIPv6Only: %s\n"
-                "%sBacklog: %u\n"
-                "%sSocketMode: %04o\n"
-                "%sDirectoryMode: %04o\n"
-                "%sKeepAlive: %s\n"
-                "%sFreeBind: %s\n"
-                "%sTransparent: %s\n"
-                "%sBroadcast: %s\n"
-                "%sPassCredentials: %s\n"
-                "%sPassSecurity: %s\n"
-                "%sTCPCongestion: %s\n",
-                prefix, socket_state_to_string(s->state),
-                prefix, socket_result_to_string(s->result),
-                prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only),
-                prefix, s->backlog,
-                prefix, s->socket_mode,
-                prefix, s->directory_mode,
-                prefix, yes_no(s->keep_alive),
-                prefix, yes_no(s->free_bind),
-                prefix, yes_no(s->transparent),
-                prefix, yes_no(s->broadcast),
-                prefix, yes_no(s->pass_cred),
-                prefix, yes_no(s->pass_sec),
-                prefix, strna(s->tcp_congestion));
-
-        if (s->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %lu\n",
-                        prefix, (unsigned 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"
-                        "%sNConnections: %u\n"
-                        "%sMaxConnections: %u\n",
-                        prefix, s->n_accepted,
-                        prefix, s->n_connections,
-                        prefix, s->max_connections);
-
-        if (s->priority >= 0)
-                fprintf(f,
-                        "%sPriority: %i\n",
-                        prefix, s->priority);
-
-        if (s->receive_buffer > 0)
-                fprintf(f,
-                        "%sReceiveBuffer: %zu\n",
-                        prefix, s->receive_buffer);
-
-        if (s->send_buffer > 0)
-                fprintf(f,
-                        "%sSendBuffer: %zu\n",
-                        prefix, s->send_buffer);
-
-        if (s->ip_tos >= 0)
-                fprintf(f,
-                        "%sIPTOS: %i\n",
-                        prefix, s->ip_tos);
-
-        if (s->ip_ttl >= 0)
-                fprintf(f,
-                        "%sIPTTL: %i\n",
-                        prefix, s->ip_ttl);
-
-        if (s->pipe_size > 0)
-                fprintf(f,
-                        "%sPipeSize: %zu\n",
-                        prefix, s->pipe_size);
-
-        if (s->mark >= 0)
-                fprintf(f,
-                        "%sMark: %i\n",
-                        prefix, s->mark);
-
-        if (s->mq_maxmsg > 0)
-                fprintf(f,
-                        "%sMessageQueueMaxMessages: %li\n",
-                        prefix, s->mq_maxmsg);
-
-        if (s->mq_msgsize > 0)
-                fprintf(f,
-                        "%sMessageQueueMessageSize: %li\n",
-                        prefix, s->mq_msgsize);
-
-        LIST_FOREACH(port, p, s->ports) {
-
-                if (p->type == SOCKET_SOCKET) {
-                        const char *t;
-                        int r;
-                        char *k = NULL;
-
-                        if ((r = socket_address_print(&p->address, &k)) < 0)
-                                t = strerror(-r);
-                        else
-                                t = k;
-
-                        fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t);
-                        free(k);
-                } else if (p->type == SOCKET_SPECIAL)
-                        fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
-                else if (p->type == SOCKET_MQUEUE)
-                        fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
-                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: {
-                static const char ipv4_prefix[] = {
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
-                };
-
-                if (memcmp(&local.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0 &&
-                    memcmp(&remote.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
-                        const uint8_t
-                                *a = local.in6.sin6_addr.s6_addr+12,
-                                *b = remote.in6.sin6_addr.s6_addr+12;
-
-                        if (asprintf(&r,
-                                     "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
-                                     nr,
-                                     a[0], a[1], a[2], a[3],
-                                     ntohs(local.in6.sin6_port),
-                                     b[0], b[1], b[2], b[3],
-                                     ntohs(remote.in6.sin6_port)) < 0)
-                                return -ENOMEM;
-                } else {
-                        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-%lu-%lu",
-                             nr,
-                             (unsigned long) ucred.pid,
-                             (unsigned 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 void socket_apply_socket_options(Socket *s, int fd) {
-        assert(s);
-        assert(fd >= 0);
-
-        if (s->keep_alive) {
-                int b = s->keep_alive;
-                if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
-                        log_warning("SO_KEEPALIVE failed: %m");
-        }
-
-        if (s->broadcast) {
-                int one = 1;
-                if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
-                        log_warning("SO_BROADCAST failed: %m");
-        }
-
-        if (s->pass_cred) {
-                int one = 1;
-                if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
-                        log_warning("SO_PASSCRED failed: %m");
-        }
-
-        if (s->pass_sec) {
-                int one = 1;
-                if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0)
-                        log_warning("SO_PASSSEC failed: %m");
-        }
-
-        if (s->priority >= 0)
-                if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
-                        log_warning("SO_PRIORITY failed: %m");
-
-        if (s->receive_buffer > 0) {
-                int value = (int) s->receive_buffer;
-
-                /* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
-
-                if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
-                        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
-                                log_warning("SO_RCVBUF failed: %m");
-        }
-
-        if (s->send_buffer > 0) {
-                int value = (int) s->send_buffer;
-                if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
-                        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
-                                log_warning("SO_SNDBUF failed: %m");
-        }
-
-        if (s->mark >= 0)
-                if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
-                        log_warning("SO_MARK failed: %m");
-
-        if (s->ip_tos >= 0)
-                if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
-                        log_warning("IP_TOS failed: %m");
-
-        if (s->ip_ttl >= 0) {
-                int r, x;
-
-                r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
-
-                if (socket_ipv6_is_supported())
-                        x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
-                else {
-                        x = -1;
-                        errno = EAFNOSUPPORT;
-                }
-
-                if (r < 0 && x < 0)
-                        log_warning("IP_TTL/IPV6_UNICAST_HOPS failed: %m");
-        }
-
-        if (s->tcp_congestion)
-                if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0)
-                        log_warning("TCP_CONGESTION failed: %m");
-}
-
-static void socket_apply_fifo_options(Socket *s, int fd) {
-        assert(s);
-        assert(fd >= 0);
-
-        if (s->pipe_size > 0)
-                if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
-                        log_warning("F_SETPIPE_SZ: %m");
-}
-
-static int fifo_address_create(
-                const char *path,
-                mode_t directory_mode,
-                mode_t socket_mode,
-                int *_fd) {
-
-        int fd = -1, r = 0;
-        struct stat st;
-        mode_t old_mask;
-
-        assert(path);
-        assert(_fd);
-
-        mkdir_parents(path, directory_mode);
-
-        if ((r = label_fifofile_set(path)) < 0)
-                goto fail;
-
-        /* Enforce the right access mode for the fifo */
-        old_mask = umask(~ socket_mode);
-
-        /* Include the original umask in our mask */
-        umask(~socket_mode | old_mask);
-
-        r = mkfifo(path, socket_mode);
-        umask(old_mask);
-
-        if (r < 0 && errno != EEXIST) {
-                r = -errno;
-                goto fail;
-        }
-
-        if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        label_file_clear();
-
-        if (fstat(fd, &st) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if (!S_ISFIFO(st.st_mode) ||
-            (st.st_mode & 0777) != (socket_mode & ~old_mask) ||
-            st.st_uid != getuid() ||
-            st.st_gid != getgid()) {
-
-                r = -EEXIST;
-                goto fail;
-        }
-
-        *_fd = fd;
-        return 0;
-
-fail:
-        label_file_clear();
-
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
-
-static int special_address_create(
-                const char *path,
-                int *_fd) {
-
-        int fd = -1, r = 0;
-        struct stat st;
-
-        assert(path);
-        assert(_fd);
-
-        if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if (fstat(fd, &st) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* Check whether this is a /proc, /sys or /dev file or char device */
-        if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
-                r = -EEXIST;
-                goto fail;
-        }
-
-        *_fd = fd;
-        return 0;
-
-fail:
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
-
-static int mq_address_create(
-                const char *path,
-                mode_t mq_mode,
-                long maxmsg,
-                long msgsize,
-                int *_fd) {
-
-        int fd = -1, r = 0;
-        struct stat st;
-        mode_t old_mask;
-        struct mq_attr _attr, *attr = NULL;
-
-        assert(path);
-        assert(_fd);
-
-        if (maxmsg > 0 && msgsize > 0) {
-                zero(_attr);
-                _attr.mq_flags = O_NONBLOCK;
-                _attr.mq_maxmsg = maxmsg;
-                _attr.mq_msgsize = msgsize;
-                attr = &_attr;
-        }
-
-        /* Enforce the right access mode for the mq */
-        old_mask = umask(~ mq_mode);
-
-        /* Include the original umask in our mask */
-        umask(~mq_mode | old_mask);
-
-        fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
-        umask(old_mask);
-
-        if (fd < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if (fstat(fd, &st) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
-            st.st_uid != getuid() ||
-            st.st_gid != getgid()) {
-
-                r = -EEXIST;
-                goto fail;
-        }
-
-        *_fd = fd;
-        return 0;
-
-fail:
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
-
-static int socket_open_fds(Socket *s) {
-        SocketPort *p;
-        int r;
-        char *label = NULL;
-        bool know_label = false;
-
-        assert(s);
-
-        LIST_FOREACH(port, p, s->ports) {
-
-                if (p->fd >= 0)
-                        continue;
-
-                if (p->type == SOCKET_SOCKET) {
-
-                        if (!know_label) {
-
-                                if ((r = socket_instantiate_service(s)) < 0)
-                                        return r;
-
-                                if (UNIT_DEREF(s->service) &&
-                                    SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
-                                        r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
-
-                                        if (r < 0) {
-                                                if (r != -EPERM)
-                                                        return r;
-                                        }
-                                }
-
-                                know_label = true;
-                        }
-
-                        if ((r = socket_address_listen(
-                                             &p->address,
-                                             s->backlog,
-                                             s->bind_ipv6_only,
-                                             s->bind_to_device,
-                                             s->free_bind,
-                                             s->transparent,
-                                             s->directory_mode,
-                                             s->socket_mode,
-                                             label,
-                                             &p->fd)) < 0)
-                                goto rollback;
-
-                        socket_apply_socket_options(s, p->fd);
-
-                } else  if (p->type == SOCKET_SPECIAL) {
-
-                        if ((r = special_address_create(
-                                             p->path,
-                                             &p->fd)) < 0)
-                                goto rollback;
-
-                } else  if (p->type == SOCKET_FIFO) {
-
-                        if ((r = fifo_address_create(
-                                             p->path,
-                                             s->directory_mode,
-                                             s->socket_mode,
-                                             &p->fd)) < 0)
-                                goto rollback;
-
-                        socket_apply_fifo_options(s, p->fd);
-                } else if (p->type == SOCKET_MQUEUE) {
-
-                        if ((r = mq_address_create(
-                                             p->path,
-                                             s->socket_mode,
-                                             s->mq_maxmsg,
-                                             s->mq_msgsize,
-                                             &p->fd)) < 0)
-                                goto rollback;
-                } else
-                        assert_not_reached("Unknown port type");
-        }
-
-        label_free(label);
-        return 0;
-
-rollback:
-        socket_close_fds(s);
-        label_free(label);
-        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",
-                          UNIT(s)->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], true);
-}
-
-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,
-                       UNIT(s)->manager->environment,
-                       true,
-                       true,
-                       true,
-                       UNIT(s)->manager->confirm_spawn,
-                       UNIT(s)->cgroup_bondings,
-                       UNIT(s)->cgroup_attributes,
-                       &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, SocketResult f) {
-        assert(s);
-
-        if (f != SOCKET_SUCCESS)
-                s->result = f;
-
-        socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, SocketResult f);
-
-static void socket_enter_stop_post(Socket *s, SocketResult f) {
-        int r;
-        assert(s);
-
-        if (f != SOCKET_SUCCESS)
-                s->result = f;
-
-        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, SOCKET_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
-        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
-        int r;
-        Set *pid_set = NULL;
-        bool wait_for_exit = false;
-
-        assert(s);
-
-        if (f != SOCKET_SUCCESS)
-                s->result = f;
-
-        if (s->exec_context.kill_mode != KILL_NONE) {
-                int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
-
-                if (s->control_pid > 0) {
-                        if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
-
-                                log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
-                        else
-                                wait_for_exit = true;
-                }
-
-                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
-
-                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        /* Exclude the control pid from being killed via the cgroup */
-                        if (s->control_pid > 0)
-                                if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
-                                        goto fail;
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
-                                        log_warning("Failed to kill control group: %s", strerror(-r));
-                        } else if (r > 0)
-                                wait_for_exit = true;
-
-                        set_free(pid_set);
-                        pid_set = NULL;
-                }
-        }
-
-        if (wait_for_exit) {
-                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, SOCKET_SUCCESS);
-        else
-                socket_enter_dead(s, SOCKET_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
-        if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
-                socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
-        else
-                socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-
-        if (pid_set)
-                set_free(pid_set);
-}
-
-static void socket_enter_stop_pre(Socket *s, SocketResult f) {
-        int r;
-        assert(s);
-
-        if (f != SOCKET_SUCCESS)
-                s->result = f;
-
-        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, SOCKET_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'stop-pre' task: %s", UNIT(s)->id, strerror(-r));
-        socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_listening(Socket *s) {
-        int r;
-        assert(s);
-
-        r = socket_watch_fds(s);
-        if (r < 0) {
-                log_warning("%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
-                goto fail;
-        }
-
-        socket_set_state(s, SOCKET_LISTENING);
-        return;
-
-fail:
-        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_start_post(Socket *s) {
-        int r;
-        assert(s);
-
-        r = socket_open_fds(s);
-        if (r < 0) {
-                log_warning("%s failed to listen on sockets: %s", UNIT(s)->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])) {
-                r = socket_spawn(s, s->control_command, &s->control_pid);
-                if (r < 0) {
-                        log_warning("%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
-                        goto fail;
-                }
-
-                socket_set_state(s, SOCKET_START_POST);
-        } else
-                socket_enter_listening(s);
-
-        return;
-
-fail:
-        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-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' task: %s", UNIT(s)->id, strerror(-r));
-        socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_running(Socket *s, int cfd) {
-        int r;
-        DBusError error;
-
-        assert(s);
-        dbus_error_init(&error);
-
-        /* We don't take connections anymore if we are supposed to
-         * shut down anyway */
-        if (unit_pending_inactive(UNIT(s))) {
-                log_debug("Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
-
-                if (cfd >= 0)
-                        close_nointr_nofail(cfd);
-                else  {
-                        /* Flush all sockets by closing and reopening them */
-                        socket_close_fds(s);
-
-                        r = socket_watch_fds(s);
-                        if (r < 0) {
-                                log_warning("%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
-                                socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-                        }
-                }
-
-                return;
-        }
-
-        if (cfd < 0) {
-                Iterator i;
-                Unit *u;
-                bool pending = false;
-
-                /* If there's already a start pending don't bother to
-                 * do anything */
-                SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
-                        if (unit_pending_active(u)) {
-                                pending = true;
-                                break;
-                        }
-
-                if (!pending) {
-                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
-                        if (r < 0)
-                                goto fail;
-                }
-
-                socket_set_state(s, SOCKET_RUNNING);
-        } else {
-                char *prefix, *instance = NULL, *name;
-                Service *service;
-
-                if (s->n_connections >= s->max_connections) {
-                        log_warning("Too many incoming connections (%u)", s->n_connections);
-                        close_nointr_nofail(cfd);
-                        return;
-                }
-
-                r = socket_instantiate_service(s);
-                if (r < 0)
-                        goto fail;
-
-                r = instance_from_socket(cfd, s->n_accepted, &instance);
-                if (r < 0) {
-                        if (r != -ENOTCONN)
-                                goto fail;
-
-                        /* ENOTCONN is legitimate if TCP RST was received.
-                         * This connection is over, but the socket unit lives on. */
-                        close_nointr_nofail(cfd);
-                        return;
-                }
-
-                prefix = unit_name_to_prefix(UNIT(s)->id);
-                if (!prefix) {
-                        free(instance);
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                name = unit_name_build(prefix, instance, ".service");
-                free(prefix);
-                free(instance);
-
-                if (!name) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                r = unit_add_name(UNIT_DEREF(s->service), name);
-                if (r < 0) {
-                        free(name);
-                        goto fail;
-                }
-
-                service = SERVICE(UNIT_DEREF(s->service));
-                unit_ref_unset(&s->service);
-                s->n_accepted ++;
-
-                UNIT(service)->no_gc = false;
-
-                unit_choose_id(UNIT(service), name);
-                free(name);
-
-                r = service_set_socket_fd(service, cfd, s);
-                if (r < 0)
-                        goto fail;
-
-                cfd = -1;
-                s->n_connections ++;
-
-                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
-                if (r < 0)
-                        goto fail;
-
-                /* Notify clients about changed counters */
-                unit_add_to_dbus_queue(UNIT(s));
-        }
-
-        return;
-
-fail:
-        log_warning("%s failed to queue socket startup job: %s", UNIT(s)->id, bus_error(&error, r));
-        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-
-        if (cfd >= 0)
-                close_nointr_nofail(cfd);
-
-        dbus_error_free(&error);
-}
-
-static void socket_run_next(Socket *s) {
-        int r;
-
-        assert(s);
-        assert(s->control_command);
-        assert(s->control_command->command_next);
-
-        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 next task: %s", UNIT(s)->id, strerror(-r));
-
-        if (s->state == SOCKET_START_POST)
-                socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-        else if (s->state == SOCKET_STOP_POST)
-                socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-        else
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
-}
-
-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 (UNIT_DEREF(s->service)) {
-                Service *service;
-
-                service = SERVICE(UNIT_DEREF(s->service));
-
-                if (UNIT(service)->load_state != UNIT_LOADED) {
-                        log_error("Socket service %s not loaded, refusing.", UNIT(service)->id);
-                        return -ENOENT;
-                }
-
-                /* If the service is already active we cannot start the
-                 * socket */
-                if (service->state != SERVICE_DEAD &&
-                    service->state != SERVICE_FAILED &&
-                    service->state != SERVICE_AUTO_RESTART) {
-                        log_error("Socket service %s already active, refusing.", UNIT(service)->id);
-                        return -EBUSY;
-                }
-
-#ifdef HAVE_SYSV_COMPAT
-                if (service->sysv_path) {
-                        log_error("Using SysV services for socket activation is not supported. Refusing.");
-                        return -ENOENT;
-                }
-#endif
-        }
-
-        assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
-
-        s->result = SOCKET_SUCCESS;
-        socket_enter_start_pre(s);
-        return 0;
-}
-
-static int socket_stop(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-
-        /* 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_SIGKILL)
-                return 0;
-
-        /* If there's already something running we go directly into
-         * kill mode. */
-        if (s->state == SOCKET_START_PRE ||
-            s->state == SOCKET_START_POST) {
-                socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_SUCCESS);
-                return -EAGAIN;
-        }
-
-        assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
-
-        socket_enter_stop_pre(s, SOCKET_SUCCESS);
-        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, "result", socket_result_to_string(s->result));
-        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", "%lu", (unsigned long) 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;
-
-                        if (socket_address_family(&p->address) == AF_NETLINK)
-                                unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t);
-                        else
-                                unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t);
-                        free(t);
-                } else if (p->type == SOCKET_SPECIAL)
-                        unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path);
-                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);
-
-        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, "result")) {
-                SocketResult f;
-
-                f = socket_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != SOCKET_SUCCESS)
-                        s->result = f;
-
-        } else if (streq(key, "n-accepted")) {
-                unsigned k;
-
-                if (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")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        s->control_pid = 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 (p->type == SOCKET_FIFO &&
-                                    streq_ptr(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, "special")) {
-                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 special value %s", value);
-                else {
-
-                        LIST_FOREACH(port, p, s->ports)
-                                if (p->type == SOCKET_SPECIAL &&
-                                    streq_ptr(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, type, skip = 0;
-                SocketPort *p;
-
-                if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 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, type))
-                                        break;
-
-                        if (p) {
-                                if (p->fd >= 0)
-                                        close_nointr_nofail(p->fd);
-                                p->fd = fdset_remove(fds, fd);
-                        }
-                }
-
-        } else if (streq(key, "netlink")) {
-                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_netlink(&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 bool socket_check_gc(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(u);
-
-        return s->n_connections > 0;
-}
-
-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);
-
-        if (s->state != SOCKET_LISTENING)
-                return;
-
-        log_debug("Incoming traffic on %s", u->id);
-
-        if (events != EPOLLIN) {
-
-                if (events & EPOLLHUP)
-                        log_error("%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.", u->id);
-                else
-                        log_error("%s: Got unexpected poll event (0x%x) on socket.", u->id, events);
-
-                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_apply_socket_options(s, cfd);
-        }
-
-        socket_enter_running(s, cfd);
-        return;
-
-fail:
-        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-        Socket *s = SOCKET(u);
-        SocketResult f;
-
-        assert(s);
-        assert(pid >= 0);
-
-        if (pid != s->control_pid)
-                return;
-
-        s->control_pid = 0;
-
-        if (is_clean_exit(code, status))
-                f = SOCKET_SUCCESS;
-        else if (code == CLD_EXITED)
-                f = SOCKET_FAILURE_EXIT_CODE;
-        else if (code == CLD_KILLED)
-                f = SOCKET_FAILURE_SIGNAL;
-        else if (code == CLD_DUMPED)
-                f = SOCKET_FAILURE_CORE_DUMP;
-        else
-                assert_not_reached("Unknown code");
-
-        if (s->control_command) {
-                exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
-
-                if (s->control_command->ignore)
-                        f = SOCKET_SUCCESS;
-        }
-
-        log_full(f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
-                 "%s control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
-        if (f != SOCKET_SUCCESS)
-                s->result = f;
-
-        if (s->control_command &&
-            s->control_command->command_next &&
-            f == SOCKET_SUCCESS) {
-
-                log_debug("%s running next command for state %s", u->id, socket_state_to_string(s->state));
-                socket_run_next(s);
-        } 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->id, socket_state_to_string(s->state));
-
-                switch (s->state) {
-
-                case SOCKET_START_PRE:
-                        if (f == SOCKET_SUCCESS)
-                                socket_enter_start_post(s);
-                        else
-                                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, f);
-                        break;
-
-                case SOCKET_START_POST:
-                        if (f == SOCKET_SUCCESS)
-                                socket_enter_listening(s);
-                        else
-                                socket_enter_stop_pre(s, f);
-                        break;
-
-                case SOCKET_STOP_PRE:
-                case SOCKET_STOP_PRE_SIGTERM:
-                case SOCKET_STOP_PRE_SIGKILL:
-                        socket_enter_stop_post(s, f);
-                        break;
-
-                case SOCKET_STOP_POST:
-                case SOCKET_FINAL_SIGTERM:
-                case SOCKET_FINAL_SIGKILL:
-                        socket_enter_dead(s, f);
-                        break;
-
-                default:
-                        assert_not_reached("Uh, control process died at wrong time.");
-                }
-        }
-
-        /* Notify clients about changed exit status */
-        unit_add_to_dbus_queue(u);
-}
-
-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->id);
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
-                break;
-
-        case SOCKET_START_POST:
-                log_warning("%s starting timed out. Stopping.", u->id);
-                socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
-                break;
-
-        case SOCKET_STOP_PRE:
-                log_warning("%s stopping timed out. Terminating.", u->id);
-                socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT);
-                break;
-
-        case SOCKET_STOP_PRE_SIGTERM:
-                if (s->exec_context.send_sigkill) {
-                        log_warning("%s stopping timed out. Killing.", u->id);
-                        socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s stopping timed out. Skipping SIGKILL. Ignoring.", u->id);
-                        socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case SOCKET_STOP_PRE_SIGKILL:
-                log_warning("%s still around after SIGKILL. Ignoring.", u->id);
-                socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
-                break;
-
-        case SOCKET_STOP_POST:
-                log_warning("%s stopping timed out (2). Terminating.", u->id);
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
-                break;
-
-        case SOCKET_FINAL_SIGTERM:
-                if (s->exec_context.send_sigkill) {
-                        log_warning("%s stopping timed out (2). Killing.", u->id);
-                        socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s stopping timed out (2). Skipping SIGKILL. Ignoring.", u->id);
-                        socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case SOCKET_FINAL_SIGKILL:
-                log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id);
-                socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
-                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 (rn_fds <= 0) {
-                *fds = NULL;
-                *n_fds = 0;
-                return 0;
-        }
-
-        if (!(rfds = new(int, rn_fds)))
-                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, bool failed_permanent) {
-        assert(s);
-
-        /* The service is dead. Dang!
-         *
-         * This is strictly for one-instance-for-all-connections
-         * services. */
-
-        if (s->state == SOCKET_RUNNING) {
-                log_debug("%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
-                if (failed_permanent)
-                        socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
-                else
-                        socket_enter_listening(s);
-        }
-}
-
-void socket_connection_unref(Socket *s) {
-        assert(s);
-
-        /* The service is dead. Yay!
-         *
-         * This is strictly for one-instance-per-connection
-         * services. */
-
-        assert(s->n_connections > 0);
-        s->n_connections--;
-
-        log_debug("%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
-}
-
-static void socket_reset_failed(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-
-        if (s->state == SOCKET_FAILED)
-                socket_set_state(s, SOCKET_DEAD);
-
-        s->result = SOCKET_SUCCESS;
-}
-
-static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
-        Socket *s = SOCKET(u);
-        int r = 0;
-        Set *pid_set = NULL;
-
-        assert(s);
-
-        if (who == KILL_MAIN) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Socket units have no main processes");
-                return -ESRCH;
-        }
-
-        if (s->control_pid <= 0 && who == KILL_CONTROL) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
-                return -ESRCH;
-        }
-
-        if (who == KILL_CONTROL || who == KILL_ALL)
-                if (s->control_pid > 0)
-                        if (kill(s->control_pid, signo) < 0)
-                                r = -errno;
-
-        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
-                int q;
-
-                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
-                        return -ENOMEM;
-
-                /* Exclude the control pid from being killed via the cgroup */
-                if (s->control_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
-                                r = q;
-                                goto finish;
-                        }
-
-                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
-        }
-
-finish:
-        if (pid_set)
-                set_free(pid_set);
-
-        return r;
-}
-
-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_FAILED] = "failed"
-};
-
-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);
-
-static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
-        [SOCKET_SUCCESS] = "success",
-        [SOCKET_FAILURE_RESOURCES] = "resources",
-        [SOCKET_FAILURE_TIMEOUT] = "timeout",
-        [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
-        [SOCKET_FAILURE_SIGNAL] = "signal",
-        [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
-        [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
-
-const UnitVTable socket_vtable = {
-        .suffix = ".socket",
-        .object_size = sizeof(Socket),
-        .sections =
-                "Unit\0"
-                "Socket\0"
-                "Install\0",
-
-        .init = socket_init,
-        .done = socket_done,
-        .load = socket_load,
-
-        .kill = socket_kill,
-
-        .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,
-
-        .check_gc = socket_check_gc,
-
-        .fd_event = socket_fd_event,
-        .sigchld_event = socket_sigchld_event,
-        .timer_event = socket_timer_event,
-
-        .reset_failed = socket_reset_failed,
-
-        .bus_interface = "org.freedesktop.systemd1.Socket",
-        .bus_message_handler = bus_socket_message_handler,
-        .bus_invalidating_properties =  bus_socket_invalidating_properties
-};
diff --git a/src/socket.h b/src/socket.h
deleted file mode 100644
index 6470d8b..0000000
--- a/src/socket.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-#include "service.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_FAILED,
-        _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_SPECIAL,
-        SOCKET_MQUEUE,
-        _SOCKET_FIFO_MAX,
-        _SOCKET_FIFO_INVALID = -1
-} SocketType;
-
-typedef enum SocketResult {
-        SOCKET_SUCCESS,
-        SOCKET_FAILURE_RESOURCES,
-        SOCKET_FAILURE_TIMEOUT,
-        SOCKET_FAILURE_EXIT_CODE,
-        SOCKET_FAILURE_SIGNAL,
-        SOCKET_FAILURE_CORE_DUMP,
-        SOCKET_FAILURE_SERVICE_FAILED_PERMANENT,
-        _SOCKET_RESULT_MAX,
-        _SOCKET_RESULT_INVALID = -1
-} SocketResult;
-
-typedef struct SocketPort {
-        SocketType type;
-        int fd;
-
-        SocketAddress address;
-        char *path;
-        Watch fd_watch;
-
-        LIST_FIELDS(struct SocketPort, port);
-} SocketPort;
-
-struct Socket {
-        Unit meta;
-
-        LIST_HEAD(SocketPort, ports);
-
-        unsigned n_accepted;
-        unsigned n_connections;
-        unsigned max_connections;
-
-        unsigned backlog;
-        usec_t timeout_usec;
-
-        ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        /* For Accept=no sockets refers to the one service we'll
-        activate. For Accept=yes sockets is either NULL, or filled
-        when the next service we spawn. */
-        UnitRef service;
-
-        SocketState state, deserialized_state;
-
-        Watch timer_watch;
-
-        ExecCommand* control_command;
-        SocketExecCommand control_command_id;
-        pid_t control_pid;
-
-        mode_t directory_mode;
-        mode_t socket_mode;
-
-        SocketResult result;
-
-        bool accept;
-
-        /* Socket options */
-        bool keep_alive;
-        bool free_bind;
-        bool transparent;
-        bool broadcast;
-        bool pass_cred;
-        bool pass_sec;
-        int priority;
-        int mark;
-        size_t receive_buffer;
-        size_t send_buffer;
-        int ip_tos;
-        int ip_ttl;
-        size_t pipe_size;
-        char *bind_to_device;
-        char *tcp_congestion;
-        long mq_maxmsg;
-        long mq_msgsize;
-
-        /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
-        SocketAddressBindIPv6Only bind_ipv6_only;
-};
-
-/* 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, bool failed_permanent);
-
-/* 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);
-
-/* Called from the service code when a per-connection service ended */
-void socket_connection_unref(Socket *s);
-
-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);
-
-const char* socket_result_to_string(SocketResult i);
-SocketResult socket_result_from_string(const char *s);
-
-#endif
diff --git a/src/spawn-agent.h b/src/spawn-agent.h
deleted file mode 100644
index fd0a910..0000000
--- a/src/spawn-agent.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foospawnagenthfoo
-#define foospawnagenthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2011 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/>.
-***/
-
-void agent_open(void);
-void agent_close(void);
-
-#endif
diff --git a/src/special.h b/src/special.h
deleted file mode 100644
index 43e2e6f..0000000
--- a/src/special.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foospecialhfoo
-#define foospecialhfoo
-
-/***
-  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/>.
-***/
-
-#define SPECIAL_DEFAULT_TARGET "default.target"
-
-/* Shutdown targets */
-#define SPECIAL_UMOUNT_TARGET "umount.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_HALT_TARGET "halt.target"
-#define SPECIAL_POWEROFF_TARGET "poweroff.target"
-#define SPECIAL_REBOOT_TARGET "reboot.target"
-#define SPECIAL_KEXEC_TARGET "kexec.target"
-#define SPECIAL_EXIT_TARGET "exit.target"
-
-/* Special boot targets */
-#define SPECIAL_RESCUE_TARGET "rescue.target"
-#define SPECIAL_EMERGENCY_TARGET "emergency.target"
-
-/* Early boot targets */
-#define SPECIAL_SYSINIT_TARGET "sysinit.target"
-#define SPECIAL_SOCKETS_TARGET "sockets.target"
-#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"         /* LSB's $local_fs */
-#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
-#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target"       /* LSB's $remote_fs */
-#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
-#define SPECIAL_SWAP_TARGET "swap.target"
-#define SPECIAL_BASIC_TARGET "basic.target"
-
-/* LSB compatibility */
-#define SPECIAL_NETWORK_TARGET "network.target"           /* LSB's $network */
-#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"             /* LSB's $syslog */
-#define SPECIAL_TIME_SYNC_TARGET "time-sync.target"       /* LSB's $time */
-#define SPECIAL_DISPLAY_MANAGER_SERVICE "display-manager.service"       /* Debian's $x-display-manager */
-#define SPECIAL_MAIL_TRANSFER_AGENT_TARGET "mail-transfer-agent.target" /* Debian's $mail-{transport|transfer-agent */
-#define SPECIAL_HTTP_DAEMON_TARGET "http-daemon.target"
-
-/* Magic early boot services */
-#define SPECIAL_FSCK_SERVICE "fsck at .service"
-#define SPECIAL_QUOTACHECK_SERVICE "quotacheck.service"
-#define SPECIAL_QUOTAON_SERVICE "quotaon.service"
-#define SPECIAL_REMOUNT_ROOTFS_SERVICE "remount-rootfs.service"
-
-/* Services systemd relies on */
-#define SPECIAL_DBUS_SERVICE "dbus.service"
-#define SPECIAL_DBUS_SOCKET "dbus.socket"
-#define SPECIAL_JOURNALD_SOCKET "systemd-journald.socket"
-#define SPECIAL_JOURNALD_SERVICE "systemd-journald.service"
-
-/* Magic init signals */
-#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
-#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
-#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
-
-/* For SysV compatibility. Usually an alias for a saner target. On
- * SysV-free systems this doesn't exist. */
-#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target"
-#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
-#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
-#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
-
-#endif
diff --git a/src/swap.c b/src/swap.c
deleted file mode 100644
index 9c72732..0000000
--- a/src/swap.c
+++ /dev/null
@@ -1,1415 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <libudev.h>
-
-#include "unit.h"
-#include "swap.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "unit-name.h"
-#include "dbus-swap.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "def.h"
-
-static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
-        [SWAP_DEAD] = UNIT_INACTIVE,
-        [SWAP_ACTIVATING] = UNIT_ACTIVATING,
-        [SWAP_ACTIVE] = UNIT_ACTIVE,
-        [SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
-        [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
-        [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
-        [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
-        [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
-        [SWAP_FAILED] = UNIT_FAILED
-};
-
-static void swap_unset_proc_swaps(Swap *s) {
-        Swap *first;
-
-        assert(s);
-
-        if (!s->parameters_proc_swaps.what)
-                return;
-
-        /* Remove this unit from the chain of swaps which share the
-         * same kernel swap device. */
-
-        first = hashmap_get(UNIT(s)->manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what);
-        LIST_REMOVE(Swap, same_proc_swaps, first, s);
-
-        if (first)
-                hashmap_remove_and_replace(UNIT(s)->manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what, first->parameters_proc_swaps.what, first);
-        else
-                hashmap_remove(UNIT(s)->manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what);
-
-        free(s->parameters_proc_swaps.what);
-        s->parameters_proc_swaps.what = NULL;
-}
-
-static void swap_init(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(UNIT(s)->load_state == UNIT_STUB);
-
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-
-        exec_context_init(&s->exec_context);
-        s->exec_context.std_output = u->manager->default_std_output;
-        s->exec_context.std_error = u->manager->default_std_error;
-
-        s->parameters_etc_fstab.priority = s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
-
-        s->timer_watch.type = WATCH_INVALID;
-
-        s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
-
-        UNIT(s)->ignore_on_isolate = true;
-}
-
-static void swap_unwatch_control_pid(Swap *s) {
-        assert(s);
-
-        if (s->control_pid <= 0)
-                return;
-
-        unit_unwatch_pid(UNIT(s), s->control_pid);
-        s->control_pid = 0;
-}
-
-static void swap_done(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        swap_unset_proc_swaps(s);
-
-        free(s->what);
-        s->what = NULL;
-
-        free(s->parameters_etc_fstab.what);
-        free(s->parameters_fragment.what);
-        s->parameters_etc_fstab.what = s->parameters_fragment.what = NULL;
-
-        exec_context_done(&s->exec_context);
-        exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
-        s->control_command = NULL;
-
-        swap_unwatch_control_pid(s);
-
-        unit_unwatch_timer(u, &s->timer_watch);
-}
-
-int swap_add_one_mount_link(Swap *s, Mount *m) {
-         int r;
-
-        assert(s);
-        assert(m);
-
-        if (UNIT(s)->load_state != UNIT_LOADED ||
-            UNIT(m)->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_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
-                return r;
-
-        return 0;
-}
-
-static int swap_add_mount_links(Swap *s) {
-        Unit *other;
-        int r;
-
-        assert(s);
-
-        LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_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(UNIT(s)->manager, SPECIAL_SWAP_TARGET, NULL, NULL, &tu)) < 0)
-                return r;
-
-        if (!p->noauto &&
-            !p->nofail &&
-            (p->handle || UNIT(s)->manager->swap_auto) &&
-            s->from_etc_fstab &&
-            UNIT(s)->manager->running_as == MANAGER_SYSTEM)
-                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_add_device_links(Swap *s) {
-        SwapParameters *p;
-
-        assert(s);
-
-        if (!s->what)
-                return 0;
-
-        if (s->from_fragment)
-                p = &s->parameters_fragment;
-        else if (s->from_etc_fstab)
-                p = &s->parameters_etc_fstab;
-        else
-                return 0;
-
-        if (is_device_path(s->what))
-                return unit_add_node_link(UNIT(s), s->what,
-                                          !p->noauto && p->nofail &&
-                                          UNIT(s)->manager->running_as == MANAGER_SYSTEM);
-        else
-                /* File based swap devices need to be ordered after
-                 * remount-rootfs.service, since they might need a
-                 * writable file system. */
-                return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_ROOTFS_SERVICE, NULL, true);
-}
-
-static int swap_add_default_dependencies(Swap *s) {
-        int r;
-
-        assert(s);
-
-        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int swap_verify(Swap *s) {
-        bool b;
-        char *e;
-
-        if (UNIT(s)->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)->id);
-                return -EINVAL;
-        }
-
-        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
-                log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int swap_load(Unit *u) {
-        int r;
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(u->load_state == UNIT_STUB);
-
-        /* Load a .swap file */
-        if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
-                return r;
-
-        if (u->load_state == UNIT_LOADED) {
-                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
-                        return r;
-
-                if (UNIT(s)->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->id);
-
-                        if (!s->what)
-                                return -ENOMEM;
-                }
-
-                path_kill_slashes(s->what);
-
-                if (!UNIT(s)->description)
-                        if ((r = unit_set_description(u, s->what)) < 0)
-                                return r;
-
-                if ((r = swap_add_device_links(s)) < 0)
-                        return r;
-
-                if ((r = swap_add_mount_links(s)) < 0)
-                        return r;
-
-                if ((r = swap_add_target_links(s)) < 0)
-                        return r;
-
-                if ((r = unit_add_default_cgroups(u)) < 0)
-                        return r;
-
-                if (UNIT(s)->default_dependencies)
-                        if ((r = swap_add_default_dependencies(s)) < 0)
-                                return r;
-        }
-
-        return swap_verify(s);
-}
-
-int swap_add_one(
-                Manager *m,
-                const char *what,
-                const char *what_proc_swaps,
-                int priority,
-                bool noauto,
-                bool nofail,
-                bool handle,
-                bool set_flags) {
-
-        Unit *u = NULL;
-        char *e = NULL, *wp = NULL;
-        bool delete = false;
-        int r;
-        SwapParameters *p;
-
-        assert(m);
-        assert(what);
-
-        e = unit_name_from_path(what, ".swap");
-        if (!e)
-                return -ENOMEM;
-
-        u = manager_get_unit(m, e);
-
-        if (what_proc_swaps &&
-            u &&
-            SWAP(u)->from_proc_swaps &&
-            !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
-                return -EEXIST;
-
-        if (!u) {
-                delete = true;
-
-                u = unit_new(m, sizeof(Swap));
-                if (!u) {
-                        free(e);
-                        return -ENOMEM;
-                }
-
-                r = unit_add_name(u, e);
-                if (r < 0)
-                        goto fail;
-
-                SWAP(u)->what = strdup(what);
-                if (!SWAP(u)->what) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                unit_add_to_load_queue(u);
-        } else
-                delete = false;
-
-        if (what_proc_swaps) {
-                Swap *first;
-
-                p = &SWAP(u)->parameters_proc_swaps;
-
-                if (!p->what) {
-                        if (!(wp = strdup(what_proc_swaps))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        if (!m->swaps_by_proc_swaps)
-                                if (!(m->swaps_by_proc_swaps = hashmap_new(string_hash_func, string_compare_func))) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                        free(p->what);
-                        p->what = wp;
-
-                        first = hashmap_get(m->swaps_by_proc_swaps, wp);
-                        LIST_PREPEND(Swap, same_proc_swaps, first, SWAP(u));
-
-                        if ((r = hashmap_replace(m->swaps_by_proc_swaps, wp, first)) < 0)
-                                goto fail;
-                }
-
-                if (set_flags) {
-                        SWAP(u)->is_active = true;
-                        SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
-                }
-
-                SWAP(u)->from_proc_swaps = true;
-
-        } else {
-                p = &SWAP(u)->parameters_etc_fstab;
-
-                if (!(wp = strdup(what))) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                free(p->what);
-                p->what = wp;
-
-                SWAP(u)->from_etc_fstab = true;
-        }
-
-        p->priority = priority;
-        p->noauto = noauto;
-        p->nofail = nofail;
-        p->handle = handle;
-
-        unit_add_to_dbus_queue(u);
-
-        free(e);
-
-        return 0;
-
-fail:
-        log_warning("Failed to load swap unit: %s", strerror(-r));
-
-        free(wp);
-        free(e);
-
-        if (delete && u)
-                unit_free(u);
-
-        return r;
-}
-
-static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) {
-        struct stat st;
-        int r = 0, k;
-
-        assert(m);
-
-        if (stat(device, &st) >= 0 && S_ISBLK(st.st_mode)) {
-                struct udev_device *d;
-                const char *dn;
-                struct udev_list_entry *item = NULL, *first = NULL;
-
-                /* So this is a proper swap device. Create swap units
-                 * for all names this swap device is known under */
-
-                if (!(d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev)))
-                        return -ENOMEM;
-
-                if ((dn = udev_device_get_devnode(d)))
-                        r = swap_add_one(m, dn, device, prio, false, false, false, set_flags);
-
-                /* Add additional units for all symlinks */
-                first = udev_device_get_devlinks_list_entry(d);
-                udev_list_entry_foreach(item, first) {
-                        const char *p;
-
-                        /* Don't bother with the /dev/block links */
-                        p = udev_list_entry_get_name(item);
-
-                        if (path_startswith(p, "/dev/block/"))
-                                continue;
-
-                        if (stat(p, &st) >= 0)
-                                if ((!S_ISBLK(st.st_mode)) || st.st_rdev != udev_device_get_devnum(d))
-                                        continue;
-
-                        if ((k = swap_add_one(m, p, device, prio, false, false, false, set_flags)) < 0)
-                                r = k;
-                }
-
-                udev_device_unref(d);
-        }
-
-        if ((k = swap_add_one(m, device, device, prio, false, false, false, set_flags)) < 0)
-                r = k;
-
-        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 != SWAP_ACTIVATING &&
-            state != SWAP_ACTIVATING_SIGTERM &&
-            state != SWAP_ACTIVATING_SIGKILL &&
-            state != SWAP_DEACTIVATING &&
-            state != SWAP_DEACTIVATING_SIGTERM &&
-            state != SWAP_DEACTIVATING_SIGKILL) {
-                unit_unwatch_timer(UNIT(s), &s->timer_watch);
-                swap_unwatch_control_pid(s);
-                s->control_command = NULL;
-                s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
-        }
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(s)->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], true);
-}
-
-static int swap_coldplug(Unit *u) {
-        Swap *s = SWAP(u);
-        SwapState new_state = SWAP_DEAD;
-        int r;
-
-        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) {
-
-                if (new_state == SWAP_ACTIVATING ||
-                    new_state == SWAP_ACTIVATING_SIGTERM ||
-                    new_state == SWAP_ACTIVATING_SIGKILL ||
-                    new_state == SWAP_DEACTIVATING ||
-                    new_state == SWAP_DEACTIVATING_SIGTERM ||
-                    new_state == SWAP_DEACTIVATING_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;
-                }
-
-                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"
-                "%sResult: %s\n"
-                "%sWhat: %s\n"
-                "%sPriority: %i\n"
-                "%sNoAuto: %s\n"
-                "%sNoFail: %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, swap_result_to_string(s->result),
-                prefix, s->what,
-                prefix, p->priority,
-                prefix, yes_no(p->noauto),
-                prefix, yes_no(p->nofail),
-                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));
-
-        if (s->control_pid > 0)
-                fprintf(f,
-                        "%sControl PID: %lu\n",
-                        prefix, (unsigned long) s->control_pid);
-
-        exec_context_dump(&s->exec_context, f, prefix);
-}
-
-static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
-        pid_t pid;
-        int r;
-
-        assert(s);
-        assert(c);
-        assert(_pid);
-
-        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                goto fail;
-
-        if ((r = exec_spawn(c,
-                            NULL,
-                            &s->exec_context,
-                            NULL, 0,
-                            UNIT(s)->manager->environment,
-                            true,
-                            true,
-                            true,
-                            UNIT(s)->manager->confirm_spawn,
-                            UNIT(s)->cgroup_bondings,
-                            UNIT(s)->cgroup_attributes,
-                            &pid)) < 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 swap_enter_dead(Swap *s, SwapResult f) {
-        assert(s);
-
-        if (f != SWAP_SUCCESS)
-                s->result = f;
-
-        swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
-}
-
-static void swap_enter_active(Swap *s, SwapResult f) {
-        assert(s);
-
-        if (f != SWAP_SUCCESS)
-                s->result = f;
-
-        swap_set_state(s, SWAP_ACTIVE);
-}
-
-static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
-        int r;
-        Set *pid_set = NULL;
-        bool wait_for_exit = false;
-
-        assert(s);
-
-        if (f != SWAP_SUCCESS)
-                s->result = f;
-
-        if (s->exec_context.kill_mode != KILL_NONE) {
-                int sig = (state == SWAP_ACTIVATING_SIGTERM ||
-                           state == SWAP_DEACTIVATING_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
-
-                if (s->control_pid > 0) {
-                        if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
-
-                                log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
-                        else
-                                wait_for_exit = true;
-                }
-
-                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
-
-                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        /* Exclude the control pid from being killed via the cgroup */
-                        if (s->control_pid > 0)
-                                if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
-                                        goto fail;
-
-                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
-                                if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
-                                        log_warning("Failed to kill control group: %s", strerror(-r));
-                        } else if (r > 0)
-                                wait_for_exit = true;
-
-                        set_free(pid_set);
-                        pid_set = NULL;
-                }
-        }
-
-        if (wait_for_exit) {
-                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
-                        goto fail;
-
-                swap_set_state(s, state);
-        } else
-                swap_enter_dead(s, SWAP_SUCCESS);
-
-        return;
-
-fail:
-        log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
-        swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
-
-        if (pid_set)
-                set_free(pid_set);
-}
-
-static void swap_enter_activating(Swap *s) {
-        int r, priority;
-
-        assert(s);
-
-        s->control_command_id = SWAP_EXEC_ACTIVATE;
-        s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
-
-        if (s->from_fragment)
-                priority = s->parameters_fragment.priority;
-        else if (s->from_etc_fstab)
-                priority = s->parameters_etc_fstab.priority;
-        else
-                priority = -1;
-
-        if (priority >= 0) {
-                char p[LINE_MAX];
-
-                snprintf(p, sizeof(p), "%i", priority);
-                char_array_0(p);
-
-                r = exec_command_set(
-                                s->control_command,
-                                "/sbin/swapon",
-                                "-p",
-                                p,
-                                s->what,
-                                NULL);
-        } else
-                r = exec_command_set(
-                                s->control_command,
-                                "/sbin/swapon",
-                                s->what,
-                                NULL);
-
-        if (r < 0)
-                goto fail;
-
-        swap_unwatch_control_pid(s);
-
-        if ((r = swap_spawn(s, s->control_command, &s->control_pid)) < 0)
-                goto fail;
-
-        swap_set_state(s, SWAP_ACTIVATING);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'swapon' task: %s", UNIT(s)->id, strerror(-r));
-        swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
-}
-
-static void swap_enter_deactivating(Swap *s) {
-        int r;
-
-        assert(s);
-
-        s->control_command_id = SWAP_EXEC_DEACTIVATE;
-        s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE;
-
-        if ((r = exec_command_set(
-                             s->control_command,
-                             "/sbin/swapoff",
-                             s->what,
-                             NULL)) < 0)
-                goto fail;
-
-        swap_unwatch_control_pid(s);
-
-        if ((r = swap_spawn(s, s->control_command, &s->control_pid)) < 0)
-                goto fail;
-
-        swap_set_state(s, SWAP_DEACTIVATING);
-
-        return;
-
-fail:
-        log_warning("%s failed to run 'swapoff' task: %s", UNIT(s)->id, strerror(-r));
-        swap_enter_active(s, SWAP_FAILURE_RESOURCES);
-}
-
-static int swap_start(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        /* We cannot fulfill this request right now, try again later
-         * please! */
-
-        if (s->state == SWAP_DEACTIVATING ||
-            s->state == SWAP_DEACTIVATING_SIGTERM ||
-            s->state == SWAP_DEACTIVATING_SIGKILL ||
-            s->state == SWAP_ACTIVATING_SIGTERM ||
-            s->state == SWAP_ACTIVATING_SIGKILL)
-                return -EAGAIN;
-
-        if (s->state == SWAP_ACTIVATING)
-                return 0;
-
-        assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED);
-
-        s->result = SWAP_SUCCESS;
-        swap_enter_activating(s);
-        return 0;
-}
-
-static int swap_stop(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        if (s->state == SWAP_DEACTIVATING ||
-            s->state == SWAP_DEACTIVATING_SIGTERM ||
-            s->state == SWAP_DEACTIVATING_SIGKILL ||
-            s->state == SWAP_ACTIVATING_SIGTERM ||
-            s->state == SWAP_ACTIVATING_SIGKILL)
-                return 0;
-
-        assert(s->state == SWAP_ACTIVATING ||
-               s->state == SWAP_ACTIVE);
-
-        swap_enter_deactivating(s);
-        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));
-        unit_serialize_item(u, f, "result", swap_result_to_string(s->result));
-
-        if (s->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid);
-
-        if (s->control_command_id >= 0)
-                unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id));
-
-        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 if (streq(key, "result")) {
-                SwapResult f;
-
-                f = swap_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != SWAP_SUCCESS)
-                        s->result = f;
-        } else if (streq(key, "control-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_debug("Failed to parse control-pid value %s", value);
-                else
-                        s->control_pid = pid;
-
-        } else if (streq(key, "control-command")) {
-                SwapExecCommand id;
-
-                if ((id = swap_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
-                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 void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
-        Swap *s = SWAP(u);
-        SwapResult f;
-
-        assert(s);
-        assert(pid >= 0);
-
-        if (pid != s->control_pid)
-                return;
-
-        s->control_pid = 0;
-
-        if (is_clean_exit(code, status))
-                f = SWAP_SUCCESS;
-        else if (code == CLD_EXITED)
-                f = SWAP_FAILURE_EXIT_CODE;
-        else if (code == CLD_KILLED)
-                f = SWAP_FAILURE_SIGNAL;
-        else if (code == CLD_DUMPED)
-                f = SWAP_FAILURE_CORE_DUMP;
-        else
-                assert_not_reached("Unknown code");
-
-        if (f != SWAP_SUCCESS)
-                s->result = f;
-
-        if (s->control_command) {
-                exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
-
-                s->control_command = NULL;
-                s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
-        }
-
-        log_full(f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
-                 "%s swap process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
-        switch (s->state) {
-
-        case SWAP_ACTIVATING:
-        case SWAP_ACTIVATING_SIGTERM:
-        case SWAP_ACTIVATING_SIGKILL:
-
-                if (f == SWAP_SUCCESS)
-                        swap_enter_active(s, f);
-                else
-                        swap_enter_dead(s, f);
-                break;
-
-        case SWAP_DEACTIVATING:
-        case SWAP_DEACTIVATING_SIGKILL:
-        case SWAP_DEACTIVATING_SIGTERM:
-
-                if (f == SWAP_SUCCESS)
-                        swap_enter_dead(s, f);
-                else
-                        swap_enter_dead(s, f);
-                break;
-
-        default:
-                assert_not_reached("Uh, control process died at wrong time.");
-        }
-
-        /* Notify clients about changed exit status */
-        unit_add_to_dbus_queue(u);
-
-        /* Request a reload of /proc/swaps, so that following units
-         * can follow our state change */
-        u->manager->request_reload = true;
-}
-
-static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-        assert(elapsed == 1);
-        assert(w == &s->timer_watch);
-
-        switch (s->state) {
-
-        case SWAP_ACTIVATING:
-                log_warning("%s activation timed out. Stopping.", u->id);
-                swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
-                break;
-
-        case SWAP_DEACTIVATING:
-                log_warning("%s deactivation timed out. Stopping.", u->id);
-                swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
-                break;
-
-        case SWAP_ACTIVATING_SIGTERM:
-                if (s->exec_context.send_sigkill) {
-                        log_warning("%s activation timed out. Killing.", u->id);
-                        swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s activation timed out. Skipping SIGKILL. Ignoring.", u->id);
-                        swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case SWAP_DEACTIVATING_SIGTERM:
-                if (s->exec_context.send_sigkill) {
-                        log_warning("%s deactivation timed out. Killing.", u->id);
-                        swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
-                } else {
-                        log_warning("%s deactivation timed out. Skipping SIGKILL. Ignoring.", u->id);
-                        swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
-                }
-                break;
-
-        case SWAP_ACTIVATING_SIGKILL:
-        case SWAP_DEACTIVATING_SIGKILL:
-                log_warning("%s swap process still around after SIGKILL. Ignoring.", u->id);
-                swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
-                break;
-
-        default:
-                assert_not_reached("Timeout at wrong time.");
-        }
-}
-
-static int swap_load_proc_swaps(Manager *m, bool set_flags) {
-        unsigned i;
-        int r = 0;
-
-        assert(m);
-
-        rewind(m->proc_swaps);
-
-        (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
-
-        for (i = 1;; i++) {
-                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;
-
-                        log_warning("Failed to parse /proc/swaps:%u.", i);
-                        free(dev);
-                        continue;
-                }
-
-                d = cunescape(dev);
-                free(dev);
-
-                if (!d)
-                        return -ENOMEM;
-
-                k = swap_process_new_swap(m, d, prio, set_flags);
-                free(d);
-
-                if (k < 0)
-                        r = k;
-        }
-
-        return r;
-}
-
-int swap_dispatch_reload(Manager *m) {
-        /* This function should go as soon as the kernel properly notifies us */
-
-        if (_likely_(!m->request_reload))
-                return 0;
-
-        m->request_reload = false;
-
-        return swap_fd_event(m, EPOLLPRI);
-}
-
-int swap_fd_event(Manager *m, int events) {
-        Unit *u;
-        int r;
-
-        assert(m);
-        assert(events & EPOLLPRI);
-
-        if ((r = swap_load_proc_swaps(m, true)) < 0) {
-                log_error("Failed to reread /proc/swaps: %s", strerror(-r));
-
-                /* Reset flags, just in case, for late calls */
-                LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
-                        Swap *swap = SWAP(u);
-
-                        swap->is_active = swap->just_activated = false;
-                }
-
-                return 0;
-        }
-
-        manager_dispatch_load_queue(m);
-
-        LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
-                Swap *swap = SWAP(u);
-
-                if (!swap->is_active) {
-                        /* This has just been deactivated */
-
-                        swap->from_proc_swaps = false;
-                        swap_unset_proc_swaps(swap);
-
-                        switch (swap->state) {
-
-                        case SWAP_ACTIVE:
-                                swap_enter_dead(swap, SWAP_SUCCESS);
-                                break;
-
-                        default:
-                                swap_set_state(swap, swap->state);
-                                break;
-                        }
-
-                } else if (swap->just_activated) {
-
-                        /* New swap entry */
-
-                        switch (swap->state) {
-
-                        case SWAP_DEAD:
-                        case SWAP_FAILED:
-                                swap_enter_active(swap, SWAP_SUCCESS);
-                                break;
-
-                        default:
-                                /* Nothing really changed, but let's
-                                 * issue an notification call
-                                 * nonetheless, in case somebody is
-                                 * waiting for this. */
-                                swap_set_state(swap, swap->state);
-                                break;
-                        }
-                }
-
-                /* Reset the flags for later calls */
-                swap->is_active = swap->just_activated = false;
-        }
-
-        return 1;
-}
-
-static Unit *swap_following(Unit *u) {
-        Swap *s = SWAP(u);
-        Swap *other, *first = NULL;
-
-        assert(s);
-
-        if (streq_ptr(s->what, s->parameters_proc_swaps.what))
-                return NULL;
-
-        /* Make everybody follow the unit that's named after the swap
-         * device in the kernel */
-
-        LIST_FOREACH_AFTER(same_proc_swaps, other, s)
-                if (streq_ptr(other->what, other->parameters_proc_swaps.what))
-                        return UNIT(other);
-
-        LIST_FOREACH_BEFORE(same_proc_swaps, other, s) {
-                if (streq_ptr(other->what, other->parameters_proc_swaps.what))
-                        return UNIT(other);
-
-                first = other;
-        }
-
-        return UNIT(first);
-}
-
-static int swap_following_set(Unit *u, Set **_set) {
-        Swap *s = SWAP(u);
-        Swap *other;
-        Set *set;
-        int r;
-
-        assert(s);
-        assert(_set);
-
-        if (LIST_JUST_US(same_proc_swaps, s)) {
-                *_set = NULL;
-                return 0;
-        }
-
-        if (!(set = set_new(NULL, NULL)))
-                return -ENOMEM;
-
-        LIST_FOREACH_AFTER(same_proc_swaps, other, s)
-                if ((r = set_put(set, other)) < 0)
-                        goto fail;
-
-        LIST_FOREACH_BEFORE(same_proc_swaps, other, s)
-                if ((r = set_put(set, other)) < 0)
-                        goto fail;
-
-        *_set = set;
-        return 1;
-
-fail:
-        set_free(set);
-        return r;
-}
-
-static void swap_shutdown(Manager *m) {
-        assert(m);
-
-        if (m->proc_swaps) {
-                fclose(m->proc_swaps);
-                m->proc_swaps = NULL;
-        }
-
-        hashmap_free(m->swaps_by_proc_swaps);
-        m->swaps_by_proc_swaps = NULL;
-}
-
-static int swap_enumerate(Manager *m) {
-        int r;
-        struct epoll_event ev;
-        assert(m);
-
-        if (!m->proc_swaps) {
-                if (!(m->proc_swaps = fopen("/proc/swaps", "re")))
-                        return (errno == ENOENT) ? 0 : -errno;
-
-                m->swap_watch.type = WATCH_SWAP;
-                m->swap_watch.fd = fileno(m->proc_swaps);
-
-                zero(ev);
-                ev.events = EPOLLPRI;
-                ev.data.ptr = &m->swap_watch;
-
-                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->swap_watch.fd, &ev) < 0)
-                        return -errno;
-        }
-
-        /* We rely on mount.c to load /etc/fstab for us */
-
-        if ((r = swap_load_proc_swaps(m, false)) < 0)
-                swap_shutdown(m);
-
-        return r;
-}
-
-static void swap_reset_failed(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        if (s->state == SWAP_FAILED)
-                swap_set_state(s, SWAP_DEAD);
-
-        s->result = SWAP_SUCCESS;
-}
-
-static int swap_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
-        Swap *s = SWAP(u);
-        int r = 0;
-        Set *pid_set = NULL;
-
-        assert(s);
-
-        if (who == KILL_MAIN) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Swap units have no main processes");
-                return -ESRCH;
-        }
-
-        if (s->control_pid <= 0 && who == KILL_CONTROL) {
-                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
-                return -ESRCH;
-        }
-
-        if (who == KILL_CONTROL || who == KILL_ALL)
-                if (s->control_pid > 0)
-                        if (kill(s->control_pid, signo) < 0)
-                                r = -errno;
-
-        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
-                int q;
-
-                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
-                        return -ENOMEM;
-
-                /* Exclude the control pid from being killed via the cgroup */
-                if (s->control_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
-                                r = q;
-                                goto finish;
-                        }
-
-                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
-        }
-
-finish:
-        if (pid_set)
-                set_free(pid_set);
-
-        return r;
-}
-
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
-        [SWAP_DEAD] = "dead",
-        [SWAP_ACTIVATING] = "activating",
-        [SWAP_ACTIVE] = "active",
-        [SWAP_DEACTIVATING] = "deactivating",
-        [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
-        [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
-        [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
-        [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
-        [SWAP_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
-static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
-        [SWAP_EXEC_ACTIVATE] = "ExecActivate",
-        [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
-
-static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
-        [SWAP_SUCCESS] = "success",
-        [SWAP_FAILURE_RESOURCES] = "resources",
-        [SWAP_FAILURE_TIMEOUT] = "timeout",
-        [SWAP_FAILURE_EXIT_CODE] = "exit-code",
-        [SWAP_FAILURE_SIGNAL] = "signal",
-        [SWAP_FAILURE_CORE_DUMP] = "core-dump"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
-
-const UnitVTable swap_vtable = {
-        .suffix = ".swap",
-        .object_size = sizeof(Swap),
-        .sections =
-                "Unit\0"
-                "Swap\0"
-                "Install\0",
-
-        .no_alias = true,
-        .no_instances = true,
-        .show_status = true,
-
-        .init = swap_init,
-        .load = swap_load,
-        .done = swap_done,
-
-        .coldplug = swap_coldplug,
-
-        .dump = swap_dump,
-
-        .start = swap_start,
-        .stop = swap_stop,
-
-        .kill = swap_kill,
-
-        .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,
-
-        .sigchld_event = swap_sigchld_event,
-        .timer_event = swap_timer_event,
-
-        .reset_failed = swap_reset_failed,
-
-        .bus_interface = "org.freedesktop.systemd1.Swap",
-        .bus_message_handler = bus_swap_message_handler,
-        .bus_invalidating_properties =  bus_swap_invalidating_properties,
-
-        .following = swap_following,
-        .following_set = swap_following_set,
-
-        .enumerate = swap_enumerate,
-        .shutdown = swap_shutdown
-};
diff --git a/src/swap.h b/src/swap.h
deleted file mode 100644
index 62d08da..0000000
--- a/src/swap.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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_ACTIVATING,
-        SWAP_ACTIVE,
-        SWAP_DEACTIVATING,
-        SWAP_ACTIVATING_SIGTERM,
-        SWAP_ACTIVATING_SIGKILL,
-        SWAP_DEACTIVATING_SIGTERM,
-        SWAP_DEACTIVATING_SIGKILL,
-        SWAP_FAILED,
-        _SWAP_STATE_MAX,
-        _SWAP_STATE_INVALID = -1
-} SwapState;
-
-typedef enum SwapExecCommand {
-        SWAP_EXEC_ACTIVATE,
-        SWAP_EXEC_DEACTIVATE,
-        _SWAP_EXEC_COMMAND_MAX,
-        _SWAP_EXEC_COMMAND_INVALID = -1
-} SwapExecCommand;
-
-typedef struct SwapParameters {
-        char *what;
-        int priority;
-        bool noauto:1;
-        bool nofail:1;
-        bool handle:1;
-} SwapParameters;
-
-typedef enum SwapResult {
-        SWAP_SUCCESS,
-        SWAP_FAILURE_RESOURCES,
-        SWAP_FAILURE_TIMEOUT,
-        SWAP_FAILURE_EXIT_CODE,
-        SWAP_FAILURE_SIGNAL,
-        SWAP_FAILURE_CORE_DUMP,
-        _SWAP_RESULT_MAX,
-        _SWAP_RESULT_INVALID = -1
-} SwapResult;
-
-struct Swap {
-        Unit meta;
-
-        char *what;
-
-        SwapParameters parameters_etc_fstab;
-        SwapParameters parameters_proc_swaps;
-        SwapParameters parameters_fragment;
-
-        bool from_etc_fstab:1;
-        bool from_proc_swaps:1;
-        bool from_fragment:1;
-
-        /* Used while looking for swaps that vanished or got added
-         * from/to /proc/swaps */
-        bool is_active:1;
-        bool just_activated:1;
-
-        SwapResult result;
-
-        usec_t timeout_usec;
-
-        ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
-        ExecContext exec_context;
-
-        SwapState state, deserialized_state;
-
-        ExecCommand* control_command;
-        SwapExecCommand control_command_id;
-        pid_t control_pid;
-
-        Watch timer_watch;
-
-        /* In order to be able to distinguish dependencies on
-        different device nodes we might end up creating multiple
-        devices for the same swap. We chain them up here. */
-
-        LIST_FIELDS(struct Swap, same_proc_swaps);
-};
-
-extern const UnitVTable swap_vtable;
-
-int swap_add_one(Manager *m, const char *what, const char *what_proc_swaps, int prio, bool no_auto, bool no_fail, bool handle, bool set_flags);
-
-int swap_add_one_mount_link(Swap *s, Mount *m);
-
-int swap_dispatch_reload(Manager *m);
-int swap_fd_event(Manager *m, int events);
-
-const char* swap_state_to_string(SwapState i);
-SwapState swap_state_from_string(const char *s);
-
-const char* swap_exec_command_to_string(SwapExecCommand i);
-SwapExecCommand swap_exec_command_from_string(const char *s);
-
-const char* swap_result_to_string(SwapResult i);
-SwapResult swap_result_from_string(const char *s);
-
-#endif
diff --git a/src/sysfs-show.h b/src/sysfs-show.h
deleted file mode 100644
index 9939e8b..0000000
--- a/src/sysfs-show.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosysfsshowhfoo
-#define foosysfsshowhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2011 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 show_sysfs(const char *seat, const char *prefix, unsigned columns);
-
-#endif
diff --git a/src/target.c b/src/target.c
deleted file mode 100644
index 6c1e0c3..0000000
--- a/src/target.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <unistd.h>
-
-#include "unit.h"
-#include "target.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "dbus-target.h"
-#include "special.h"
-#include "unit-name.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)->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], true);
-}
-
-static int target_add_default_dependencies(Target *t) {
-        static const UnitDependency deps[] = {
-                UNIT_REQUIRES,
-                UNIT_REQUIRES_OVERRIDABLE,
-                UNIT_REQUISITE,
-                UNIT_REQUISITE_OVERRIDABLE,
-                UNIT_WANTS,
-                UNIT_BIND_TO
-        };
-
-        Iterator i;
-        Unit *other;
-        int r;
-        unsigned k;
-
-        assert(t);
-
-        /* Imply ordering for requirement dependencies on target
-         * units. Note that when the user created a contradicting
-         * ordering manually we won't add anything in here to make
-         * sure we don't create a loop. */
-
-        for (k = 0; k < ELEMENTSOF(deps); k++)
-                SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i)
-                        if ((r = unit_add_default_target_dependency(other, UNIT(t))) < 0)
-                                return r;
-
-        /* Make sure targets are unloaded on shutdown */
-        return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int target_load(Unit *u) {
-        Target *t = TARGET(u);
-        int r;
-
-        assert(t);
-
-        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->load_state == UNIT_LOADED) {
-                if (u->default_dependencies)
-                        if ((r = target_add_default_dependencies(t)) < 0)
-                                return r;
-        }
-
-        return 0;
-}
-
-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);
-}
-
-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",
-        .object_size = sizeof(Target),
-        .sections =
-                "Unit\0"
-                "Target\0"
-                "Install\0",
-
-        .load = target_load,
-        .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_interface = "org.freedesktop.systemd1.Target",
-        .bus_message_handler = bus_target_message_handler
-};
diff --git a/src/target.h b/src/target.h
deleted file mode 100644
index 5b97c86..0000000
--- a/src/target.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 {
-        Unit meta;
-
-        TargetState state, deserialized_state;
-};
-
-extern const UnitVTable target_vtable;
-
-const char* target_state_to_string(TargetState i);
-TargetState target_state_from_string(const char *s);
-
-#endif
diff --git a/src/tcpwrap.c b/src/tcpwrap.c
deleted file mode 100644
index 0aab142..0000000
--- a/src/tcpwrap.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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/un.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#ifdef HAVE_LIBWRAP
-#include <tcpd.h>
-#endif
-
-#include "tcpwrap.h"
-#include "log.h"
-
-bool socket_tcpwrap(int fd, const char *name) {
-#ifdef HAVE_LIBWRAP
-        struct request_info req;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_in in;
-                struct sockaddr_in6 in6;
-                struct sockaddr_un un;
-                struct sockaddr_storage storage;
-        } sa_union;
-        socklen_t l = sizeof(sa_union);
-
-        if (getsockname(fd, &sa_union.sa, &l) < 0)
-                return true;
-
-        if (sa_union.sa.sa_family != AF_INET &&
-            sa_union.sa.sa_family != AF_INET6)
-                return true;
-
-        request_init(&req,
-                     RQ_DAEMON, name,
-                     RQ_FILE, fd,
-                     NULL);
-
-        fromhost(&req);
-
-        if (!hosts_access(&req)) {
-                log_warning("Connection refused by tcpwrap.");
-                return false;
-        }
-
-        log_debug("Connection accepted by tcpwrap.");
-#endif
-        return true;
-}
diff --git a/src/tcpwrap.h b/src/tcpwrap.h
deleted file mode 100644
index 4d4553e..0000000
--- a/src/tcpwrap.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foolibwraphfoo
-#define foolibwraphfoo
-
-/***
-  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>
-
-bool socket_tcpwrap(int fd, const char *name);
-
-#endif
diff --git a/src/timer.c b/src/timer.c
deleted file mode 100644
index e318fee..0000000
--- a/src/timer.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 "unit-name.h"
-#include "timer.h"
-#include "dbus-timer.h"
-#include "special.h"
-#include "bus-errors.h"
-
-static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
-        [TIMER_DEAD] = UNIT_INACTIVE,
-        [TIMER_WAITING] = UNIT_ACTIVE,
-        [TIMER_RUNNING] = UNIT_ACTIVE,
-        [TIMER_ELAPSED] = UNIT_ACTIVE,
-        [TIMER_FAILED] = UNIT_FAILED
-};
-
-static void timer_init(Unit *u) {
-        Timer *t = TIMER(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        t->next_elapse = (usec_t) -1;
-}
-
-static void timer_done(Unit *u) {
-        Timer *t = TIMER(u);
-        TimerValue *v;
-
-        assert(t);
-
-        while ((v = t->values)) {
-                LIST_REMOVE(TimerValue, value, t->values, v);
-                free(v);
-        }
-
-        unit_unwatch_timer(u, &t->timer_watch);
-
-        unit_ref_unset(&t->unit);
-}
-
-static int timer_verify(Timer *t) {
-        assert(t);
-
-        if (UNIT(t)->load_state != UNIT_LOADED)
-                return 0;
-
-        if (!t->values) {
-                log_error("%s lacks value setting. Refusing.", UNIT(t)->id);
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int timer_add_default_dependencies(Timer *t) {
-        int r;
-
-        assert(t);
-
-        if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
-                if ((r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
-                        return r;
-
-                if ((r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
-                        return r;
-        }
-
-        return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int timer_load(Unit *u) {
-        Timer *t = TIMER(u);
-        int r;
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        if ((r = unit_load_fragment_and_dropin(u)) < 0)
-                return r;
-
-        if (u->load_state == UNIT_LOADED) {
-
-                if (!UNIT_DEREF(t->unit)) {
-                        Unit *x;
-
-                        r = unit_load_related_unit(u, ".service", &x);
-                        if (r < 0)
-                                return r;
-
-                        unit_ref_set(&t->unit, x);
-                }
-
-                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
-                if (r < 0)
-                        return r;
-
-                if (UNIT(t)->default_dependencies)
-                        if ((r = timer_add_default_dependencies(t)) < 0)
-                                return r;
-        }
-
-        return timer_verify(t);
-}
-
-static void timer_dump(Unit *u, FILE *f, const char *prefix) {
-        Timer *t = TIMER(u);
-        TimerValue *v;
-        char
-                timespan1[FORMAT_TIMESPAN_MAX];
-
-        fprintf(f,
-                "%sTimer State: %s\n"
-                "%sResult: %s\n"
-                "%sUnit: %s\n",
-                prefix, timer_state_to_string(t->state),
-                prefix, timer_result_to_string(t->result),
-                prefix, UNIT_DEREF(t->unit)->id);
-
-        LIST_FOREACH(value, v, t->values)
-                fprintf(f,
-                        "%s%s: %s\n",
-                        prefix,
-                        timer_base_to_string(v->base),
-                        strna(format_timespan(timespan1, sizeof(timespan1), v->value)));
-}
-
-static void timer_set_state(Timer *t, TimerState state) {
-        TimerState old_state;
-        assert(t);
-
-        old_state = t->state;
-        t->state = state;
-
-        if (state != TIMER_WAITING)
-                unit_unwatch_timer(UNIT(t), &t->timer_watch);
-
-        if (state != old_state)
-                log_debug("%s changed %s -> %s",
-                          UNIT(t)->id,
-                          timer_state_to_string(old_state),
-                          timer_state_to_string(state));
-
-        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static void timer_enter_waiting(Timer *t, bool initial);
-
-static int timer_coldplug(Unit *u) {
-        Timer *t = TIMER(u);
-
-        assert(t);
-        assert(t->state == TIMER_DEAD);
-
-        if (t->deserialized_state != t->state) {
-
-                if (t->deserialized_state == TIMER_WAITING)
-                        timer_enter_waiting(t, false);
-                else
-                        timer_set_state(t, t->deserialized_state);
-        }
-
-        return 0;
-}
-
-static void timer_enter_dead(Timer *t, TimerResult f) {
-        assert(t);
-
-        if (f != TIMER_SUCCESS)
-                t->result = f;
-
-        timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
-}
-
-static void timer_enter_waiting(Timer *t, bool initial) {
-        TimerValue *v;
-        usec_t base = 0, delay, n;
-        bool found = false;
-        int r;
-
-        n = now(CLOCK_MONOTONIC);
-
-        LIST_FOREACH(value, v, t->values) {
-
-                if (v->disabled)
-                        continue;
-
-                switch (v->base) {
-
-                case TIMER_ACTIVE:
-                        if (state_translation_table[t->state] == UNIT_ACTIVE)
-                                base = UNIT(t)->inactive_exit_timestamp.monotonic;
-                        else
-                                base = n;
-                        break;
-
-                case TIMER_BOOT:
-                        /* CLOCK_MONOTONIC equals the uptime on Linux */
-                        base = 0;
-                        break;
-
-                case TIMER_STARTUP:
-                        base = UNIT(t)->manager->startup_timestamp.monotonic;
-                        break;
-
-                case TIMER_UNIT_ACTIVE:
-
-                        if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0)
-                                continue;
-
-                        base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic;
-                        break;
-
-                case TIMER_UNIT_INACTIVE:
-
-                        if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0)
-                                continue;
-
-                        base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic;
-                        break;
-
-                default:
-                        assert_not_reached("Unknown timer base");
-                }
-
-                v->next_elapse = base + v->value;
-
-                if (!initial && v->next_elapse < n) {
-                        v->disabled = true;
-                        continue;
-                }
-
-                if (!found)
-                        t->next_elapse = v->next_elapse;
-                else
-                        t->next_elapse = MIN(t->next_elapse, v->next_elapse);
-
-                found = true;
-        }
-
-        if (!found) {
-                timer_set_state(t, TIMER_ELAPSED);
-                return;
-        }
-
-        delay = n < t->next_elapse ? t->next_elapse - n : 0;
-
-        if ((r = unit_watch_timer(UNIT(t), delay, &t->timer_watch)) < 0)
-                goto fail;
-
-        timer_set_state(t, TIMER_WAITING);
-        return;
-
-fail:
-        log_warning("%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
-        timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-}
-
-static void timer_enter_running(Timer *t) {
-        DBusError error;
-        int r;
-
-        assert(t);
-        dbus_error_init(&error);
-
-        /* Don't start job if we are supposed to go down */
-        if (UNIT(t)->job && UNIT(t)->job->type == JOB_STOP)
-                return;
-
-        if ((r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL)) < 0)
-                goto fail;
-
-        timer_set_state(t, TIMER_RUNNING);
-        return;
-
-fail:
-        log_warning("%s failed to queue unit startup job: %s", UNIT(t)->id, bus_error(&error, r));
-        timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-
-        dbus_error_free(&error);
-}
-
-static int timer_start(Unit *u) {
-        Timer *t = TIMER(u);
-
-        assert(t);
-        assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
-
-        if (UNIT_DEREF(t->unit)->load_state != UNIT_LOADED)
-                return -ENOENT;
-
-        t->result = TIMER_SUCCESS;
-        timer_enter_waiting(t, true);
-        return 0;
-}
-
-static int timer_stop(Unit *u) {
-        Timer *t = TIMER(u);
-
-        assert(t);
-        assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
-
-        timer_enter_dead(t, TIMER_SUCCESS);
-        return 0;
-}
-
-static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Timer *t = TIMER(u);
-
-        assert(u);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
-        unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
-
-        return 0;
-}
-
-static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Timer *t = TIMER(u);
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                TimerState state;
-
-                if ((state = timer_state_from_string(value)) < 0)
-                        log_debug("Failed to parse state value %s", value);
-                else
-                        t->deserialized_state = state;
-        } else if (streq(key, "result")) {
-                TimerResult f;
-
-                f = timer_result_from_string(value);
-                if (f < 0)
-                        log_debug("Failed to parse result value %s", value);
-                else if (f != TIMER_SUCCESS)
-                        t->result = f;
-
-        } else
-                log_debug("Unknown serialization key '%s'", key);
-
-        return 0;
-}
-
-static UnitActiveState timer_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[TIMER(u)->state];
-}
-
-static const char *timer_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return timer_state_to_string(TIMER(u)->state);
-}
-
-static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
-        Timer *t = TIMER(u);
-
-        assert(t);
-        assert(elapsed == 1);
-
-        if (t->state != TIMER_WAITING)
-                return;
-
-        log_debug("Timer elapsed on %s", u->id);
-        timer_enter_running(t);
-}
-
-void timer_unit_notify(Unit *u, UnitActiveState new_state) {
-        Iterator i;
-        Unit *k;
-
-        if (u->type == UNIT_TIMER)
-                return;
-
-        SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
-                Timer *t;
-                TimerValue *v;
-
-                if (k->type != UNIT_TIMER)
-                        continue;
-
-                if (k->load_state != UNIT_LOADED)
-                        continue;
-
-                t = TIMER(k);
-
-                /* Reenable all timers that depend on unit state */
-                LIST_FOREACH(value, v, t->values)
-                        if (v->base == TIMER_UNIT_ACTIVE ||
-                            v->base == TIMER_UNIT_INACTIVE)
-                                v->disabled = false;
-
-                switch (t->state) {
-
-                case TIMER_WAITING:
-                case TIMER_ELAPSED:
-
-                        /* Recalculate sleep time */
-                        timer_enter_waiting(t, false);
-                        break;
-
-                case TIMER_RUNNING:
-
-                        if (UNIT_IS_INACTIVE_OR_FAILED(new_state)) {
-                                log_debug("%s got notified about unit deactivation.", UNIT(t)->id);
-                                timer_enter_waiting(t, false);
-                        }
-
-                        break;
-
-                case TIMER_DEAD:
-                case TIMER_FAILED:
-                        break;
-
-                default:
-                        assert_not_reached("Unknown timer state");
-                }
-        }
-}
-
-static void timer_reset_failed(Unit *u) {
-        Timer *t = TIMER(u);
-
-        assert(t);
-
-        if (t->state == TIMER_FAILED)
-                timer_set_state(t, TIMER_DEAD);
-
-        t->result = TIMER_SUCCESS;
-}
-
-static const char* const timer_state_table[_TIMER_STATE_MAX] = {
-        [TIMER_DEAD] = "dead",
-        [TIMER_WAITING] = "waiting",
-        [TIMER_RUNNING] = "running",
-        [TIMER_ELAPSED] = "elapsed",
-        [TIMER_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
-
-static const char* const timer_base_table[_TIMER_BASE_MAX] = {
-        [TIMER_ACTIVE] = "OnActiveSec",
-        [TIMER_BOOT] = "OnBootSec",
-        [TIMER_STARTUP] = "OnStartupSec",
-        [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
-        [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
-
-static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
-        [TIMER_SUCCESS] = "success",
-        [TIMER_FAILURE_RESOURCES] = "resources"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
-
-const UnitVTable timer_vtable = {
-        .suffix = ".timer",
-        .object_size = sizeof(Timer),
-        .sections =
-                "Unit\0"
-                "Timer\0"
-                "Install\0",
-
-        .init = timer_init,
-        .done = timer_done,
-        .load = timer_load,
-
-        .coldplug = timer_coldplug,
-
-        .dump = timer_dump,
-
-        .start = timer_start,
-        .stop = timer_stop,
-
-        .serialize = timer_serialize,
-        .deserialize_item = timer_deserialize_item,
-
-        .active_state = timer_active_state,
-        .sub_state_to_string = timer_sub_state_to_string,
-
-        .timer_event = timer_timer_event,
-
-        .reset_failed = timer_reset_failed,
-
-        .bus_interface = "org.freedesktop.systemd1.Timer",
-        .bus_message_handler = bus_timer_message_handler,
-        .bus_invalidating_properties =  bus_timer_invalidating_properties
-};
diff --git a/src/timer.h b/src/timer.h
deleted file mode 100644
index f5c5c64..0000000
--- a/src/timer.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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_ELAPSED,
-        TIMER_FAILED,
-        _TIMER_STATE_MAX,
-        _TIMER_STATE_INVALID = -1
-} TimerState;
-
-typedef enum TimerBase {
-        TIMER_ACTIVE,
-        TIMER_BOOT,
-        TIMER_STARTUP,
-        TIMER_UNIT_ACTIVE,
-        TIMER_UNIT_INACTIVE,
-        _TIMER_BASE_MAX,
-        _TIMER_BASE_INVALID = -1
-} TimerBase;
-
-typedef struct TimerValue {
-        usec_t value;
-        usec_t next_elapse;
-
-        LIST_FIELDS(struct TimerValue, value);
-
-        TimerBase base;
-        bool disabled;
-} TimerValue;
-
-typedef enum TimerResult {
-        TIMER_SUCCESS,
-        TIMER_FAILURE_RESOURCES,
-        _TIMER_RESULT_MAX,
-        _TIMER_RESULT_INVALID = -1
-} TimerResult;
-
-struct Timer {
-        Unit meta;
-
-        LIST_HEAD(TimerValue, values);
-        usec_t next_elapse;
-
-        TimerState state, deserialized_state;
-        UnitRef unit;
-
-        Watch timer_watch;
-
-        TimerResult result;
-};
-
-void timer_unit_notify(Unit *u, UnitActiveState new_state);
-
-extern const UnitVTable timer_vtable;
-
-const char *timer_state_to_string(TimerState i);
-TimerState timer_state_from_string(const char *s);
-
-const char *timer_base_to_string(TimerBase i);
-TimerBase timer_base_from_string(const char *s);
-
-const char* timer_result_to_string(TimerResult i);
-TimerResult timer_result_from_string(const char *s);
-
-#endif
diff --git a/src/unit.c b/src/unit.c
deleted file mode 100644
index 9e33701..0000000
--- a/src/unit.c
+++ /dev/null
@@ -1,2676 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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 <sys/stat.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"
-#include "special.h"
-#include "cgroup-util.h"
-#include "missing.h"
-#include "cgroup-attr.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_PATH] = &path_vtable
-};
-
-Unit *unit_new(Manager *m, size_t size) {
-        Unit *u;
-
-        assert(m);
-        assert(size >= sizeof(Unit));
-
-        u = malloc0(size);
-        if (!u)
-                return NULL;
-
-        u->names = set_new(string_hash_func, string_compare_func);
-        if (!u->names) {
-                free(u);
-                return NULL;
-        }
-
-        u->manager = m;
-        u->type = _UNIT_TYPE_INVALID;
-        u->deserialized_job = _JOB_TYPE_INVALID;
-        u->default_dependencies = true;
-        u->unit_file_state = _UNIT_FILE_STATE_INVALID;
-
-        return u;
-}
-
-bool unit_has_name(Unit *u, const char *name) {
-        assert(u);
-        assert(name);
-
-        return !!set_get(u->names, (char*) name);
-}
-
-int unit_add_name(Unit *u, const char *text) {
-        UnitType t;
-        char *s, *i = NULL;
-        int r;
-
-        assert(u);
-        assert(text);
-
-        if (unit_name_is_template(text)) {
-                if (!u->instance)
-                        return -EINVAL;
-
-                s = unit_name_replace_instance(text, u->instance);
-        } else
-                s = strdup(text);
-
-        if (!s)
-                return -ENOMEM;
-
-        if (!unit_name_is_valid(s, false)) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        assert_se((t = unit_name_to_type(s)) >= 0);
-
-        if (u->type != _UNIT_TYPE_INVALID && t != u->type) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        if ((r = unit_name_to_instance(s, &i)) < 0)
-                goto fail;
-
-        if (i && unit_vtable[t]->no_instances) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        /* Ensure that this unit is either instanced or not instanced,
-         * but not both. */
-        if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) {
-                r = -EINVAL;
-                goto fail;
-        }
-
-        if (unit_vtable[t]->no_alias &&
-            !set_isempty(u->names) &&
-            !set_get(u->names, s)) {
-                r = -EEXIST;
-                goto fail;
-        }
-
-        if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) {
-                r = -E2BIG;
-                goto fail;
-        }
-
-        if ((r = set_put(u->names, s)) < 0) {
-                if (r == -EEXIST)
-                        r = 0;
-                goto fail;
-        }
-
-        if ((r = hashmap_put(u->manager->units, s, u)) < 0) {
-                set_remove(u->names, s);
-                goto fail;
-        }
-
-        if (u->type == _UNIT_TYPE_INVALID) {
-
-                u->type = t;
-                u->id = s;
-                u->instance = i;
-
-                LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u);
-
-                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, *i;
-        int r;
-
-        assert(u);
-        assert(name);
-
-        if (unit_name_is_template(name)) {
-
-                if (!u->instance)
-                        return -EINVAL;
-
-                if (!(t = unit_name_replace_instance(name, u->instance)))
-                        return -ENOMEM;
-
-                name = t;
-        }
-
-        /* Selects one of the names of this unit as the id */
-        s = set_get(u->names, (char*) name);
-        free(t);
-
-        if (!s)
-                return -ENOENT;
-
-        if ((r = unit_name_to_instance(s, &i)) < 0)
-                return r;
-
-        u->id = s;
-
-        free(u->instance);
-        u->instance = i;
-
-        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->description);
-        u->description = s;
-
-        unit_add_to_dbus_queue(u);
-        return 0;
-}
-
-bool unit_check_gc(Unit *u) {
-        assert(u);
-
-        if (u->load_state == UNIT_STUB)
-                return true;
-
-        if (UNIT_VTABLE(u)->no_gc)
-                return true;
-
-        if (u->no_gc)
-                return true;
-
-        if (u->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->type != _UNIT_TYPE_INVALID);
-
-        if (u->load_state != UNIT_STUB || u->in_load_queue)
-                return;
-
-        LIST_PREPEND(Unit, load_queue, u->manager->load_queue, u);
-        u->in_load_queue = true;
-}
-
-void unit_add_to_cleanup_queue(Unit *u) {
-        assert(u);
-
-        if (u->in_cleanup_queue)
-                return;
-
-        LIST_PREPEND(Unit, cleanup_queue, u->manager->cleanup_queue, u);
-        u->in_cleanup_queue = true;
-}
-
-void unit_add_to_gc_queue(Unit *u) {
-        assert(u);
-
-        if (u->in_gc_queue || u->in_cleanup_queue)
-                return;
-
-        if (unit_check_gc(u))
-                return;
-
-        LIST_PREPEND(Unit, gc_queue, u->manager->gc_queue, u);
-        u->in_gc_queue = true;
-
-        u->manager->n_in_gc_queue ++;
-
-        if (u->manager->gc_queue_timestamp <= 0)
-                u->manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
-}
-
-void unit_add_to_dbus_queue(Unit *u) {
-        assert(u);
-        assert(u->type != _UNIT_TYPE_INVALID);
-
-        if (u->load_state == UNIT_STUB || u->in_dbus_queue)
-                return;
-
-        /* Shortcut things if nobody cares */
-        if (!bus_has_subscriber(u->manager)) {
-                u->sent_dbus_new_signal = true;
-                return;
-        }
-
-        LIST_PREPEND(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
-        u->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->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);
-
-        if (u->load_state != UNIT_STUB)
-                if (UNIT_VTABLE(u)->done)
-                        UNIT_VTABLE(u)->done(u);
-
-        SET_FOREACH(t, u->names, i)
-                hashmap_remove_value(u->manager->units, t, u);
-
-        if (u->job)
-                job_free(u->job);
-
-        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
-                bidi_set_free(u, u->dependencies[d]);
-
-        if (u->type != _UNIT_TYPE_INVALID)
-                LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
-
-        if (u->in_load_queue)
-                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
-
-        if (u->in_dbus_queue)
-                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
-
-        if (u->in_cleanup_queue)
-                LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u);
-
-        if (u->in_gc_queue) {
-                LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u);
-                u->manager->n_in_gc_queue--;
-        }
-
-        cgroup_bonding_free_list(u->cgroup_bondings, u->manager->n_reloading <= 0);
-        cgroup_attribute_free_list(u->cgroup_attributes);
-
-        free(u->description);
-        free(u->fragment_path);
-        free(u->instance);
-
-        set_free_free(u->names);
-
-        condition_free_list(u->conditions);
-
-        while (u->refs)
-                unit_ref_unset(u->refs);
-
-        free(u);
-}
-
-UnitActiveState unit_active_state(Unit *u) {
-        assert(u);
-
-        if (u->load_state == UNIT_MERGED)
-                return unit_active_state(unit_follow_merge(u));
-
-        /* After a reload it might happen that a unit is not correctly
-         * loaded but still has a process around. That's why we won't
-         * shortcut failed loading to UNIT_INACTIVE_FAILED. */
-
-        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->names, &other->names);
-
-        set_free_free(other->names);
-        other->names = NULL;
-        other->id = NULL;
-
-        SET_FOREACH(t, u->names, i)
-                assert_se(hashmap_replace(u->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);
-
-        /* Fix backwards pointers */
-        SET_FOREACH(back, other->dependencies[d], i) {
-                UnitDependency k;
-
-                for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
-                        if ((r = set_remove_and_put(back->dependencies[k], other, u)) < 0) {
-
-                                if (r == -EEXIST)
-                                        set_remove(back->dependencies[k], other);
-                                else
-                                        assert(r == -ENOENT);
-                        }
-        }
-
-        complete_move(&u->dependencies[d], &other->dependencies[d]);
-
-        set_free(other->dependencies[d]);
-        other->dependencies[d] = NULL;
-}
-
-int unit_merge(Unit *u, Unit *other) {
-        UnitDependency d;
-
-        assert(u);
-        assert(other);
-        assert(u->manager == other->manager);
-        assert(u->type != _UNIT_TYPE_INVALID);
-
-        other = unit_follow_merge(other);
-
-        if (other == u)
-                return 0;
-
-        if (u->type != other->type)
-                return -EINVAL;
-
-        if (!u->instance != !other->instance)
-                return -EINVAL;
-
-        if (other->load_state != UNIT_STUB &&
-            other->load_state != UNIT_ERROR)
-                return -EEXIST;
-
-        if (other->job)
-                return -EEXIST;
-
-        if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
-                return -EEXIST;
-
-        /* Merge names */
-        merge_names(u, other);
-
-        /* Redirect all references */
-        while (other->refs)
-                unit_ref_set(other->refs, u);
-
-        /* Merge dependencies */
-        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
-                merge_dependencies(u, other, d);
-
-        other->load_state = UNIT_MERGED;
-        other->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->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->instance)
-                        return -EINVAL;
-
-                if (!(s = unit_name_replace_instance(name, u->instance)))
-                        return -ENOMEM;
-
-                name = s;
-        }
-
-        if (!(other = manager_get_unit(u->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->load_state == UNIT_MERGED)
-                assert_se(u = u->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_KMSG &&
-            c->std_output != EXEC_OUTPUT_SYSLOG &&
-            c->std_output != EXEC_OUTPUT_JOURNAL &&
-            c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
-            c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE &&
-            c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
-            c->std_error != EXEC_OUTPUT_KMSG &&
-            c->std_error != EXEC_OUTPUT_SYSLOG &&
-            c->std_error != EXEC_OUTPUT_JOURNAL &&
-            c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
-            c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
-            c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE)
-                return 0;
-
-        /* If syslog or kernel logging is requested, make sure our own
-         * logging daemon is run first. */
-
-        if (u->manager->running_as == MANAGER_SYSTEM)
-                if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true)) < 0)
-                        return r;
-
-        return 0;
-}
-
-const char *unit_description(Unit *u) {
-        assert(u);
-
-        if (u->description)
-                return u->description;
-
-        return strna(u->id);
-}
-
-void unit_dump(Unit *u, FILE *f, const char *prefix) {
-        char *t;
-        UnitDependency d;
-        Iterator i;
-        char *p2;
-        const char *prefix2;
-        char
-                timestamp1[FORMAT_TIMESTAMP_MAX],
-                timestamp2[FORMAT_TIMESTAMP_MAX],
-                timestamp3[FORMAT_TIMESTAMP_MAX],
-                timestamp4[FORMAT_TIMESTAMP_MAX],
-                timespan[FORMAT_TIMESPAN_MAX];
-        Unit *following;
-
-        assert(u);
-        assert(u->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"
-                "%s\tNeed Daemon Reload: %s\n",
-                prefix, u->id,
-                prefix, unit_description(u),
-                prefix, strna(u->instance),
-                prefix, unit_load_state_to_string(u->load_state),
-                prefix, unit_active_state_to_string(unit_active_state(u)),
-                prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
-                prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
-                prefix, yes_no(unit_check_gc(u)),
-                prefix, yes_no(unit_need_daemon_reload(u)));
-
-        SET_FOREACH(t, u->names, i)
-                fprintf(f, "%s\tName: %s\n", prefix, t);
-
-        if ((following = unit_following(u)))
-                fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
-
-        if (u->fragment_path)
-                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
-
-        if (u->job_timeout > 0)
-                fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout));
-
-        condition_dump_list(u->conditions, f, prefix);
-
-        if (dual_timestamp_is_set(&u->condition_timestamp))
-                fprintf(f,
-                        "%s\tCondition Timestamp: %s\n"
-                        "%s\tCondition Result: %s\n",
-                        prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)),
-                        prefix, yes_no(u->condition_result));
-
-        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
-                Unit *other;
-
-                SET_FOREACH(other, u->dependencies[d], i)
-                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id);
-        }
-
-        if (u->load_state == UNIT_LOADED) {
-                CGroupBonding *b;
-                CGroupAttribute *a;
-
-                fprintf(f,
-                        "%s\tStopWhenUnneeded: %s\n"
-                        "%s\tRefuseManualStart: %s\n"
-                        "%s\tRefuseManualStop: %s\n"
-                        "%s\tDefaultDependencies: %s\n"
-                        "%s\tOnFailureIsolate: %s\n"
-                        "%s\tIgnoreOnIsolate: %s\n"
-                        "%s\tIgnoreOnSnapshot: %s\n",
-                        prefix, yes_no(u->stop_when_unneeded),
-                        prefix, yes_no(u->refuse_manual_start),
-                        prefix, yes_no(u->refuse_manual_stop),
-                        prefix, yes_no(u->default_dependencies),
-                        prefix, yes_no(u->on_failure_isolate),
-                        prefix, yes_no(u->ignore_on_isolate),
-                        prefix, yes_no(u->ignore_on_snapshot));
-
-                LIST_FOREACH(by_unit, b, u->cgroup_bondings)
-                        fprintf(f, "%s\tControlGroup: %s:%s\n",
-                                prefix, b->controller, b->path);
-
-                LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
-                        char *v = NULL;
-
-                        if (a->map_callback)
-                                a->map_callback(a->controller, a->name, a->value, &v);
-
-                        fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n",
-                                prefix, a->controller, a->name, v ? v : a->value);
-
-                        free(v);
-                }
-
-                if (UNIT_VTABLE(u)->dump)
-                        UNIT_VTABLE(u)->dump(u, f, prefix2);
-
-        } else if (u->load_state == UNIT_MERGED)
-                fprintf(f,
-                        "%s\tMerged into: %s\n",
-                        prefix, u->merged_into->id);
-        else if (u->load_state == UNIT_ERROR)
-                fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
-
-
-        if (u->job)
-                job_dump(u->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->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->load_state == UNIT_STUB)
-                u->load_state = UNIT_LOADED;
-
-        /* Load drop-in directory data */
-        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
-                return r;
-
-        return 0;
-}
-
-int unit_add_default_target_dependency(Unit *u, Unit *target) {
-        assert(u);
-        assert(target);
-
-        if (target->type != UNIT_TARGET)
-                return 0;
-
-        /* Only add the dependency if both units are loaded, so that
-         * that loop check below is reliable */
-        if (u->load_state != UNIT_LOADED ||
-            target->load_state != UNIT_LOADED)
-                return 0;
-
-        /* If either side wants no automatic dependencies, then let's
-         * skip this */
-        if (!u->default_dependencies ||
-            !target->default_dependencies)
-                return 0;
-
-        /* Don't create loops */
-        if (set_get(target->dependencies[UNIT_BEFORE], u))
-                return 0;
-
-        return unit_add_dependency(target, UNIT_AFTER, u, true);
-}
-
-static int unit_add_default_dependencies(Unit *u) {
-        static const UnitDependency deps[] = {
-                UNIT_REQUIRED_BY,
-                UNIT_REQUIRED_BY_OVERRIDABLE,
-                UNIT_WANTED_BY,
-                UNIT_BOUND_BY
-        };
-
-        Unit *target;
-        Iterator i;
-        int r;
-        unsigned k;
-
-        assert(u);
-
-        for (k = 0; k < ELEMENTSOF(deps); k++)
-                SET_FOREACH(target, u->dependencies[deps[k]], i)
-                        if ((r = unit_add_default_target_dependency(u, target)) < 0)
-                                return r;
-
-        return 0;
-}
-
-int unit_load(Unit *u) {
-        int r;
-
-        assert(u);
-
-        if (u->in_load_queue) {
-                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
-                u->in_load_queue = false;
-        }
-
-        if (u->type == _UNIT_TYPE_INVALID)
-                return -EINVAL;
-
-        if (u->load_state != UNIT_STUB)
-                return 0;
-
-        if (UNIT_VTABLE(u)->load)
-                if ((r = UNIT_VTABLE(u)->load(u)) < 0)
-                        goto fail;
-
-        if (u->load_state == UNIT_STUB) {
-                r = -ENOENT;
-                goto fail;
-        }
-
-        if (u->load_state == UNIT_LOADED &&
-            u->default_dependencies)
-                if ((r = unit_add_default_dependencies(u)) < 0)
-                        goto fail;
-
-        if (u->on_failure_isolate &&
-            set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
-
-                log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.",
-                          u->id);
-
-                r = -EINVAL;
-                goto fail;
-        }
-
-        assert((u->load_state != UNIT_MERGED) == !u->merged_into);
-
-        unit_add_to_dbus_queue(unit_follow_merge(u));
-        unit_add_to_gc_queue(u);
-
-        return 0;
-
-fail:
-        u->load_state = UNIT_ERROR;
-        u->load_error = r;
-        unit_add_to_dbus_queue(u);
-        unit_add_to_gc_queue(u);
-
-        log_debug("Failed to load configuration for %s: %s", u->id, strerror(-r));
-
-        return r;
-}
-
-bool unit_condition_test(Unit *u) {
-        assert(u);
-
-        dual_timestamp_get(&u->condition_timestamp);
-        u->condition_result = condition_test_list(u->conditions);
-
-        return u->condition_result;
-}
-
-/* Errors:
- *         -EBADR:     This unit type does not support starting.
- *         -EALREADY:  Unit is already started.
- *         -EAGAIN:    An operation is already in progress. Retry later.
- *         -ECANCELED: Too many requests for now.
- */
-int unit_start(Unit *u) {
-        UnitActiveState state;
-        Unit *following;
-
-        assert(u);
-
-        if (u->load_state != UNIT_LOADED)
-                return -EINVAL;
-
-        /* If this is already 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 the conditions failed, don't do anything at all. If we
-         * already are activating this call might still be useful to
-         * speed up activation in case there is some hold-off time,
-         * but we don't want to recheck the condition in that case. */
-        if (state != UNIT_ACTIVATING &&
-            !unit_condition_test(u)) {
-                log_debug("Starting of %s requested but condition failed. Ignoring.", u->id);
-                return -EALREADY;
-        }
-
-        /* Forward to the main object, if we aren't it. */
-        if ((following = unit_following(u))) {
-                log_debug("Redirecting start request from %s to %s.", u->id, following->id);
-                return unit_start(following);
-        }
-
-        /* 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);
-
-        unit_status_printf(u, NULL, "Starting %s...", unit_description(u));
-        return UNIT_VTABLE(u)->start(u);
-}
-
-bool unit_can_start(Unit *u) {
-        assert(u);
-
-        return !!UNIT_VTABLE(u)->start;
-}
-
-bool unit_can_isolate(Unit *u) {
-        assert(u);
-
-        return unit_can_start(u) &&
-                u->allow_isolate;
-}
-
-/* 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;
-        Unit *following;
-
-        assert(u);
-
-        state = unit_active_state(u);
-        if (UNIT_IS_INACTIVE_OR_FAILED(state))
-                return -EALREADY;
-
-        if ((following = unit_following(u))) {
-                log_debug("Redirecting stop request from %s to %s.", u->id, following->id);
-                return unit_stop(following);
-        }
-
-        if (!UNIT_VTABLE(u)->stop)
-                return -EBADR;
-
-        unit_add_to_dbus_queue(u);
-
-        unit_status_printf(u, NULL, "Stopping %s...", unit_description(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;
-        Unit *following;
-
-        assert(u);
-
-        if (u->load_state != UNIT_LOADED)
-                return -EINVAL;
-
-        if (!unit_can_reload(u))
-                return -EBADR;
-
-        state = unit_active_state(u);
-        if (state == UNIT_RELOADING)
-                return -EALREADY;
-
-        if (state != UNIT_ACTIVE)
-                return -ENOEXEC;
-
-        if ((following = unit_following(u))) {
-                log_debug("Redirecting reload request from %s to %s.", u->id, following->id);
-                return unit_reload(following);
-        }
-
-        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_unneeded(Unit *u) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-
-        /* If this service shall be shut down when unneeded then do
-         * so. */
-
-        if (!u->stop_when_unneeded)
-                return;
-
-        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
-                return;
-
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
-                if (unit_pending_active(other))
-                        return;
-
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
-                if (unit_pending_active(other))
-                        return;
-
-        SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
-                if (unit_pending_active(other))
-                        return;
-
-        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
-                if (unit_pending_active(other))
-                        return;
-
-        log_info("Service %s is not needed anymore. Stopping.", u->id);
-
-        /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
-        manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, 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->dependencies[UNIT_REQUIRES], i)
-                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
-                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_BIND_TO], i)
-                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
-                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
-                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
-                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
-                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
-                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
-                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-}
-
-static void retroactively_stop_dependencies(Unit *u) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
-        /* Pull down units which are bound to us recursively if enabled */
-        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-}
-
-static void check_unneeded_dependencies(Unit *u) {
-        Iterator i;
-        Unit *other;
-
-        assert(u);
-        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
-        /* Garbage collect services that might not be needed anymore, if enabled */
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_BIND_TO], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
-}
-
-void unit_trigger_on_failure(Unit *u) {
-        Unit *other;
-        Iterator i;
-
-        assert(u);
-
-        if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
-                return;
-
-        log_info("Triggering OnFailure= dependencies of %s.", u->id);
-
-        SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
-                int r;
-
-                if ((r = manager_add_job(u->manager, JOB_START, other, u->on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL)) < 0)
-                        log_error("Failed to enqueue OnFailure= job: %s", strerror(-r));
-        }
-}
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
-        bool unexpected;
-
-        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! */
-
-        if (u->manager->n_reloading <= 0) {
-                dual_timestamp ts;
-
-                dual_timestamp_get(&ts);
-
-                if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
-                        u->inactive_exit_timestamp = ts;
-                else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
-                        u->inactive_enter_timestamp = ts;
-
-                if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                        u->active_enter_timestamp = ts;
-                else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                        u->active_exit_timestamp = ts;
-
-                timer_unit_notify(u, ns);
-                path_unit_notify(u, ns);
-        }
-
-        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                cgroup_bonding_trim_list(u->cgroup_bondings, true);
-
-        if (u->job) {
-                unexpected = false;
-
-                if (u->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->job);
-
-                /* Let's check whether this state change constitutes a
-                 * finished job, or maybe contradicts a running job and
-                 * hence needs to invalidate jobs. */
-
-                switch (u->job->type) {
-
-                case JOB_START:
-                case JOB_VERIFY_ACTIVE:
-
-                        if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                                job_finish_and_invalidate(u->job, JOB_DONE);
-                        else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
-                                unexpected = true;
-
-                                if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                        job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
-                        }
-
-                        break;
-
-                case JOB_RELOAD:
-                case JOB_RELOAD_OR_START:
-
-                        if (u->job->state == JOB_RUNNING) {
-                                if (ns == UNIT_ACTIVE)
-                                        job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED);
-                                else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
-                                        unexpected = true;
-
-                                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                                job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
-                                }
-                        }
-
-                        break;
-
-                case JOB_STOP:
-                case JOB_RESTART:
-                case JOB_TRY_RESTART:
-
-                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                job_finish_and_invalidate(u->job, JOB_DONE);
-                        else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
-                                unexpected = true;
-                                job_finish_and_invalidate(u->job, JOB_FAILED);
-                        }
-
-                        break;
-
-                default:
-                        assert_not_reached("Job type unknown");
-                }
-
-        } else
-                unexpected = true;
-
-        if (u->manager->n_reloading <= 0) {
-
-                /* If this state change happened without being
-                 * requested by a job, then let's retroactively start
-                 * or stop dependencies. We skip that step when
-                 * deserializing, since we don't want to create any
-                 * additional jobs just because something is already
-                 * activated. */
-
-                if (unexpected) {
-                        if (UNIT_IS_INACTIVE_OR_FAILED(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);
-                }
-
-                /* stop unneeded units regardless if going down was expected or not */
-                if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
-                        check_unneeded_dependencies(u);
-
-                if (ns != os && ns == UNIT_FAILED) {
-                        log_notice("Unit %s entered failed state.", u->id);
-                        unit_trigger_on_failure(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(u->manager, true);
-
-                if (u->type == UNIT_SERVICE &&
-                    !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
-                    u->manager->n_reloading <= 0) {
-                        /* Write audit record if we have just finished starting up */
-                        manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, true);
-                        u->in_audit = true;
-                }
-
-                if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
-                        manager_send_unit_plymouth(u->manager, u);
-
-        } else {
-
-                /* We don't care about D-Bus here, since we'll get an
-                 * asynchronous notification for it anyway. */
-
-                if (u->type == UNIT_SERVICE &&
-                    UNIT_IS_INACTIVE_OR_FAILED(ns) &&
-                    !UNIT_IS_INACTIVE_OR_FAILED(os) &&
-                    u->manager->n_reloading <= 0) {
-
-                        /* Hmm, if there was no start record written
-                         * write it now, so that we always have a nice
-                         * pair */
-                        if (!u->in_audit) {
-                                manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
-
-                                if (ns == UNIT_INACTIVE)
-                                        manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, true);
-                        } else
-                                /* Write audit record if we have just finished shutting down */
-                                manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
-
-                        u->in_audit = false;
-                }
-        }
-
-        manager_recheck_journal(u->manager);
-
-        /* Maybe we finished startup and are now ready for being
-         * stopped because unneeded? */
-        unit_check_unneeded(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->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->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->manager->watch_pids, LONG_TO_PTR(pid), u);
-}
-
-void unit_unwatch_pid(Unit *u, pid_t pid) {
-        assert(u);
-        assert(pid >= 1);
-
-        hashmap_remove_value(u->manager->watch_pids, LONG_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_UNIT_TIMER && w->data.unit == u));
-
-        /* This will try to reuse the old timer if there is one */
-
-        if (w->type == WATCH_UNIT_TIMER) {
-                assert(w->data.unit == u);
-                assert(w->fd >= 0);
-
-                ours = false;
-                fd = w->fd;
-        } else if (w->type == WATCH_INVALID) {
-
-                ours = true;
-                if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
-                        return -errno;
-        } else
-                assert_not_reached("Invalid watch type");
-
-        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->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
-                        goto fail;
-        }
-
-        w->type = WATCH_UNIT_TIMER;
-        w->fd = fd;
-        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_UNIT_TIMER);
-        assert(w->data.unit == u);
-        assert(w->fd >= 0);
-
-        assert_se(epoll_ctl(u->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:
-        case JOB_STOP:
-                return true;
-
-        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_BIND_TO] = UNIT_BOUND_BY,
-                [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_BOUND_BY] = UNIT_BIND_TO,
-                [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
-                [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
-                [UNIT_BEFORE] = UNIT_AFTER,
-                [UNIT_AFTER] = UNIT_BEFORE,
-                [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
-                [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
-                [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
-                [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
-                [UNIT_PROPAGATE_RELOAD_TO] = UNIT_PROPAGATE_RELOAD_FROM,
-                [UNIT_PROPAGATE_RELOAD_FROM] = UNIT_PROPAGATE_RELOAD_TO
-        };
-        int r, q = 0, v = 0, w = 0;
-
-        assert(u);
-        assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
-        assert(other);
-
-        u = unit_follow_merge(u);
-        other = unit_follow_merge(other);
-
-        /* We won't allow dependencies on ourselves. We will not
-         * consider them an error however. */
-        if (u == other)
-                return 0;
-
-        if ((r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
-                return r;
-
-        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
-                if ((r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
-                        return r;
-
-        if (add_reference)
-                if ((r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
-                    (r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
-                        return r;
-
-        if ((q = set_put(u->dependencies[d], other)) < 0)
-                return q;
-
-        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
-                if ((v = set_put(other->dependencies[inverse_table[d]], u)) < 0) {
-                        r = v;
-                        goto fail;
-                }
-
-        if (add_reference) {
-                if ((w = set_put(u->dependencies[UNIT_REFERENCES], other)) < 0) {
-                        r = w;
-                        goto fail;
-                }
-
-                if ((r = set_put(other->dependencies[UNIT_REFERENCED_BY], u)) < 0)
-                        goto fail;
-        }
-
-        unit_add_to_dbus_queue(u);
-        return 0;
-
-fail:
-        if (q > 0)
-                set_remove(u->dependencies[d], other);
-
-        if (v > 0)
-                set_remove(other->dependencies[inverse_table[d]], u);
-
-        if (w > 0)
-                set_remove(u->dependencies[UNIT_REFERENCES], other);
-
-        return r;
-}
-
-int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) {
-        int r;
-
-        assert(u);
-
-        if ((r = unit_add_dependency(u, d, other, add_reference)) < 0)
-                return r;
-
-        if ((r = unit_add_dependency(u, e, other, add_reference)) < 0)
-                return r;
-
-        return 0;
-}
-
-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->instance)
-                s = unit_name_replace_instance(name, u->instance);
-        else {
-                char *i;
-
-                if (!(i = unit_name_to_prefix(u->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->manager, name, path, NULL, &other)) < 0)
-                goto finish;
-
-        r = unit_add_dependency(u, d, other, add_reference);
-
-finish:
-        free(s);
-        return r;
-}
-
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, 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->manager, name, path, NULL, &other)) < 0)
-                goto finish;
-
-        r = unit_add_two_dependencies(u, d, e, 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->manager, name, path, NULL, &other)) < 0)
-                goto finish;
-
-        r = unit_add_dependency(other, d, u, add_reference);
-
-finish:
-        free(s);
-        return r;
-}
-
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, 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->manager, name, path, NULL, &other)) < 0)
-                goto finish;
-
-        if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0)
-                goto finish;
-
-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 (!u->id)
-                return NULL;
-
-        if (!(e = bus_path_escape(u->id)))
-                return NULL;
-
-        p = strappend("/org/freedesktop/systemd1/unit/", e);
-        free(e);
-
-        return p;
-}
-
-int unit_add_cgroup(Unit *u, CGroupBonding *b) {
-        int r;
-
-        assert(u);
-        assert(b);
-
-        assert(b->path);
-
-        if (!b->controller) {
-                if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER)))
-                        return -ENOMEM;
-
-                b->ours = true;
-        }
-
-        /* Ensure this hasn't been added yet */
-        assert(!b->unit);
-
-        if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                CGroupBonding *l;
-
-                l = hashmap_get(u->manager->cgroup_bondings, b->path);
-                LIST_PREPEND(CGroupBonding, by_path, l, b);
-
-                if ((r = hashmap_replace(u->manager->cgroup_bondings, b->path, l)) < 0) {
-                        LIST_REMOVE(CGroupBonding, by_path, l, b);
-                        return r;
-                }
-        }
-
-        LIST_PREPEND(CGroupBonding, by_unit, u->cgroup_bondings, b);
-        b->unit = u;
-
-        return 0;
-}
-
-static char *default_cgroup_path(Unit *u) {
-        char *p;
-
-        assert(u);
-
-        if (u->instance) {
-                char *t;
-
-                t = unit_name_template(u->id);
-                if (!t)
-                        return NULL;
-
-                p = join(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL);
-                free(t);
-        } else
-                p = join(u->manager->cgroup_hierarchy, "/", u->id, NULL);
-
-        return p;
-}
-
-int unit_add_cgroup_from_text(Unit *u, const char *name) {
-        char *controller = NULL, *path = NULL;
-        CGroupBonding *b = NULL;
-        bool ours = false;
-        int r;
-
-        assert(u);
-        assert(name);
-
-        if ((r = cg_split_spec(name, &controller, &path)) < 0)
-                return r;
-
-        if (!path) {
-                path = default_cgroup_path(u);
-                ours = true;
-        }
-
-        if (!controller) {
-                controller = strdup(SYSTEMD_CGROUP_CONTROLLER);
-                ours = true;
-        }
-
-        if (!path || !controller) {
-                free(path);
-                free(controller);
-
-                return -ENOMEM;
-        }
-
-        if (cgroup_bonding_find_list(u->cgroup_bondings, controller)) {
-                r = -EEXIST;
-                goto fail;
-        }
-
-        if (!(b = new0(CGroupBonding, 1))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        b->controller = controller;
-        b->path = path;
-        b->ours = ours;
-        b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
-
-        if ((r = unit_add_cgroup(u, b)) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        free(path);
-        free(controller);
-        free(b);
-
-        return r;
-}
-
-static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
-        CGroupBonding *b = NULL;
-        int r = -ENOMEM;
-
-        assert(u);
-
-        if (!controller)
-                controller = SYSTEMD_CGROUP_CONTROLLER;
-
-        if (cgroup_bonding_find_list(u->cgroup_bondings, controller))
-                return 0;
-
-        if (!(b = new0(CGroupBonding, 1)))
-                return -ENOMEM;
-
-        if (!(b->controller = strdup(controller)))
-                goto fail;
-
-        if (!(b->path = default_cgroup_path(u)))
-                goto fail;
-
-        b->ours = true;
-        b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
-
-        if ((r = unit_add_cgroup(u, b)) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        free(b->path);
-        free(b->controller);
-        free(b);
-
-        return r;
-}
-
-int unit_add_default_cgroups(Unit *u) {
-        CGroupAttribute *a;
-        char **c;
-        int r;
-
-        assert(u);
-
-        /* Adds in the default cgroups, if they weren't specified
-         * otherwise. */
-
-        if (!u->manager->cgroup_hierarchy)
-                return 0;
-
-        if ((r = unit_add_one_default_cgroup(u, NULL)) < 0)
-                return r;
-
-        STRV_FOREACH(c, u->manager->default_controllers)
-                unit_add_one_default_cgroup(u, *c);
-
-        LIST_FOREACH(by_unit, a, u->cgroup_attributes)
-                unit_add_one_default_cgroup(u, a->controller);
-
-        return 0;
-}
-
-CGroupBonding* unit_get_default_cgroup(Unit *u) {
-        assert(u);
-
-        return cgroup_bonding_find_list(u->cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER);
-}
-
-int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback) {
-        int r;
-        char *c = NULL;
-        CGroupAttribute *a;
-
-        assert(u);
-        assert(name);
-        assert(value);
-
-        if (!controller) {
-                const char *dot;
-
-                dot = strchr(name, '.');
-                if (!dot)
-                        return -EINVAL;
-
-                c = strndup(name, dot - name);
-                if (!c)
-                        return -ENOMEM;
-
-                controller = c;
-        }
-
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                r = -EINVAL;
-                goto finish;
-        }
-
-        a = new0(CGroupAttribute, 1);
-        if (!a) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (c) {
-                a->controller = c;
-                c = NULL;
-        } else
-                a->controller = strdup(controller);
-
-        a->name = strdup(name);
-        a->value = strdup(value);
-
-        if (!a->controller || !a->name || !a->value) {
-                free(a->controller);
-                free(a->name);
-                free(a->value);
-                free(a);
-
-                return -ENOMEM;
-        }
-
-        a->map_callback = map_callback;
-
-        LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a);
-
-        r = 0;
-
-finish:
-        free(c);
-        return r;
-}
-
-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->id, type)))
-                return -ENOMEM;
-
-        assert(!unit_has_name(u, t));
-
-        r = manager_load_unit(u->manager, t, NULL, 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->id, type)))
-                return -ENOMEM;
-
-        assert(!unit_has_name(u, t));
-
-        found = manager_get_unit(u->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->id);
-}
-
-static char *specifier_prefix(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        return unit_name_to_prefix(u->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->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->instance)
-                return unit_name_unescape(u->instance);
-
-        return strdup("");
-}
-
-static char *specifier_filename(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        if (u->instance)
-                return unit_name_path_unescape(u->instance);
-
-        return unit_name_to_path(u->instance);
-}
-
-static char *specifier_cgroup(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        return default_cgroup_path(u);
-}
-
-static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        char *p;
-        assert(u);
-
-        if (specifier == 'r')
-                return strdup(u->manager->cgroup_hierarchy);
-
-        if (parent_of_path(u->manager->cgroup_hierarchy, &p) < 0)
-                return strdup("");
-
-        if (streq(p, "/")) {
-                free(p);
-                return strdup("");
-        }
-
-        return p;
-}
-
-static char *specifier_runtime(char specifier, void *data, void *userdata) {
-        Unit *u = userdata;
-        assert(u);
-
-        if (u->manager->running_as == MANAGER_USER) {
-                const char *e;
-
-                e = getenv("XDG_RUNTIME_DIR");
-                if (e)
-                        return strdup(e);
-        }
-
-        return strdup("/run");
-}
-
-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->id },
-                { 'N', specifier_prefix_and_instance, NULL },
-                { 'p', specifier_prefix,              NULL },
-                { 'i', specifier_string,              u->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. Also, adds a couple of additional codes:
-         *
-         * %c cgroup path of unit
-         * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
-         * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
-         * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
-         */
-
-        const Specifier table[] = {
-                { 'n', specifier_string,              u->id },
-                { 'N', specifier_prefix_and_instance, NULL },
-                { 'p', specifier_prefix,              NULL },
-                { 'P', specifier_prefix_unescaped,    NULL },
-                { 'i', specifier_string,              u->instance },
-                { 'I', specifier_instance_unescaped,  NULL },
-                { 'f', specifier_filename,            NULL },
-                { 'c', specifier_cgroup,              NULL },
-                { 'r', specifier_cgroup_root,         NULL },
-                { 'R', specifier_cgroup_root,         NULL },
-                { 't', specifier_runtime,             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:
-        for (j--; j >= r; j--)
-                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->manager->watch_bus, name, u);
-}
-
-void unit_unwatch_bus_name(Unit *u, const char *name) {
-        assert(u);
-        assert(name);
-
-        hashmap_remove_value(u->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;
-
-        if (u->job)
-                unit_serialize_item(u, f, "job", job_type_to_string(u->job->type));
-
-        dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
-        dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
-        dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
-        dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
-        dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
-
-        if (dual_timestamp_is_set(&u->condition_timestamp))
-                unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
-
-        /* 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[LINE_MAX], *l, *v;
-                size_t k;
-
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                return 0;
-                        return -errno;
-                }
-
-                char_array_0(line);
-                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 (streq(l, "job")) {
-                        JobType type;
-
-                        if ((type = job_type_from_string(v)) < 0)
-                                log_debug("Failed to parse job type value %s", v);
-                        else
-                                u->deserialized_job = type;
-
-                        continue;
-                } else if (streq(l, "inactive-exit-timestamp")) {
-                        dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
-                        continue;
-                } else if (streq(l, "active-enter-timestamp")) {
-                        dual_timestamp_deserialize(v, &u->active_enter_timestamp);
-                        continue;
-                } else if (streq(l, "active-exit-timestamp")) {
-                        dual_timestamp_deserialize(v, &u->active_exit_timestamp);
-                        continue;
-                } else if (streq(l, "inactive-enter-timestamp")) {
-                        dual_timestamp_deserialize(v, &u->inactive_enter_timestamp);
-                        continue;
-                } else if (streq(l, "condition-timestamp")) {
-                        dual_timestamp_deserialize(v, &u->condition_timestamp);
-                        continue;
-                } else if (streq(l, "condition-result")) {
-                        int b;
-
-                        if ((b = parse_boolean(v)) < 0)
-                                log_debug("Failed to parse condition result value %s", v);
-                        else
-                                u->condition_result = b;
-
-                        continue;
-                }
-
-                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->manager, e, NULL, NULL, &device);
-        free(e);
-
-        if (r < 0)
-                return r;
-
-        if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BIND_TO, device, true)) < 0)
-                return r;
-
-        if (wants)
-                if ((r = unit_add_dependency(device, UNIT_WANTS, u, false)) < 0)
-                        return r;
-
-        return 0;
-}
-
-int unit_coldplug(Unit *u) {
-        int r;
-
-        assert(u);
-
-        if (UNIT_VTABLE(u)->coldplug)
-                if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
-                        return r;
-
-        if (u->deserialized_job >= 0) {
-                if ((r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL)) < 0)
-                        return r;
-
-                u->deserialized_job = _JOB_TYPE_INVALID;
-        }
-
-        return 0;
-}
-
-void unit_status_printf(Unit *u, const char *status, const char *format, ...) {
-        va_list ap;
-
-        assert(u);
-        assert(format);
-
-        if (!UNIT_VTABLE(u)->show_status)
-                return;
-
-        if (!manager_get_show_status(u->manager))
-                return;
-
-        if (!manager_is_booting_or_shutting_down(u->manager))
-                return;
-
-        va_start(ap, format);
-        status_vprintf(status, true, format, ap);
-        va_end(ap);
-}
-
-bool unit_need_daemon_reload(Unit *u) {
-        assert(u);
-
-        if (u->fragment_path) {
-                struct stat st;
-
-                zero(st);
-                if (stat(u->fragment_path, &st) < 0)
-                        /* What, cannot access this anymore? */
-                        return true;
-
-                if (u->fragment_mtime > 0 &&
-                    timespec_load(&st.st_mtim) != u->fragment_mtime)
-                        return true;
-        }
-
-        if (UNIT_VTABLE(u)->need_daemon_reload)
-                return UNIT_VTABLE(u)->need_daemon_reload(u);
-
-        return false;
-}
-
-void unit_reset_failed(Unit *u) {
-        assert(u);
-
-        if (UNIT_VTABLE(u)->reset_failed)
-                UNIT_VTABLE(u)->reset_failed(u);
-}
-
-Unit *unit_following(Unit *u) {
-        assert(u);
-
-        if (UNIT_VTABLE(u)->following)
-                return UNIT_VTABLE(u)->following(u);
-
-        return NULL;
-}
-
-bool unit_pending_inactive(Unit *u) {
-        assert(u);
-
-        /* Returns true if the unit is inactive or going down */
-
-        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)))
-                return true;
-
-        if (u->job && u->job->type == JOB_STOP)
-                return true;
-
-        return false;
-}
-
-bool unit_pending_active(Unit *u) {
-        assert(u);
-
-        /* Returns true if the unit is active or going up */
-
-        if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
-                return true;
-
-        if (u->job &&
-            (u->job->type == JOB_START ||
-             u->job->type == JOB_RELOAD_OR_START ||
-             u->job->type == JOB_RESTART))
-                return true;
-
-        return false;
-}
-
-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, bool template_ok) {
-        UnitType t;
-
-        t = unit_name_to_type(n);
-        if (t < 0 || t >= _UNIT_TYPE_MAX)
-                return false;
-
-        return unit_name_is_valid_no_type(n, template_ok);
-}
-
-int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error) {
-        assert(u);
-        assert(w >= 0 && w < _KILL_WHO_MAX);
-        assert(m >= 0 && m < _KILL_MODE_MAX);
-        assert(signo > 0);
-        assert(signo < _NSIG);
-
-        if (m == KILL_NONE)
-                return 0;
-
-        if (!UNIT_VTABLE(u)->kill)
-                return -ENOTSUP;
-
-        return UNIT_VTABLE(u)->kill(u, w, m, signo, error);
-}
-
-int unit_following_set(Unit *u, Set **s) {
-        assert(u);
-        assert(s);
-
-        if (UNIT_VTABLE(u)->following_set)
-                return UNIT_VTABLE(u)->following_set(u, s);
-
-        *s = NULL;
-        return 0;
-}
-
-UnitFileState unit_get_unit_file_state(Unit *u) {
-        assert(u);
-
-        if (u->unit_file_state < 0 && u->fragment_path)
-                u->unit_file_state = unit_file_get_state(
-                                u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
-                                NULL, file_name_from_path(u->fragment_path));
-
-        return u->unit_file_state;
-}
-
-Unit* unit_ref_set(UnitRef *ref, Unit *u) {
-        assert(ref);
-        assert(u);
-
-        if (ref->unit)
-                unit_ref_unset(ref);
-
-        ref->unit = u;
-        LIST_PREPEND(UnitRef, refs, u->refs, ref);
-        return u;
-}
-
-void unit_ref_unset(UnitRef *ref) {
-        assert(ref);
-
-        if (!ref->unit)
-                return;
-
-        LIST_REMOVE(UnitRef, refs, ref->unit->refs, ref);
-        ref->unit = NULL;
-}
-
-static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
-        [UNIT_STUB] = "stub",
-        [UNIT_LOADED] = "loaded",
-        [UNIT_ERROR] = "error",
-        [UNIT_MERGED] = "merged",
-        [UNIT_MASKED] = "masked"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
-        [UNIT_ACTIVE] = "active",
-        [UNIT_RELOADING] = "reloading",
-        [UNIT_INACTIVE] = "inactive",
-        [UNIT_FAILED] = "failed",
-        [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_BIND_TO] = "BindTo",
-        [UNIT_WANTED_BY] = "WantedBy",
-        [UNIT_CONFLICTS] = "Conflicts",
-        [UNIT_CONFLICTED_BY] = "ConflictedBy",
-        [UNIT_BOUND_BY] = "BoundBy",
-        [UNIT_BEFORE] = "Before",
-        [UNIT_AFTER] = "After",
-        [UNIT_REFERENCES] = "References",
-        [UNIT_REFERENCED_BY] = "ReferencedBy",
-        [UNIT_ON_FAILURE] = "OnFailure",
-        [UNIT_TRIGGERS] = "Triggers",
-        [UNIT_TRIGGERED_BY] = "TriggeredBy",
-        [UNIT_PROPAGATE_RELOAD_TO] = "PropagateReloadTo",
-        [UNIT_PROPAGATE_RELOAD_FROM] = "PropagateReloadFrom"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
diff --git a/src/unit.h b/src/unit.h
deleted file mode 100644
index 756f465..0000000
--- a/src/unit.h
+++ /dev/null
@@ -1,562 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 struct Unit Unit;
-typedef struct UnitVTable UnitVTable;
-typedef enum UnitType UnitType;
-typedef enum UnitLoadState UnitLoadState;
-typedef enum UnitActiveState UnitActiveState;
-typedef enum UnitDependency UnitDependency;
-typedef struct UnitRef UnitRef;
-
-#include "set.h"
-#include "util.h"
-#include "list.h"
-#include "socket-util.h"
-#include "execute.h"
-#include "condition.h"
-#include "install.h"
-
-enum UnitType {
-        UNIT_SERVICE = 0,
-        UNIT_SOCKET,
-        UNIT_TARGET,
-        UNIT_DEVICE,
-        UNIT_MOUNT,
-        UNIT_AUTOMOUNT,
-        UNIT_SNAPSHOT,
-        UNIT_TIMER,
-        UNIT_SWAP,
-        UNIT_PATH,
-        _UNIT_TYPE_MAX,
-        _UNIT_TYPE_INVALID = -1
-};
-
-enum UnitLoadState {
-        UNIT_STUB,
-        UNIT_LOADED,
-        UNIT_ERROR,
-        UNIT_MERGED,
-        UNIT_MASKED,
-        _UNIT_LOAD_STATE_MAX,
-        _UNIT_LOAD_STATE_INVALID = -1
-};
-
-enum UnitActiveState {
-        UNIT_ACTIVE,
-        UNIT_RELOADING,
-        UNIT_INACTIVE,
-        UNIT_FAILED,
-        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_RELOADING;
-}
-
-static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) {
-        return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_RELOADING;
-}
-
-static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
-        return t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING;
-}
-
-static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
-        return t == UNIT_INACTIVE || t == UNIT_FAILED;
-}
-
-enum UnitDependency {
-        /* Positive dependencies */
-        UNIT_REQUIRES,
-        UNIT_REQUIRES_OVERRIDABLE,
-        UNIT_REQUISITE,
-        UNIT_REQUISITE_OVERRIDABLE,
-        UNIT_WANTS,
-        UNIT_BIND_TO,
-
-        /* Inverse of the above */
-        UNIT_REQUIRED_BY,             /* inverse of 'requires' and 'requisite' is 'required_by' */
-        UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */
-        UNIT_WANTED_BY,               /* inverse of 'wants' */
-        UNIT_BOUND_BY,                /* inverse of 'bind_to' */
-
-        /* Negative dependencies */
-        UNIT_CONFLICTS,               /* inverse of 'conflicts' is 'conflicted_by' */
-        UNIT_CONFLICTED_BY,
-
-        /* Order */
-        UNIT_BEFORE,                  /* inverse of 'before' is 'after' and vice versa */
-        UNIT_AFTER,
-
-        /* On Failure */
-        UNIT_ON_FAILURE,
-
-        /* Triggers (i.e. a socket triggers a service) */
-        UNIT_TRIGGERS,
-        UNIT_TRIGGERED_BY,
-
-        /* Propagate reloads */
-        UNIT_PROPAGATE_RELOAD_TO,
-        UNIT_PROPAGATE_RELOAD_FROM,
-
-        /* 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"
-#include "cgroup-attr.h"
-
-struct Unit {
-        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 */
-        usec_t fragment_mtime;
-
-        /* If there is something to do with this unit, then this is
-         * the job for it */
-        Job *job;
-
-        usec_t job_timeout;
-
-        /* References to this */
-        LIST_HEAD(UnitRef, refs);
-
-        /* Conditions to check */
-        LIST_HEAD(Condition, conditions);
-
-        dual_timestamp condition_timestamp;
-
-        dual_timestamp inactive_exit_timestamp;
-        dual_timestamp active_enter_timestamp;
-        dual_timestamp active_exit_timestamp;
-        dual_timestamp inactive_enter_timestamp;
-
-        /* Counterparts in the cgroup filesystem */
-        CGroupBonding *cgroup_bondings;
-        CGroupAttribute *cgroup_attributes;
-
-        /* Per type list */
-        LIST_FIELDS(Unit, units_by_type);
-
-        /* Load queue */
-        LIST_FIELDS(Unit, load_queue);
-
-        /* D-Bus queue */
-        LIST_FIELDS(Unit, dbus_queue);
-
-        /* Cleanup queue */
-        LIST_FIELDS(Unit, cleanup_queue);
-
-        /* GC queue */
-        LIST_FIELDS(Unit, gc_queue);
-
-        /* Used during GC sweeps */
-        unsigned gc_marker;
-
-        /* When deserializing, temporarily store the job type for this
-         * unit here, if there was a job scheduled */
-        int deserialized_job; /* This is actually of type JobType */
-
-        /* Error code when we didn't manage to load the unit (negative) */
-        int load_error;
-
-        /* Cached unit file state */
-        UnitFileState unit_file_state;
-
-        /* Garbage collect us we nobody wants or requires us anymore */
-        bool stop_when_unneeded;
-
-        /* Create default dependencies */
-        bool default_dependencies;
-
-        /* Refuse manual starting, allow starting only indirectly via dependency. */
-        bool refuse_manual_start;
-
-        /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */
-        bool refuse_manual_stop;
-
-        /* Allow isolation requests */
-        bool allow_isolate;
-
-        /* Isolate OnFailure unit */
-        bool on_failure_isolate;
-
-        /* Ignore this unit when isolating */
-        bool ignore_on_isolate;
-
-        /* Ignore this unit when snapshotting */
-        bool ignore_on_snapshot;
-
-        /* Did the last condition check suceed? */
-        bool condition_result;
-
-        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;
-
-        bool no_gc:1;
-
-        bool in_audit:1;
-};
-
-struct UnitRef {
-        /* Keeps tracks of references to a unit. This is useful so
-         * that we can merge two units if necessary and correct all
-         * references to them */
-
-        Unit* unit;
-        LIST_FIELDS(UnitRef, refs);
-};
-
-#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"
-#include "path.h"
-
-struct UnitVTable {
-        const char *suffix;
-
-        /* How much memory does an object of this unit type need */
-        size_t object_size;
-
-        /* Config file sections this unit type understands, separated
-         * by NUL chars */
-        const char *sections;
-
-        /* 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);
-
-        int (*kill)(Unit *u, KillWho w, KillMode m, int signo, DBusError *error);
-
-        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 fine grained 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);
-
-        /* Check whether unit needs a daemon reload */
-        bool (*need_daemon_reload)(Unit *u);
-
-        /* Reset failed state if we are in failed state */
-        void (*reset_failed)(Unit *u);
-
-        /* Called whenever any of the cgroups this unit watches for
-         * ran empty */
-        void (*cgroup_notify_empty)(Unit *u);
-
-        /* Called whenever a process of this unit sends us a message */
-        void (*notify_message)(Unit *u, pid_t pid, char **tags);
-
-        /* 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, DBusConnection *c, DBusMessage *message);
-
-        /* Return the unit this unit is following */
-        Unit *(*following)(Unit *u);
-
-        /* Return the set of units that are following each other */
-        int (*following_set)(Unit *u, Set **s);
-
-        /* 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);
-
-        /* When sending out PropertiesChanged signal, which properties
-         * shall be invalidated? This is a NUL separated list of
-         * strings, to minimize relocations a little. */
-        const char *bus_invalidating_properties;
-
-        /* The interface name */
-        const char *bus_interface;
-
-        /* Can units of this type have multiple names? */
-        bool no_alias:1;
-
-        /* Instances make no sense for this type */
-        bool no_instances:1;
-
-        /* Exclude from automatic gc */
-        bool no_gc:1;
-
-        /* Show status updates on the console */
-        bool show_status:1;
-};
-
-extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
-
-#define UNIT_VTABLE(u) unit_vtable[(u)->type]
-
-/* For casting a unit into the various unit types */
-#define DEFINE_CAST(UPPERCASE, MixedCase)                               \
-        static inline MixedCase* UPPERCASE(Unit *u) {                   \
-                if (_unlikely_(!u || u->type != UNIT_##UPPERCASE))      \
-                        return NULL;                                    \
-                                                                        \
-                return (MixedCase*) u;                                  \
-        }
-
-/* For casting the various unit types into a unit */
-#define UNIT(u) (&(u)->meta)
-
-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);
-DEFINE_CAST(PATH, Path);
-
-Unit *unit_new(Manager *m, size_t size);
-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_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, 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_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, 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_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, 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_cgroups(Unit *u);
-CGroupBonding* unit_get_default_cgroup(Unit *u);
-int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback);
-
-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(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);
-bool unit_can_isolate(Unit *u);
-
-int unit_start(Unit *u);
-int unit_stop(Unit *u);
-int unit_reload(Unit *u);
-
-int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error);
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success);
-
-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);
-
-int unit_coldplug(Unit *u);
-
-void unit_status_printf(Unit *u, const char *status, const char *format, ...);
-
-bool unit_need_daemon_reload(Unit *u);
-
-void unit_reset_failed(Unit *u);
-
-Unit *unit_following(Unit *u);
-
-bool unit_pending_inactive(Unit *u);
-bool unit_pending_active(Unit *u);
-
-int unit_add_default_target_dependency(Unit *u, Unit *target);
-
-int unit_following_set(Unit *u, Set **s);
-
-UnitType unit_name_to_type(const char *n);
-bool unit_name_is_valid(const char *n, bool template_ok);
-
-void unit_trigger_on_failure(Unit *u);
-
-bool unit_condition_test(Unit *u);
-
-UnitFileState unit_get_unit_file_state(Unit *u);
-
-Unit* unit_ref_set(UnitRef *ref, Unit *u);
-void unit_ref_unset(UnitRef *ref);
-
-#define UNIT_DEREF(ref) ((ref).unit)
-
-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);
-
-#endif



More information about the systemd-commits mailing list