[systemd-commits] Makefile.am src/cgroup-show.c src/cgroup-show.h src/dbus-common.c src/dbus-common.h src/hostname-setup.c src/hostname-setup.h src/install.c src/install.h src/logs-show.c src/logs-show.h src/loopback-setup.c src/loopback-setup.h src/machine-id-setup.c src/machine-id-setup.h src/mount-setup.c src/mount-setup.h src/path-lookup.c src/path-lookup.h src/shared src/spawn-ask-password-agent.c src/spawn-ask-password-agent.h src/spawn-polkit-agent.c src/spawn-polkit-agent.h src/specifier.c src/specifier.h src/umount.c src/umount.h src/unit-name.c src/unit-name.h src/utmp-wtmp.c src/utmp-wtmp.h src/watchdog.c src/watchdog.h

Kay Sievers kay at kemper.freedesktop.org
Thu Apr 12 03:54:10 PDT 2012


 Makefile.am                           |  161 +-
 src/cgroup-show.c                     |  261 ----
 src/cgroup-show.h                     |   30 
 src/dbus-common.c                     | 1096 -------------------
 src/dbus-common.h                     |  198 ---
 src/hostname-setup.c                  |  187 ---
 src/hostname-setup.h                  |   27 
 src/install.c                         | 1954 ----------------------------------
 src/install.h                         |   89 -
 src/logs-show.c                       |  677 -----------
 src/logs-show.h                       |   56 
 src/loopback-setup.c                  |  274 ----
 src/loopback-setup.h                  |   27 
 src/machine-id-setup.c                |  265 ----
 src/machine-id-setup.h                |   27 
 src/mount-setup.c                     |  423 -------
 src/mount-setup.h                     |   36 
 src/path-lookup.c                     |  348 ------
 src/path-lookup.h                     |   40 
 src/shared/cgroup-show.c              |  261 ++++
 src/shared/cgroup-show.h              |   30 
 src/shared/dbus-common.c              | 1096 +++++++++++++++++++
 src/shared/dbus-common.h              |  198 +++
 src/shared/hostname-setup.c           |  187 +++
 src/shared/hostname-setup.h           |   27 
 src/shared/install.c                  | 1954 ++++++++++++++++++++++++++++++++++
 src/shared/install.h                  |   89 +
 src/shared/logs-show.c                |  677 +++++++++++
 src/shared/logs-show.h                |   56 
 src/shared/loopback-setup.c           |  274 ++++
 src/shared/loopback-setup.h           |   27 
 src/shared/machine-id-setup.c         |  265 ++++
 src/shared/machine-id-setup.h         |   27 
 src/shared/mount-setup.c              |  423 +++++++
 src/shared/mount-setup.h              |   36 
 src/shared/path-lookup.c              |  348 ++++++
 src/shared/path-lookup.h              |   40 
 src/shared/spawn-ask-password-agent.c |   67 +
 src/shared/spawn-ask-password-agent.h |   28 
 src/shared/spawn-polkit-agent.c       |   86 +
 src/shared/spawn-polkit-agent.h       |   28 
 src/shared/specifier.c                |  108 +
 src/shared/specifier.h                |   37 
 src/shared/umount.c                   |  644 +++++++++++
 src/shared/umount.h                   |   33 
 src/shared/unit-name.c                |  448 +++++++
 src/shared/unit-name.h                |   57 
 src/shared/utmp-wtmp.c                |  430 +++++++
 src/shared/utmp-wtmp.h                |   38 
 src/shared/watchdog.c                 |  169 ++
 src/shared/watchdog.h                 |   31 
 src/spawn-ask-password-agent.c        |   67 -
 src/spawn-ask-password-agent.h        |   28 
 src/spawn-polkit-agent.c              |   86 -
 src/spawn-polkit-agent.h              |   28 
 src/specifier.c                       |  108 -
 src/specifier.h                       |   37 
 src/umount.c                          |  644 -----------
 src/umount.h                          |   33 
 src/unit-name.c                       |  448 -------
 src/unit-name.h                       |   57 
 src/utmp-wtmp.c                       |  430 -------
 src/utmp-wtmp.h                       |   38 
 src/watchdog.c                        |  169 --
 src/watchdog.h                        |   31 
 65 files changed, 8281 insertions(+), 8318 deletions(-)

New commits:
commit f33d3ec1d7521c91da8b30ad5cb345d6416bb07d
Author: Kay Sievers <kay at vrfy.org>
Date:   Thu Apr 12 01:51:49 2012 +0200

    move more common files to shared/ and add them to shared.la

diff --git a/Makefile.am b/Makefile.am
index 0a9f2e5..6601e18 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -120,7 +120,7 @@ AM_CPPFLAGS = \
 	-DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
 	-DX_SERVER=\"$(bindir)/X\" \
 	-DUDEVLIBEXECDIR=\""$(libexecdir)/udev"\" \
-        -DPOLKIT_AGENT_BINARY_PATH=\"$(bindir)/pkttyagent\" \
+	-DPOLKIT_AGENT_BINARY_PATH=\"$(bindir)/pkttyagent\" \
 	-I $(top_srcdir)/src \
 	-I $(top_srcdir)/src/shared \
 	-I $(top_srcdir)/src/readahead \
@@ -458,8 +458,8 @@ dist_doc_DATA = \
 	README \
 	NEWS \
 	LICENSE.LGPL2.1 \
-        LICENSE.GPL2 \
-        LICENSE.MIT \
+	LICENSE.GPL2 \
+	LICENSE.MIT \
 	DISTRO_PORTING
 
 pkgconfigdata_DATA = \
@@ -583,14 +583,50 @@ libsystemd_shared_la_SOURCES = \
 	src/shared/socket-util.h \
 	src/shared/cgroup-util.c \
 	src/shared/cgroup-util.h \
+	src/shared/dbus-common.c \
+	src/shared/dbus-common.h \
+	src/shared/hostname-setup.c \
+	src/shared/hostname-setup.h \
+	src/shared/logs-show.c \
+	src/shared/logs-show.h \
+	src/shared/cgroup-show.c \
+	src/shared/cgroup-show.h \
+	src/shared/unit-name.c \
+	src/shared/unit-name.h \
+	src/shared/utmp-wtmp.c \
+	src/shared/utmp-wtmp.h \
+	src/shared/watchdog.c \
+	src/shared/watchdog.h \
+	src/shared/umount.c \
+	src/shared/umount.h \
+	src/shared/spawn-ask-password-agent.c \
+	src/shared/spawn-ask-password-agent.h \
+	src/shared/mount-setup.c \
+	src/shared/mount-setup.h \
+	src/shared/machine-id-setup.c \
+	src/shared/machine-id-setup.h \
+	src/shared/loopback-setup.h \
+	src/shared/loopback-setup.c \
+	src/shared/specifier.c \
+	src/shared/specifier.h \
+	src/shared/spawn-polkit-agent.c \
+	src/shared/spawn-polkit-agent.h \
 	src/shared/list.h \
 	src/shared/macro.h
 
+libsystemd_shared_la_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(DBUS_CFLAGS)
+
 # ------------------------------------------------------------------------------
 noinst_LTLIBRARIES += \
 	libsystemd-label.la
 
 libsystemd_label_la_SOURCES = \
+	src/shared/install.c \
+	src/shared/install.h \
+	src/shared/path-lookup.c \
+	src/shared/path-lookup.h \
 	src/shared/cgroup-label.c \
 	src/shared/socket-label.c \
 	src/shared/label.c \
@@ -600,6 +636,7 @@ libsystemd_label_la_SOURCES = \
 
 libsystemd_label_la_CFLAGS = \
 	$(AM_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(SELINUX_CFLAGS)
 
 libsystemd_label_la_LIBADD = \
@@ -655,28 +692,6 @@ noinst_LTLIBRARIES += \
 libsystemd_core_la_SOURCES = \
 	src/def.h \
 	src/missing.h \
-	src/dbus-common.c \
-	src/dbus-common.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/install.c \
-	src/install.h \
-	src/path-lookup.c \
-	src/path-lookup.h \
-	src/unit-name.c \
-	src/unit-name.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/core/unit.c \
@@ -840,15 +855,13 @@ test_ns_LDADD = \
 	libsystemd-core.la
 
 test_loopback_SOURCES = \
-	src/test-loopback.c \
-	src/loopback-setup.c
+	src/test-loopback.c
 
 test_loopback_LDADD = \
 	libsystemd-shared.la
 
 test_hostname_SOURCES = \
-	src/test-hostname.c \
-	src/hostname-setup.c
+	src/test-hostname.c
 
 test_hostname_LDADD = \
 	libsystemd-shared.la
@@ -874,17 +887,13 @@ test_env_replace_LDADD = \
 	libsystemd-shared.la
 
 test_strv_SOURCES = \
-	src/test-strv.c \
-	src/specifier.c
+	src/test-strv.c
 
 test_strv_LDADD = \
 	libsystemd-shared.la
 
 test_install_SOURCES = \
-	src/test-install.c \
-	src/install.c \
-	src/path-lookup.c \
-	src/unit-name.c
+	src/test-install.c
 
 test_install_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -895,17 +904,14 @@ test_install_LDADD = \
 	libsystemd-shared.la
 
 test_watchdog_SOURCES = \
-	src/test-watchdog.c \
-	src/watchdog.c \
-	src/watchdog.h
+	src/test-watchdog.c
 
 test_watchdog_LDADD = \
 	libsystemd-shared.la
 
 # ------------------------------------------------------------------------------
 systemd_initctl_SOURCES = \
-	src/initctl.c \
-	src/dbus-common.c
+	src/initctl.c
 
 systemd_initctl_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -918,9 +924,7 @@ systemd_initctl_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_update_utmp_SOURCES = \
-	src/update-utmp.c \
-	src/dbus-common.c \
-	src/utmp-wtmp.c
+	src/update-utmp.c
 
 systemd_update_utmp_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -934,7 +938,6 @@ systemd_update_utmp_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_shutdownd_SOURCES = \
-	src/utmp-wtmp.c \
 	src/shutdownd.c
 
 systemd_shutdownd_LDADD = \
@@ -947,12 +950,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
+	src/shutdown.c
 
 systemd_shutdown_LDADD = \
 	libsystemd-label.la \
@@ -981,7 +979,6 @@ systemd_tmpfiles_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_machine_id_setup_SOURCES = \
-	src/machine-id-setup.c \
 	src/machine-id-main.c
 
 systemd_machine_id_setup_LDADD = \
@@ -998,8 +995,7 @@ systemd_sysctl_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_fsck_SOURCES = \
-	src/fsck.c \
-	src/dbus-common.c
+	src/fsck.c
 
 systemd_fsck_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -1034,8 +1030,7 @@ systemd_detect_virt_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_getty_generator_SOURCES = \
-	src/getty-generator.c \
-	src/unit-name.c
+	src/getty-generator.c
 
 systemd_getty_generator_LDADD = \
 	libsystemd-label.la \
@@ -1051,16 +1046,14 @@ systemd_rc_local_generator_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_remount_api_vfs_SOURCES = \
-	src/remount-api-vfs.c \
-	src/mount-setup.c
+	src/remount-api-vfs.c
 
 systemd_remount_api_vfs_LDADD = \
 	libsystemd-shared.la
 
 # ------------------------------------------------------------------------------
 systemd_cgroups_agent_SOURCES = \
-	src/cgroups-agent.c \
-	src/dbus-common.c
+	src/cgroups-agent.c
 
 systemd_cgroups_agent_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -1072,20 +1065,7 @@ systemd_cgroups_agent_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemctl_SOURCES = \
-	src/systemctl.c \
-	src/utmp-wtmp.c \
-	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-ask-password-agent.c \
-	src/spawn-ask-password-agent.h \
-	src/spawn-polkit-agent.c \
-	src/spawn-polkit-agent.h \
-	src/logs-show.c \
-	src/logs-show.h
+	src/systemctl.c
 
 systemctl_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -1126,9 +1106,7 @@ systemd_reply_password_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_cgls_SOURCES = \
-	src/cgls.c \
-	src/cgroup-show.c \
-	src/cgroup-show.h
+	src/cgls.c
 
 systemd_cgls_LDADD = \
 	libsystemd-shared.la
@@ -1142,13 +1120,12 @@ systemd_cgtop_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_nspawn_SOURCES = \
-	src/nspawn.c \
-	src/loopback-setup.c
+	src/nspawn.c
 
 systemd_nspawn_LDADD = \
 	libsystemd-label.la \
-	libsystemd-shared.la \
 	libsystemd-capability.la \
+	libsystemd-shared.la \
 	libsystemd-daemon.la
 
 # ------------------------------------------------------------------------------
@@ -1161,8 +1138,7 @@ systemd_stdio_bridge_LDADD = \
 # ------------------------------------------------------------------------------
 systemd_tty_ask_password_agent_SOURCES = \
 	src/tty-ask-password-agent.c \
-	src/ask-password-api.c \
-	src/utmp-wtmp.c
+	src/ask-password-api.c
 
 systemd_tty_ask_password_agent_LDADD = \
 	libsystemd-label.la \
@@ -1978,9 +1954,7 @@ systemd_cat_LDADD = \
 	libsystemd-journal.la
 
 journalctl_SOURCES = \
-	src/journal/journalctl.c \
-	src/logs-show.c \
-	src/logs-show.h
+	src/journal/journalctl.c
 
 journalctl_LDADD = \
 	libsystemd-shared.la \
@@ -2353,8 +2327,7 @@ systemd_cryptsetup_LDADD = \
 	$(LIBCRYPTSETUP_LIBS)
 
 systemd_cryptsetup_generator_SOURCES = \
-	src/cryptsetup/cryptsetup-generator.c \
-	src/unit-name.c
+	src/cryptsetup/cryptsetup-generator.c
 
 systemd_cryptsetup_generator_LDADD = \
 	libsystemd-label.la \
@@ -2375,7 +2348,6 @@ endif
 if ENABLE_HOSTNAMED
 systemd_hostnamed_SOURCES = \
 	src/hostname/hostnamed.c \
-	src/dbus-common.c \
 	src/polkit.c
 
 systemd_hostnamed_CFLAGS = \
@@ -2426,7 +2398,6 @@ endif
 if ENABLE_LOCALED
 systemd_localed_SOURCES = \
 	src/locale/localed.c \
-	src/dbus-common.c \
 	src/polkit.c
 
 systemd_localed_CFLAGS = \
@@ -2488,7 +2459,6 @@ endif
 if ENABLE_TIMEDATED
 systemd_timedated_SOURCES = \
 	src/timedate/timedated.c \
-	src/dbus-common.c \
 	src/polkit.c
 
 systemd_timedated_CFLAGS = \
@@ -2552,7 +2522,6 @@ systemd_logind_SOURCES = \
 	src/login/logind-session-dbus.c \
 	src/login/logind-seat-dbus.c \
 	src/login/logind-user-dbus.c \
-	src/dbus-common.c \
 	src/dbus-loop.c \
 	src/polkit.c \
 	src/login/logind-acl.h
@@ -2592,12 +2561,7 @@ rootlibexec_PROGRAMS += \
 
 loginctl_SOURCES = \
 	src/login/loginctl.c \
-	src/login/sysfs-show.c \
-	src/dbus-common.c \
-	src/spawn-polkit-agent.c \
-	src/spawn-polkit-agent.h \
-	src/cgroup-show.c \
-	src/cgroup-show.h
+	src/login/sysfs-show.c
 
 loginctl_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -2639,8 +2603,7 @@ libsystemd_login_la_LIBADD = \
 
 if HAVE_PAM
 pam_systemd_la_SOURCES = \
-	src/login/pam-module.c \
-	src/dbus-common.c
+	src/login/pam-module.c
 
 pam_systemd_la_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -2714,7 +2677,7 @@ polkitpolicy_in_files += \
 logind-install-data-hook:
 	$(MKDIR_P) -m 0755 \
 		$(DESTDIR)$(systemunitdir)/multi-user.target.wants \
-                $(DESTDIR)$(localstatedir)/lib/systemd
+		$(DESTDIR)$(localstatedir)/lib/systemd
 	( cd $(DESTDIR)$(systemunitdir) && \
 		rm -f dbus-org.freedesktop.login1.service && \
 		$(LN_S) systemd-logind.service dbus-org.freedesktop.login1.service)
diff --git a/src/cgroup-show.c b/src/cgroup-show.c
deleted file mode 100644
index 550a2f5..0000000
--- a/src/cgroup-show.c
+++ /dev/null
@@ -1,261 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <errno.h>
-
-#include "util.h"
-#include "macro.h"
-#include "cgroup-util.h"
-#include "cgroup-show.h"
-
-static int compare(const void *a, const void *b) {
-        const pid_t *p = a, *q = b;
-
-        if (*p < *q)
-                return -1;
-        if (*p > *q)
-                return 1;
-        return 0;
-}
-
-static unsigned ilog10(unsigned long ul) {
-        int n = 0;
-
-        while (ul > 0) {
-                n++;
-                ul /= 10;
-        }
-
-        return n;
-}
-
-static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
-        char *fn;
-        FILE *f;
-        size_t n = 0, n_allocated = 0;
-        pid_t *pids = NULL;
-        char *p;
-        pid_t pid, biggest = 0;
-        int r;
-
-        if (n_columns <= 0)
-                n_columns = columns();
-
-        if (!prefix)
-                prefix = "";
-
-        if ((r = cg_fix_path(path, &p)) < 0)
-                return r;
-
-        r = asprintf(&fn, "%s/cgroup.procs", p);
-        free(p);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        f = fopen(fn, "re");
-        free(fn);
-
-        if (!f)
-                return -errno;
-
-        while ((r = cg_read_pid(f, &pid)) > 0) {
-
-                if (!kernel_threads && is_kernel_thread(pid) > 0)
-                        continue;
-
-                if (n >= n_allocated) {
-                        pid_t *npids;
-
-                        n_allocated = MAX(16U, n*2U);
-
-                        if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        pids = npids;
-                }
-
-                assert(n < n_allocated);
-                pids[n++] = pid;
-
-                if (pid > biggest)
-                        biggest = pid;
-        }
-
-        if (r < 0)
-                goto finish;
-
-        if (n > 0) {
-                unsigned i, m;
-
-                /* Filter duplicates */
-                m = 0;
-                for (i = 0; i < n; i++) {
-                        unsigned j;
-
-                        for (j = i+1; j < n; j++)
-                                if (pids[i] == pids[j])
-                                        break;
-
-                        if (j >= n)
-                                pids[m++] = pids[i];
-                }
-                n = m;
-
-                /* And sort */
-                qsort(pids, n, sizeof(pid_t), compare);
-
-                if (n_columns > 8)
-                        n_columns -= 8;
-                else
-                        n_columns = 20;
-
-                for (i = 0; i < n; i++) {
-                        char *t = NULL;
-
-                        get_process_cmdline(pids[i], n_columns, true, &t);
-
-                        printf("%s%s %*lu %s\n",
-                               prefix,
-                               (more || i < n-1) ? "\342\224\234" : "\342\224\224",
-                               (int) ilog10(biggest),
-                               (unsigned long) pids[i],
-                               strna(t));
-
-                        free(t);
-                }
-        }
-
-        r = 0;
-
-finish:
-        free(pids);
-
-        if (f)
-                fclose(f);
-
-        return r;
-}
-
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
-        DIR *d;
-        char *last = NULL;
-        char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
-        bool shown_pids = false;
-        int r;
-
-        if (n_columns <= 0)
-                n_columns = columns();
-
-        if (!prefix)
-                prefix = "";
-
-        if ((r = cg_fix_path(path, &fn)) < 0)
-                return r;
-
-        if (!(d = opendir(fn))) {
-                free(fn);
-                return -errno;
-        }
-
-        while ((r = cg_read_subgroup(d, &gn)) > 0) {
-
-                if (!shown_pids) {
-                        show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
-                        shown_pids = true;
-                }
-
-                if (last) {
-                        printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
-
-                        if (!p1)
-                                if (!(p1 = strappend(prefix, "\342\224\202 "))) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                        show_cgroup_by_path(last, p1, n_columns-2, kernel_threads);
-
-                        free(last);
-                        last = NULL;
-                }
-
-                r = asprintf(&last, "%s/%s", fn, gn);
-                free(gn);
-
-                if (r < 0) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-        }
-
-        if (r < 0)
-                goto finish;
-
-        if (!shown_pids)
-                show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads);
-
-        if (last) {
-                printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
-
-                if (!p2)
-                        if (!(p2 = strappend(prefix, "  "))) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                show_cgroup_by_path(last, p2, n_columns-2, kernel_threads);
-        }
-
-        r = 0;
-
-finish:
-        free(p1);
-        free(p2);
-        free(last);
-        free(fn);
-
-        closedir(d);
-
-        return r;
-}
-
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
-        char *p;
-        int r;
-
-        assert(controller);
-        assert(path);
-
-        r = cg_get_path(controller, path, NULL, &p);
-        if (r < 0)
-                return r;
-
-        r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads);
-        free(p);
-
-        return r;
-}
diff --git a/src/cgroup-show.h b/src/cgroup-show.h
deleted file mode 100644
index 5433f46..0000000
--- a/src/cgroup-show.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foocgroupshowhfoo
-#define foocgroupshowhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads);
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads);
-
-#endif
diff --git a/src/dbus-common.c b/src/dbus-common.c
deleted file mode 100644
index 038fdd4..0000000
--- a/src/dbus-common.c
+++ /dev/null
@@ -1,1096 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <dbus/dbus.h>
-#include <string.h>
-#include <sys/epoll.h>
-
-#include "log.h"
-#include "dbus-common.h"
-#include "util.h"
-#include "def.h"
-#include "strv.h"
-
-int bus_check_peercred(DBusConnection *c) {
-        int fd;
-        struct ucred ucred;
-        socklen_t l;
-
-        assert(c);
-
-        assert_se(dbus_connection_get_unix_fd(c, &fd));
-
-        l = sizeof(struct ucred);
-        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
-                log_error("SO_PEERCRED failed: %m");
-                return -errno;
-        }
-
-        if (l != sizeof(struct ucred)) {
-                log_error("SO_PEERCRED returned wrong size.");
-                return -E2BIG;
-        }
-
-        if (ucred.uid != 0 && ucred.uid != geteuid())
-                return -EPERM;
-
-        return 1;
-}
-
-static int sync_auth(DBusConnection *bus, DBusError *error) {
-        usec_t begin, tstamp;
-
-        assert(bus);
-
-        /* This complexity should probably move into D-Bus itself:
-         *
-         * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
-
-        begin = tstamp = now(CLOCK_MONOTONIC);
-        for (;;) {
-
-                if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
-                        break;
-
-                if (dbus_connection_get_is_authenticated(bus))
-                        break;
-
-                if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
-                        break;
-
-                tstamp = now(CLOCK_MONOTONIC);
-        }
-
-        if (!dbus_connection_get_is_connected(bus)) {
-                dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
-                return -ECONNREFUSED;
-        }
-
-        if (!dbus_connection_get_is_authenticated(bus)) {
-                dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
-                return -EACCES;
-        }
-
-        return 0;
-}
-
-int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
-        DBusConnection *bus = NULL;
-        int r;
-        bool private = true;
-
-        assert(_bus);
-
-        if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
-                /* If we are root, then let's talk directly to the
-                 * system instance, instead of going via the bus */
-
-                bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
-                if (!bus)
-                        return -EIO;
-
-        } else {
-                if (t == DBUS_BUS_SESSION) {
-                        const char *e;
-
-                        /* If we are supposed to talk to the instance,
-                         * try via XDG_RUNTIME_DIR first, then
-                         * fallback to normal bus access */
-
-                        e = getenv("XDG_RUNTIME_DIR");
-                        if (e) {
-                                char *p;
-
-                                if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
-                                        return -ENOMEM;
-
-                                bus = dbus_connection_open_private(p, NULL);
-                                free(p);
-                        }
-                }
-
-                if (!bus) {
-                        bus = dbus_bus_get_private(t, error);
-                        if (!bus)
-                                return -EIO;
-
-                        private = false;
-                }
-        }
-
-        dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
-        if (private) {
-                if (bus_check_peercred(bus) < 0) {
-                        dbus_connection_close(bus);
-                        dbus_connection_unref(bus);
-
-                        dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
-                        return -EACCES;
-                }
-        }
-
-        r = sync_auth(bus, error);
-        if (r < 0) {
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-                return r;
-        }
-
-        if (_private)
-                *_private = private;
-
-        *_bus = bus;
-        return 0;
-}
-
-int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
-        DBusConnection *bus;
-        char *p = NULL;
-        int r;
-
-        assert(_bus);
-        assert(user || host);
-
-        if (user && host)
-                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
-        else if (user)
-                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s at localhost,argv3=systemd-stdio-bridge", user);
-        else if (host)
-                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
-
-        if (!p) {
-                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
-                return -ENOMEM;
-        }
-
-        bus = dbus_connection_open_private(p, error);
-        free(p);
-
-        if (!bus)
-                return -EIO;
-
-        dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
-        if ((r = sync_auth(bus, error)) < 0) {
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-                return r;
-        }
-
-        if (!dbus_bus_register(bus, error)) {
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-                return r;
-        }
-
-        *_bus = bus;
-        return 0;
-}
-
-int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
-        DBusConnection *bus;
-        int r;
-
-        assert(_bus);
-
-        /* Don't bother with PolicyKit if we are root */
-        if (geteuid() == 0)
-                return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
-
-        bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
-        if (!bus)
-                return -EIO;
-
-        dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
-        if ((r = sync_auth(bus, error)) < 0) {
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-                return r;
-        }
-
-        if (!dbus_bus_register(bus, error)) {
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-                return r;
-        }
-
-        *_bus = bus;
-        return 0;
-}
-
-const char *bus_error_message(const DBusError *error) {
-        assert(error);
-
-        /* Sometimes the D-Bus server is a little bit too verbose with
-         * its error messages, so let's override them here */
-        if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
-                return "Access denied";
-
-        return error->message;
-}
-
-DBusHandlerResult bus_default_message_handler(
-                DBusConnection *c,
-                DBusMessage *message,
-                const char *introspection,
-                const char *interfaces,
-                const BusBoundProperties *bound_properties) {
-
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(c);
-        assert(message);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
-                const char *interface, *property;
-                const BusBoundProperties *bp;
-                const BusProperty *p;
-                void *data;
-                DBusMessageIter iter, sub;
-
-                if (!dbus_message_get_args(
-                            message,
-                            &error,
-                            DBUS_TYPE_STRING, &interface,
-                            DBUS_TYPE_STRING, &property,
-                            DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(c, message, &error, -EINVAL);
-
-                for (bp = bound_properties; bp->interface; bp++) {
-                        if (!streq(bp->interface, interface))
-                                continue;
-
-                        for (p = bp->properties; p->property; p++)
-                                if (streq(p->property, property))
-                                        goto get_prop;
-                }
-
-                /* no match */
-                if (!nulstr_contains(interfaces, interface))
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                else
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
-
-                return bus_send_error_reply(c, message, &error, -EINVAL);
-
-get_prop:
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
-                        goto oom;
-
-                data = (char*)bp->base + p->offset;
-                if (p->indirect)
-                        data = *(void**)data;
-                r = p->append(&sub, property, data);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-
-                        dbus_message_unref(reply);
-                        return bus_send_error_reply(c, message, NULL, r);
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
-                const char *interface;
-                const BusBoundProperties *bp;
-                const BusProperty *p;
-                DBusMessageIter iter, sub, sub2, sub3;
-
-                if (!dbus_message_get_args(
-                            message,
-                            &error,
-                            DBUS_TYPE_STRING, &interface,
-                            DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(c, message, &error, -EINVAL);
-
-                if (interface[0] && !nulstr_contains(interfaces, interface)) {
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                        return bus_send_error_reply(c, message, &error, -EINVAL);
-                }
-
-                if (!(reply = dbus_message_new_method_return(message)))
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
-                        goto oom;
-
-                for (bp = bound_properties; bp->interface; bp++) {
-                        if (interface[0] && !streq(bp->interface, interface))
-                                continue;
-
-                        for (p = bp->properties; p->property; p++) {
-                                void *data;
-
-                                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
-                                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
-                                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
-                                        goto oom;
-
-                                data = (char*)bp->base + p->offset;
-                                if (p->indirect)
-                                        data = *(void**)data;
-                                r = p->append(&sub3, p->property, data);
-                                if (r < 0) {
-                                        if (r == -ENOMEM)
-                                                goto oom;
-
-                                        dbus_message_unref(reply);
-                                        return bus_send_error_reply(c, message, NULL, r);
-                                }
-
-                                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
-                                    !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.DBus.Properties", "Set") && bound_properties) {
-                const char *interface, *property;
-                DBusMessageIter iter;
-                const BusBoundProperties *bp;
-                const BusProperty *p;
-                DBusMessageIter sub;
-                char *sig;
-                void *data;
-
-                if (!dbus_message_iter_init(message, &iter) ||
-                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                        return bus_send_error_reply(c, message, NULL, -EINVAL);
-
-                dbus_message_iter_get_basic(&iter, &interface);
-
-                if (!dbus_message_iter_next(&iter) ||
-                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                        return bus_send_error_reply(c, message, NULL, -EINVAL);
-
-                dbus_message_iter_get_basic(&iter, &property);
-
-                if (!dbus_message_iter_next(&iter) ||
-                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
-                    dbus_message_iter_has_next(&iter))
-                        return bus_send_error_reply(c, message, NULL, -EINVAL);
-
-                for (bp = bound_properties; bp->interface; bp++) {
-                        if (!streq(bp->interface, interface))
-                                continue;
-
-                        for (p = bp->properties; p->property; p++)
-                                if (streq(p->property, property))
-                                        goto set_prop;
-                }
-
-                /* no match */
-                if (!nulstr_contains(interfaces, interface))
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                else
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
-
-                return bus_send_error_reply(c, message, &error, -EINVAL);
-
-set_prop:
-                if (!p->set) {
-                        dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
-                        return bus_send_error_reply(c, message, &error, -EINVAL);
-                }
-
-                dbus_message_iter_recurse(&iter, &sub);
-
-                sig = dbus_message_iter_get_signature(&sub);
-                if (!sig)
-                        goto oom;
-
-                if (!streq(sig, p->signature)) {
-                        dbus_free(sig);
-                        return bus_send_error_reply(c, message, NULL, -EINVAL);
-                }
-
-                dbus_free(sig);
-
-                data = (char*)bp->base + p->offset;
-                if (p->indirect)
-                        data = *(void**)data;
-                r = p->set(&sub, property, data);
-                if (r < 0) {
-                        if (r == -ENOMEM)
-                                goto oom;
-                        return bus_send_error_reply(c, message, NULL, r);
-                }
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-        } else {
-                const char *interface = dbus_message_get_interface(message);
-
-                if (!interface || !nulstr_contains(interfaces, interface)) {
-                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
-                        return bus_send_error_reply(c, message, &error, -EINVAL);
-                }
-        }
-
-        if (reply) {
-                if (!dbus_connection_send(c, reply, NULL))
-                        goto oom;
-
-                dbus_message_unref(reply);
-                return DBUS_HANDLER_RESULT_HANDLED;
-        }
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
-        const char *t = data;
-
-        assert(i);
-        assert(property);
-
-        if (!t)
-                t = "";
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
-        char **t = data;
-
-        assert(i);
-        assert(property);
-
-        return bus_append_strv_iter(i, t);
-}
-
-int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
-        bool *b = data;
-        dbus_bool_t db;
-
-        assert(i);
-        assert(property);
-        assert(b);
-
-        db = *b;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
-        int *b = data;
-        dbus_bool_t db;
-
-        assert(i);
-        assert(property);
-        assert(b);
-
-        db = *b > 0;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
-        assert(i);
-        assert(property);
-        assert(data);
-
-        /* Let's ensure that usec_t is actually 64bit, and hence this
-         * function can be used for usec_t */
-        assert_cc(sizeof(uint64_t) == sizeof(usec_t));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
-        assert(i);
-        assert(property);
-        assert(data);
-
-        /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
-         * 32bit, and hence this function can be used for
-         * pid_t/mode_t/uid_t/gid_t */
-        assert_cc(sizeof(uint32_t) == sizeof(pid_t));
-        assert_cc(sizeof(uint32_t) == sizeof(mode_t));
-        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
-        assert_cc(sizeof(uint32_t) == sizeof(uid_t));
-        assert_cc(sizeof(uint32_t) == sizeof(gid_t));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
-        assert(i);
-        assert(property);
-        assert(data);
-
-        assert_cc(sizeof(int32_t) == sizeof(int));
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(data);
-
-        u = (uint64_t) *(size_t*) data;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(data);
-
-        u = (uint64_t) *(unsigned long*) data;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
-        int64_t l;
-
-        assert(i);
-        assert(property);
-        assert(data);
-
-        l = (int64_t) *(long*) data;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
-                return -ENOMEM;
-
-        return 0;
-}
-
-const char *bus_errno_to_dbus(int error) {
-
-        switch(error) {
-
-        case -EINVAL:
-                return DBUS_ERROR_INVALID_ARGS;
-
-        case -ENOMEM:
-                return DBUS_ERROR_NO_MEMORY;
-
-        case -EPERM:
-        case -EACCES:
-                return DBUS_ERROR_ACCESS_DENIED;
-
-        case -ESRCH:
-                return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
-
-        case -ENOENT:
-                return DBUS_ERROR_FILE_NOT_FOUND;
-
-        case -EEXIST:
-                return DBUS_ERROR_FILE_EXISTS;
-
-        case -ETIMEDOUT:
-        case -ETIME:
-                return DBUS_ERROR_TIMEOUT;
-
-        case -EIO:
-                return DBUS_ERROR_IO_ERROR;
-
-        case -ENETRESET:
-        case -ECONNABORTED:
-        case -ECONNRESET:
-                return DBUS_ERROR_DISCONNECTED;
-        }
-
-        return DBUS_ERROR_FAILED;
-}
-
-DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
-        DBusMessage *reply = NULL;
-        const char *name, *text;
-
-        if (berror && dbus_error_is_set(berror)) {
-                name = berror->name;
-                text = berror->message;
-        } else {
-                name = bus_errno_to_dbus(error);
-                text = strerror(-error);
-        }
-
-        if (!(reply = dbus_message_new_error(message, name, text)))
-                goto oom;
-
-        if (!dbus_connection_send(c, reply, NULL))
-                goto oom;
-
-        dbus_message_unref(reply);
-
-        if (berror)
-                dbus_error_free(berror);
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        if (reply)
-                dbus_message_unref(reply);
-
-        if (berror)
-                dbus_error_free(berror);
-
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
-        DBusMessage *m;
-        DBusMessageIter iter, sub;
-        const char *i;
-
-        assert(interface);
-        assert(properties);
-
-        if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
-                goto oom;
-
-        dbus_message_iter_init_append(m, &iter);
-
-        /* We won't send any property values, since they might be
-         * large and sometimes not cheap to generated */
-
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
-            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
-            !dbus_message_iter_close_container(&iter, &sub) ||
-            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
-                goto oom;
-
-        NULSTR_FOREACH(i, properties)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
-                        goto oom;
-
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                goto oom;
-
-        return m;
-
-oom:
-        if (m)
-                dbus_message_unref(m);
-
-        return NULL;
-}
-
-uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
-        unsigned flags;
-        uint32_t events = 0;
-
-        assert(bus_watch);
-
-        /* no watch flags for disabled watches */
-        if (!dbus_watch_get_enabled(bus_watch))
-                return 0;
-
-        flags = dbus_watch_get_flags(bus_watch);
-
-        if (flags & DBUS_WATCH_READABLE)
-                events |= EPOLLIN;
-        if (flags & DBUS_WATCH_WRITABLE)
-                events |= EPOLLOUT;
-
-        return events | EPOLLHUP | EPOLLERR;
-}
-
-unsigned bus_events_to_flags(uint32_t events) {
-        unsigned flags = 0;
-
-        if (events & EPOLLIN)
-                flags |= DBUS_WATCH_READABLE;
-        if (events & EPOLLOUT)
-                flags |= DBUS_WATCH_WRITABLE;
-        if (events & EPOLLHUP)
-                flags |= DBUS_WATCH_HANGUP;
-        if (events & EPOLLERR)
-                flags |= DBUS_WATCH_ERROR;
-
-        return flags;
-}
-
-int bus_parse_strv(DBusMessage *m, char ***_l) {
-        DBusMessageIter iter;
-
-        assert(m);
-        assert(_l);
-
-        if (!dbus_message_iter_init(m, &iter))
-                return -EINVAL;
-
-        return bus_parse_strv_iter(&iter, _l);
-}
-
-int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
-        DBusMessageIter sub;
-        unsigned n = 0, i = 0;
-        char **l;
-
-        assert(iter);
-        assert(_l);
-
-        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
-            return -EINVAL;
-
-        dbus_message_iter_recurse(iter, &sub);
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                n++;
-                dbus_message_iter_next(&sub);
-        }
-
-        if (!(l = new(char*, n+1)))
-                return -ENOMEM;
-
-        dbus_message_iter_recurse(iter, &sub);
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *s;
-
-                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
-                dbus_message_iter_get_basic(&sub, &s);
-
-                if (!(l[i++] = strdup(s))) {
-                        strv_free(l);
-                        return -ENOMEM;
-                }
-
-                dbus_message_iter_next(&sub);
-        }
-
-        assert(i == n);
-        l[i] = NULL;
-
-        if (_l)
-                *_l = l;
-
-        return 0;
-}
-
-int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
-        DBusMessageIter sub;
-
-        assert(iter);
-
-        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
-
-        STRV_FOREACH(l, l)
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
-                        return -ENOMEM;
-
-        if (!dbus_message_iter_close_container(iter, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
-
-        assert(iter);
-        assert(data);
-
-        if (dbus_message_iter_get_arg_type(iter) != type)
-                return -EIO;
-
-        dbus_message_iter_get_basic(iter, data);
-
-        if (!dbus_message_iter_next(iter) != !next)
-                return -EIO;
-
-        return 0;
-}
-
-int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
-        assert(name);
-        assert(iter);
-
-        switch (dbus_message_iter_get_arg_type(iter)) {
-
-        case DBUS_TYPE_STRING: {
-                const char *s;
-                dbus_message_iter_get_basic(iter, &s);
-
-                if (all || !isempty(s))
-                        printf("%s=%s\n", name, s);
-
-                return 1;
-        }
-
-        case DBUS_TYPE_BOOLEAN: {
-                dbus_bool_t b;
-
-                dbus_message_iter_get_basic(iter, &b);
-                printf("%s=%s\n", name, yes_no(b));
-
-                return 1;
-        }
-
-        case DBUS_TYPE_UINT64: {
-                uint64_t u;
-                dbus_message_iter_get_basic(iter, &u);
-
-                /* Yes, heuristics! But we can change this check
-                 * should it turn out to not be sufficient */
-
-                if (endswith(name, "Timestamp")) {
-                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
-
-                        t = format_timestamp(timestamp, sizeof(timestamp), u);
-                        if (t || all)
-                                printf("%s=%s\n", name, strempty(t));
-
-                } else if (strstr(name, "USec")) {
-                        char timespan[FORMAT_TIMESPAN_MAX];
-
-                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
-                } else
-                        printf("%s=%llu\n", name, (unsigned long long) u);
-
-                return 1;
-        }
-
-        case DBUS_TYPE_UINT32: {
-                uint32_t u;
-                dbus_message_iter_get_basic(iter, &u);
-
-                if (strstr(name, "UMask") || strstr(name, "Mode"))
-                        printf("%s=%04o\n", name, u);
-                else
-                        printf("%s=%u\n", name, (unsigned) u);
-
-                return 1;
-        }
-
-        case DBUS_TYPE_INT32: {
-                int32_t i;
-                dbus_message_iter_get_basic(iter, &i);
-
-                printf("%s=%i\n", name, (int) i);
-                return 1;
-        }
-
-        case DBUS_TYPE_DOUBLE: {
-                double d;
-                dbus_message_iter_get_basic(iter, &d);
-
-                printf("%s=%g\n", name, d);
-                return 1;
-        }
-
-        case DBUS_TYPE_ARRAY:
-
-                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
-                        DBusMessageIter sub;
-                        bool space = false;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        if (all ||
-                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                printf("%s=", name);
-
-                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                        const char *s;
-
-                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
-                                        dbus_message_iter_get_basic(&sub, &s);
-                                        printf("%s%s", space ? " " : "", s);
-
-                                        space = true;
-                                        dbus_message_iter_next(&sub);
-                                }
-
-                                puts("");
-                        }
-
-                        return 1;
-
-                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
-                        DBusMessageIter sub;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        if (all ||
-                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                printf("%s=", name);
-
-                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                        uint8_t u;
-
-                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
-                                        dbus_message_iter_get_basic(&sub, &u);
-                                        printf("%02x", u);
-
-                                        dbus_message_iter_next(&sub);
-                                }
-
-                                puts("");
-                        }
-
-                        return 1;
-                }
-
-                break;
-        }
-
-        return 0;
-}
-
-static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
-        DBusMessage *reply;
-        DBusConnection *bus = userdata;
-
-        assert_se(reply = dbus_pending_call_steal_reply(pending));
-        dbus_message_unref(reply);
-
-        dbus_connection_close(bus);
-}
-
-void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
-        DBusMessage *m = NULL;
-        DBusPendingCall *pending = NULL;
-
-        assert(bus);
-
-        /* We unregister the name here, but we continue to process
-         * requests, until we get the response for it, so that all
-         * requests are guaranteed to be processed. */
-
-        m = dbus_message_new_method_call(
-                        DBUS_SERVICE_DBUS,
-                        DBUS_PATH_DBUS,
-                        DBUS_INTERFACE_DBUS,
-                        "ReleaseName");
-        if (!m)
-                goto oom;
-
-        if (!dbus_message_append_args(
-                            m,
-                            DBUS_TYPE_STRING,
-                            &name,
-                            DBUS_TYPE_INVALID))
-                goto oom;
-
-        if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
-                goto oom;
-
-        if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
-                goto oom;
-
-        dbus_message_unref(m);
-        dbus_pending_call_unref(pending);
-
-        return;
-
-oom:
-        log_error("Out of memory");
-
-        if (pending) {
-                dbus_pending_call_cancel(pending);
-                dbus_pending_call_unref(pending);
-        }
-
-        if (m)
-                dbus_message_unref(m);
-}
-
-DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
-        usec_t *remain_until = userdata;
-
-        assert(bus);
-        assert(m);
-        assert(remain_until);
-
-        /* Everytime we get a new message we reset out timeout */
-        *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
-
-        if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
-                dbus_connection_close(bus);
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
diff --git a/src/dbus-common.h b/src/dbus-common.h
deleted file mode 100644
index 38d8e65..0000000
--- a/src/dbus-common.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foodbuscommonhfoo
-#define foodbuscommonhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#ifndef DBUS_ERROR_UNKNOWN_OBJECT
-#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject"
-#endif
-
-#ifndef DBUS_ERROR_UNKNOWN_INTERFACE
-#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface"
-#endif
-
-#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
-#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
-#endif
-
-#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
-#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
-#endif
-
-#define BUS_PROPERTIES_INTERFACE                                        \
-        " <interface name=\"org.freedesktop.DBus.Properties\">\n"       \
-        "  <method name=\"Get\">\n"                                     \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
-        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetAll\">\n"                                  \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"Set\">\n"                                     \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
-        "   <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <signal name=\"PropertiesChanged\">\n"                       \
-        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
-        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
-        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
-        "  </signal>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECTABLE_INTERFACE                                    \
-        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"   \
-        "  <method name=\"Introspect\">\n"                              \
-        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_PEER_INTERFACE                                              \
-        "<interface name=\"org.freedesktop.DBus.Peer\">\n"              \
-        " <method name=\"Ping\"/>\n"                                    \
-        " <method name=\"GetMachineId\">\n"                             \
-        "  <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
-        " </method>\n"                                                  \
-        "</interface>\n"
-
-#define BUS_GENERIC_INTERFACES_LIST             \
-        "org.freedesktop.DBus.Properties\0"     \
-        "org.freedesktop.DBus.Introspectable\0" \
-        "org.freedesktop.DBus.Peer\0"
-
-int bus_check_peercred(DBusConnection *c);
-
-int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error);
-
-int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error);
-int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error);
-
-const char *bus_error_message(const DBusError *error);
-
-typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data);
-typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property, void *data);
-
-typedef struct BusProperty {
-        const char *property;            /* name of the property */
-        BusPropertyCallback append;      /* Function that is called to serialize this property */
-        const char *signature;
-        const uint16_t offset;           /* Offset from BusBoundProperties::base address to the property data.
-                                          * uint16_t is sufficient, because we have no structs too big.
-                                          * -Werror=overflow will catch it if this does not hold. */
-        bool indirect;                   /* data is indirect, ie. not base+offset, but *(base+offset) */
-        BusPropertySetCallback set;      /* Optional: Function that is called to set this property */
-} BusProperty;
-
-typedef struct BusBoundProperties {
-        const char *interface;           /* interface of the properties */
-        const BusProperty *properties;   /* array of properties, ended by a NULL-filled element */
-        const void *const base;          /* base pointer to which the offset must be added to reach data */
-} BusBoundProperties;
-
-DBusHandlerResult bus_send_error_reply(
-                DBusConnection *c,
-                DBusMessage *message,
-                DBusError *bus_error,
-                int error);
-
-DBusHandlerResult bus_default_message_handler(
-                DBusConnection *c,
-                DBusMessage *message,
-                const char *introspection,
-                const char *interfaces,
-                const BusBoundProperties *bound_properties);
-
-int bus_property_append_string(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_size(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data);
-int bus_property_append_long(DBusMessageIter *i, const char *property, void *data);
-
-#define bus_property_append_int bus_property_append_int32
-#define bus_property_append_pid bus_property_append_uint32
-#define bus_property_append_uid bus_property_append_uint32
-#define bus_property_append_gid bus_property_append_uint32
-#define bus_property_append_mode bus_property_append_uint32
-#define bus_property_append_unsigned bus_property_append_uint32
-#define bus_property_append_usec bus_property_append_uint64
-
-#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type)             \
-        int function(DBusMessageIter *i, const char *property, void *data) { \
-                const char *value;                                      \
-                type *field = data;                                     \
-                                                                        \
-                assert(i);                                              \
-                assert(property);                                       \
-                                                                        \
-                value = name##_to_string(*field);                       \
-                                                                        \
-                if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \
-                        return -ENOMEM;                                 \
-                                                                        \
-                return 0;                                               \
-        }
-
-#define DEFINE_BUS_PROPERTY_SET_ENUM(function,name,type)                \
-        int function(DBusMessageIter *i, const char *property, void *data) { \
-                const char *value;                                      \
-                type *field = data;                                     \
-                                                                        \
-                assert(i);                                              \
-                assert(property);                                       \
-                                                                        \
-                dbus_message_iter_get_basic(i, &value);                 \
-                                                                        \
-                *field = name##_from_string(value);                     \
-                                                                        \
-                return 0;                                               \
-        }
-
-const char *bus_errno_to_dbus(int error);
-
-DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties);
-
-uint32_t bus_flags_to_events(DBusWatch *bus_watch);
-unsigned bus_events_to_flags(uint32_t events);
-
-int bus_parse_strv(DBusMessage *m, char ***_l);
-int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l);
-
-int bus_append_strv_iter(DBusMessageIter *iter, char **l);
-
-int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next);
-
-int generic_print_property(const char *name, DBusMessageIter *iter, bool all);
-
-void bus_async_unregister_and_exit(DBusConnection *bus, const char *name);
-
-DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata);
-
-#endif
diff --git a/src/hostname-setup.c b/src/hostname-setup.c
deleted file mode 100644
index 550d3c2..0000000
--- a/src/hostname-setup.c
+++ /dev/null
@@ -1,187 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "hostname-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-
-#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
-#define FILENAME "/etc/sysconfig/network"
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
-#define FILENAME "/etc/HOSTNAME"
-#elif defined(TARGET_ARCH)
-#define FILENAME "/etc/rc.conf"
-#elif defined(TARGET_GENTOO)
-#define FILENAME "/etc/conf.d/hostname"
-#endif
-
-static int read_and_strip_hostname(const char *path, char **hn) {
-        char *s;
-        int r;
-
-        assert(path);
-        assert(hn);
-
-        if ((r = read_one_line_file(path, &s)) < 0)
-                return r;
-
-        hostname_cleanup(s);
-
-        if (isempty(s)) {
-                free(s);
-                return -ENOENT;
-        }
-
-        *hn = s;
-
-        return 0;
-}
-
-static int read_distro_hostname(char **hn) {
-
-#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
-        int r;
-        FILE *f;
-
-        assert(hn);
-
-        if (!(f = fopen(FILENAME, "re")))
-                return -errno;
-
-        for (;;) {
-                char line[LINE_MAX];
-                char *s, *k;
-
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                break;
-
-                        r = -errno;
-                        goto finish;
-                }
-
-                s = strstrip(line);
-
-                if (!startswith_no_case(s, "HOSTNAME="))
-                        continue;
-
-                if (!(k = strdup(s+9))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                hostname_cleanup(k);
-
-                if (isempty(k)) {
-                        free(k);
-                        r = -ENOENT;
-                        goto finish;
-                }
-
-                *hn = k;
-                r = 0;
-                goto finish;
-        }
-
-        r = -ENOENT;
-
-finish:
-        fclose(f);
-        return r;
-
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
-        return read_and_strip_hostname(FILENAME, hn);
-#else
-        return -ENOENT;
-#endif
-}
-
-static int read_hostname(char **hn) {
-        int r;
-
-        assert(hn);
-
-        /* First, try to load the generic hostname configuration file,
-         * that we support on all distributions */
-
-        if ((r = read_and_strip_hostname("/etc/hostname", hn)) < 0) {
-
-                if (r == -ENOENT)
-                        return read_distro_hostname(hn);
-
-                return r;
-        }
-
-        return 0;
-}
-
-int hostname_setup(void) {
-        int r;
-        char *b = NULL;
-        const char *hn = NULL;
-
-        if ((r = read_hostname(&b)) < 0) {
-                if (r == -ENOENT)
-                        log_info("No hostname configured.");
-                else
-                        log_warning("Failed to read configured hostname: %s", strerror(-r));
-
-                hn = NULL;
-        } else
-                hn = b;
-
-        if (!hn) {
-                /* Don't override the hostname if it is unset and not
-                 * explicitly configured */
-
-                char *old_hostname = NULL;
-
-                if ((old_hostname = gethostname_malloc())) {
-                        bool already_set;
-
-                        already_set = old_hostname[0] != 0;
-                        free(old_hostname);
-
-                        if (already_set)
-                                goto finish;
-                }
-
-                hn = "localhost";
-        }
-
-        if (sethostname(hn, strlen(hn)) < 0) {
-                log_warning("Failed to set hostname to <%s>: %m", hn);
-                r = -errno;
-        } else
-                log_info("Set hostname to <%s>.", hn);
-
-finish:
-        free(b);
-
-        return r;
-}
diff --git a/src/hostname-setup.h b/src/hostname-setup.h
deleted file mode 100644
index 9550b8c..0000000
--- a/src/hostname-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foohostnamesetuphfoo
-#define foohostnamesetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int hostname_setup(void);
-
-#endif
diff --git a/src/install.c b/src/install.c
deleted file mode 100644
index 080ae6a..0000000
--- a/src/install.c
+++ /dev/null
@@ -1,1954 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty <of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <fnmatch.h>
-
-#include "util.h"
-#include "mkdir.h"
-#include "hashmap.h"
-#include "set.h"
-#include "path-lookup.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "install.h"
-#include "conf-parser.h"
-
-typedef struct {
-        char *name;
-        char *path;
-
-        char **aliases;
-        char **wanted_by;
-} InstallInfo;
-
-typedef struct {
-        Hashmap *will_install;
-        Hashmap *have_installed;
-} InstallContext;
-
-static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
-        assert(paths);
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        zero(*paths);
-
-        return lookup_paths_init(paths,
-                                 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
-                                 scope == UNIT_FILE_USER);
-}
-
-static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
-        char *p = NULL;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(ret);
-
-        switch (scope) {
-
-        case UNIT_FILE_SYSTEM:
-
-                if (root_dir && runtime)
-                        asprintf(&p, "%s/run/systemd/system", root_dir);
-                else if (runtime)
-                        p = strdup("/run/systemd/system");
-                else if (root_dir)
-                        asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
-                else
-                        p = strdup(SYSTEM_CONFIG_UNIT_PATH);
-
-                break;
-
-        case UNIT_FILE_GLOBAL:
-
-                if (root_dir)
-                        return -EINVAL;
-
-                if (runtime)
-                        p = strdup("/run/systemd/user");
-                else
-                        p = strdup(USER_CONFIG_UNIT_PATH);
-                break;
-
-        case UNIT_FILE_USER:
-
-                if (root_dir || runtime)
-                        return -EINVAL;
-
-                r = user_config_home(&p);
-                if (r <= 0)
-                        return r < 0 ? r : -ENOENT;
-
-                break;
-
-        default:
-                assert_not_reached("Bad scope");
-        }
-
-        if (!p)
-                return -ENOMEM;
-
-        *ret = p;
-        return 0;
-}
-
-static int add_file_change(
-                UnitFileChange **changes,
-                unsigned *n_changes,
-                UnitFileChangeType type,
-                const char *path,
-                const char *source) {
-
-        UnitFileChange *c;
-        unsigned i;
-
-        assert(path);
-        assert(!changes == !n_changes);
-
-        if (!changes)
-                return 0;
-
-        c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
-        if (!c)
-                return -ENOMEM;
-
-        *changes = c;
-        i = *n_changes;
-
-        c[i].type = type;
-        c[i].path = strdup(path);
-        if (!c[i].path)
-                return -ENOMEM;
-
-        if (source) {
-                c[i].source = strdup(source);
-                if (!c[i].source) {
-                        free(c[i].path);
-                        return -ENOMEM;
-                }
-        } else
-                c[i].source = NULL;
-
-        *n_changes = i+1;
-        return 0;
-}
-
-static int mark_symlink_for_removal(
-                Set **remove_symlinks_to,
-                const char *p) {
-
-        char *n;
-        int r;
-
-        assert(p);
-
-        r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
-        if (r < 0)
-                return r;
-
-        n = strdup(p);
-        if (!n)
-                return -ENOMEM;
-
-        path_kill_slashes(n);
-
-        r = set_put(*remove_symlinks_to, n);
-        if (r < 0) {
-                free(n);
-                return r == -EEXIST ? 0 : r;
-        }
-
-        return 0;
-}
-
-static int remove_marked_symlinks_fd(
-                Set *remove_symlinks_to,
-                int fd,
-                const char *path,
-                const char *config_path,
-                bool *deleted,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        int r = 0;
-        DIR *d;
-        struct dirent buffer, *de;
-
-        assert(remove_symlinks_to);
-        assert(fd >= 0);
-        assert(path);
-        assert(config_path);
-        assert(deleted);
-
-        d = fdopendir(fd);
-        if (!d) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        rewinddir(d);
-
-        for (;;) {
-                int k;
-
-                k = readdir_r(d, &buffer, &de);
-                if (k != 0) {
-                        r = -errno;
-                        break;
-                }
-
-                if (!de)
-                        break;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                dirent_ensure_type(d, de);
-
-                if (de->d_type == DT_DIR) {
-                        int nfd, q;
-                        char *p;
-
-                        nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
-                        if (nfd < 0) {
-                                if (errno == ENOENT)
-                                        continue;
-
-                                if (r == 0)
-                                        r = -errno;
-                                continue;
-                        }
-
-                        p = path_make_absolute(de->d_name, path);
-                        if (!p) {
-                                close_nointr_nofail(nfd);
-                                r = -ENOMEM;
-                                break;
-                        }
-
-                        /* This will close nfd, regardless whether it succeeds or not */
-                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
-                        free(p);
-
-                        if (r == 0)
-                                r = q;
-
-                } else if (de->d_type == DT_LNK) {
-                        char *p, *dest;
-                        int q;
-                        bool found;
-
-                        p = path_make_absolute(de->d_name, path);
-                        if (!p) {
-                                r = -ENOMEM;
-                                break;
-                        }
-
-                        q = readlink_and_canonicalize(p, &dest);
-                        if (q < 0) {
-                                free(p);
-
-                                if (q == -ENOENT)
-                                        continue;
-
-                                if (r == 0)
-                                        r = q;
-                                continue;
-                        }
-
-                        found =
-                                set_get(remove_symlinks_to, dest) ||
-                                set_get(remove_symlinks_to, file_name_from_path(dest));
-
-                        if (found) {
-
-                                if (unlink(p) < 0 && errno != ENOENT) {
-
-                                        if (r == 0)
-                                                r = -errno;
-                                } else {
-                                        rmdir_parents(p, config_path);
-                                        path_kill_slashes(p);
-
-                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
-
-                                        if (!set_get(remove_symlinks_to, p)) {
-
-                                                q = mark_symlink_for_removal(&remove_symlinks_to, p);
-                                                if (q < 0) {
-                                                        if (r == 0)
-                                                                r = q;
-                                                } else
-                                                        *deleted = true;
-                                        }
-                                }
-                        }
-
-                        free(p);
-                        free(dest);
-                }
-        }
-
-        closedir(d);
-
-        return r;
-}
-
-static int remove_marked_symlinks(
-                Set *remove_symlinks_to,
-                const char *config_path,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        int fd, r = 0;
-        bool deleted;
-
-        assert(config_path);
-
-        if (set_size(remove_symlinks_to) <= 0)
-                return 0;
-
-        fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
-        if (fd < 0)
-                return -errno;
-
-        do {
-                int q, cfd;
-                deleted = false;
-
-                cfd = dup(fd);
-                if (cfd < 0) {
-                        r = -errno;
-                        break;
-                }
-
-                /* This takes possession of cfd and closes it */
-                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
-                if (r == 0)
-                        r = q;
-        } while (deleted);
-
-        close_nointr_nofail(fd);
-
-        return r;
-}
-
-static int find_symlinks_fd(
-                const char *name,
-                int fd,
-                const char *path,
-                const char *config_path,
-                bool *same_name_link) {
-
-        int r = 0;
-        DIR *d;
-        struct dirent buffer, *de;
-
-        assert(name);
-        assert(fd >= 0);
-        assert(path);
-        assert(config_path);
-        assert(same_name_link);
-
-        d = fdopendir(fd);
-        if (!d) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        for (;;) {
-                int k;
-
-                k = readdir_r(d, &buffer, &de);
-                if (k != 0) {
-                        r = -errno;
-                        break;
-                }
-
-                if (!de)
-                        break;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                dirent_ensure_type(d, de);
-
-                if (de->d_type == DT_DIR) {
-                        int nfd, q;
-                        char *p;
-
-                        nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
-                        if (nfd < 0) {
-                                if (errno == ENOENT)
-                                        continue;
-
-                                if (r == 0)
-                                        r = -errno;
-                                continue;
-                        }
-
-                        p = path_make_absolute(de->d_name, path);
-                        if (!p) {
-                                close_nointr_nofail(nfd);
-                                r = -ENOMEM;
-                                break;
-                        }
-
-                        /* This will close nfd, regardless whether it succeeds or not */
-                        q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
-                        free(p);
-
-                        if (q > 0) {
-                                r = 1;
-                                break;
-                        }
-
-                        if (r == 0)
-                                r = q;
-
-                } else if (de->d_type == DT_LNK) {
-                        char *p, *dest;
-                        bool found_path, found_dest, b = false;
-                        int q;
-
-                        /* Acquire symlink name */
-                        p = path_make_absolute(de->d_name, path);
-                        if (!p) {
-                                r = -ENOMEM;
-                                break;
-                        }
-
-                        /* Acquire symlink destination */
-                        q = readlink_and_canonicalize(p, &dest);
-                        if (q < 0) {
-                                free(p);
-
-                                if (q == -ENOENT)
-                                        continue;
-
-                                if (r == 0)
-                                        r = q;
-                                continue;
-                        }
-
-                        /* Check if the symlink itself matches what we
-                         * are looking for */
-                        if (path_is_absolute(name))
-                                found_path = path_equal(p, name);
-                        else
-                                found_path = streq(de->d_name, name);
-
-                        /* Check if what the symlink points to
-                         * matches what we are looking for */
-                        if (path_is_absolute(name))
-                                found_dest = path_equal(dest, name);
-                        else
-                                found_dest = streq(file_name_from_path(dest), name);
-
-                        free(dest);
-
-                        if (found_path && found_dest) {
-                                char *t;
-
-                                /* Filter out same name links in the main
-                                 * config path */
-                                t = path_make_absolute(name, config_path);
-                                if (!t) {
-                                        free(p);
-                                        r = -ENOMEM;
-                                        break;
-                                }
-
-                                b = path_equal(t, p);
-                                free(t);
-                        }
-
-                        free(p);
-
-                        if (b)
-                                *same_name_link = true;
-                        else if (found_path || found_dest) {
-                                r = 1;
-                                break;
-                        }
-                }
-        }
-
-        closedir(d);
-
-        return r;
-}
-
-static int find_symlinks(
-                const char *name,
-                const char *config_path,
-                bool *same_name_link) {
-
-        int fd;
-
-        assert(name);
-        assert(config_path);
-        assert(same_name_link);
-
-        fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
-        if (fd < 0)
-                return -errno;
-
-        /* This takes possession of fd and closes it */
-        return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
-}
-
-static int find_symlinks_in_scope(
-                UnitFileScope scope,
-                const char *root_dir,
-                const char *name,
-                UnitFileState *state) {
-
-        int r;
-        char *path;
-        bool same_name_link_runtime = false, same_name_link = false;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(name);
-
-        if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
-
-                /* First look in runtime config path */
-                r = get_config_path(scope, true, root_dir, &path);
-                if (r < 0)
-                        return r;
-
-                r = find_symlinks(name, path, &same_name_link_runtime);
-                free(path);
-
-                if (r < 0)
-                        return r;
-                else if (r > 0) {
-                        *state = UNIT_FILE_ENABLED_RUNTIME;
-                        return r;
-                }
-        }
-
-        /* Then look in the normal config path */
-        r = get_config_path(scope, false, root_dir, &path);
-        if (r < 0)
-                return r;
-
-        r = find_symlinks(name, path, &same_name_link);
-        free(path);
-
-        if (r < 0)
-                return r;
-        else if (r > 0) {
-                *state = UNIT_FILE_ENABLED;
-                return r;
-        }
-
-        /* Hmm, we didn't find it, but maybe we found the same name
-         * link? */
-        if (same_name_link_runtime) {
-                *state = UNIT_FILE_LINKED_RUNTIME;
-                return 1;
-        } else if (same_name_link) {
-                *state = UNIT_FILE_LINKED;
-                return 1;
-        }
-
-        return 0;
-}
-
-int unit_file_mask(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **i, *prefix;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        r = get_config_path(scope, runtime, root_dir, &prefix);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(i, files) {
-                char *path;
-
-                if (!unit_name_is_valid_no_type(*i, true)) {
-                        if (r == 0)
-                                r = -EINVAL;
-                        continue;
-                }
-
-                path = path_make_absolute(*i, prefix);
-                if (!path) {
-                        r = -ENOMEM;
-                        break;
-                }
-
-                if (symlink("/dev/null", path) >= 0) {
-                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
-
-                        free(path);
-                        continue;
-                }
-
-                if (errno == EEXIST) {
-
-                        if (null_or_empty_path(path) > 0) {
-                                free(path);
-                                continue;
-                        }
-
-                        if (force) {
-                                unlink(path);
-
-                                if (symlink("/dev/null", path) >= 0) {
-
-                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-                                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
-
-                                        free(path);
-                                        continue;
-                                }
-                        }
-
-                        if (r == 0)
-                                r = -EEXIST;
-                } else {
-                        if (r == 0)
-                                r = -errno;
-                }
-
-                free(path);
-        }
-
-        free(prefix);
-
-        return r;
-}
-
-int unit_file_unmask(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **i, *config_path = NULL;
-        int r, q;
-        Set *remove_symlinks_to = NULL;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-                char *path;
-
-                if (!unit_name_is_valid_no_type(*i, true)) {
-                        if (r == 0)
-                                r = -EINVAL;
-                        continue;
-                }
-
-                path = path_make_absolute(*i, config_path);
-                if (!path) {
-                        r = -ENOMEM;
-                        break;
-                }
-
-                q = null_or_empty_path(path);
-                if (q > 0) {
-                        if (unlink(path) >= 0) {
-                                mark_symlink_for_removal(&remove_symlinks_to, path);
-                                add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-
-                                free(path);
-                                continue;
-                        }
-
-                        q = -errno;
-                }
-
-                if (q != -ENOENT && r == 0)
-                        r = q;
-
-                free(path);
-        }
-
-
-finish:
-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-        set_free_free(remove_symlinks_to);
-        free(config_path);
-
-        return r;
-}
-
-int unit_file_link(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        LookupPaths paths;
-        char **i, *config_path = NULL;
-        int r, q;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        zero(paths);
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-                char *path, *fn;
-                struct stat st;
-
-                fn = file_name_from_path(*i);
-
-                if (!path_is_absolute(*i) ||
-                    !unit_name_is_valid_no_type(fn, true)) {
-                        if (r == 0)
-                                r = -EINVAL;
-                        continue;
-                }
-
-                if (lstat(*i, &st) < 0) {
-                        if (r == 0)
-                                r = -errno;
-                        continue;
-                }
-
-                if (!S_ISREG(st.st_mode)) {
-                        r = -ENOENT;
-                        continue;
-                }
-
-                q = in_search_path(*i, paths.unit_path);
-                if (q < 0) {
-                        r = q;
-                        break;
-                }
-
-                if (q > 0)
-                        continue;
-
-                path = path_make_absolute(fn, config_path);
-                if (!path) {
-                        r = -ENOMEM;
-                        break;
-                }
-
-                if (symlink(*i, path) >= 0) {
-                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
-
-                        free(path);
-                        continue;
-                }
-
-                if (errno == EEXIST) {
-                        char *dest = NULL;
-
-                        q = readlink_and_make_absolute(path, &dest);
-
-                        if (q < 0 && errno != ENOENT) {
-                                free(path);
-
-                                if (r == 0)
-                                        r = q;
-
-                                continue;
-                        }
-
-                        if (q >= 0 && path_equal(dest, *i)) {
-                                free(dest);
-                                free(path);
-                                continue;
-                        }
-
-                        free(dest);
-
-                        if (force) {
-                                unlink(path);
-
-                                if (symlink(*i, path) >= 0) {
-
-                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-                                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
-
-                                        free(path);
-                                        continue;
-                                }
-                        }
-
-                        if (r == 0)
-                                r = -EEXIST;
-                } else {
-                        if (r == 0)
-                                r = -errno;
-                }
-
-                free(path);
-        }
-
-                finish:
-        lookup_paths_free(&paths);
-        free(config_path);
-
-        return r;
-}
-
-void unit_file_list_free(Hashmap *h) {
-        UnitFileList *i;
-
-        while ((i = hashmap_steal_first(h))) {
-                free(i->path);
-                free(i);
-        }
-
-        hashmap_free(h);
-}
-
-void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
-        unsigned i;
-
-        assert(changes || n_changes == 0);
-
-        if (!changes)
-                return;
-
-        for (i = 0; i < n_changes; i++) {
-                free(changes[i].path);
-                free(changes[i].source);
-        }
-
-        free(changes);
-}
-
-static void install_info_free(InstallInfo *i) {
-        assert(i);
-
-        free(i->name);
-        free(i->path);
-        strv_free(i->aliases);
-        strv_free(i->wanted_by);
-        free(i);
-}
-
-static void install_info_hashmap_free(Hashmap *m) {
-        InstallInfo *i;
-
-        if (!m)
-                return;
-
-        while ((i = hashmap_steal_first(m)))
-                install_info_free(i);
-
-        hashmap_free(m);
-}
-
-static void install_context_done(InstallContext *c) {
-        assert(c);
-
-        install_info_hashmap_free(c->will_install);
-        install_info_hashmap_free(c->have_installed);
-
-        c->will_install = c->have_installed = NULL;
-}
-
-static int install_info_add(
-                InstallContext *c,
-                const char *name,
-                const char *path) {
-        InstallInfo *i = NULL;
-        int r;
-
-        assert(c);
-        assert(name || path);
-
-        if (!name)
-                name = file_name_from_path(path);
-
-        if (!unit_name_is_valid_no_type(name, true))
-                return -EINVAL;
-
-        if (hashmap_get(c->have_installed, name) ||
-            hashmap_get(c->will_install, name))
-                return 0;
-
-        r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
-        if (r < 0)
-                return r;
-
-        i = new0(InstallInfo, 1);
-        if (!i)
-                return -ENOMEM;
-
-        i->name = strdup(name);
-        if (!i->name) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (path) {
-                i->path = strdup(path);
-                if (!i->path) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        r = hashmap_put(c->will_install, i->name, i);
-        if (r < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        if (i)
-                install_info_free(i);
-
-        return r;
-}
-
-static int install_info_add_auto(
-                InstallContext *c,
-                const char *name_or_path) {
-
-        assert(c);
-        assert(name_or_path);
-
-        if (path_is_absolute(name_or_path))
-                return install_info_add(c, NULL, name_or_path);
-        else
-                return install_info_add(c, name_or_path, NULL);
-}
-
-static int config_parse_also(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char *w;
-        size_t l;
-        char *state;
-        InstallContext *c = data;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char *n;
-                int r;
-
-                n = strndup(w, l);
-                if (!n)
-                        return -ENOMEM;
-
-                r = install_info_add(c, n, NULL);
-                if (r < 0) {
-                        free(n);
-                        return r;
-                }
-
-                free(n);
-        }
-
-        return 0;
-}
-
-static int unit_file_load(
-                InstallContext *c,
-                InstallInfo *info,
-                const char *path,
-                bool allow_symlink) {
-
-        const ConfigTableItem items[] = {
-                { "Install", "Alias",    config_parse_strv, 0, &info->aliases   },
-                { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
-                { "Install", "Also",     config_parse_also, 0, c                },
-                { NULL, NULL, NULL, 0, NULL }
-        };
-
-        int fd;
-        FILE *f;
-        int r;
-
-        assert(c);
-        assert(info);
-        assert(path);
-
-        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
-        if (fd < 0)
-                return -errno;
-
-        f = fdopen(fd, "re");
-        if (!f) {
-                close_nointr_nofail(fd);
-                return -ENOMEM;
-        }
-
-        r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
-        fclose(f);
-        if (r < 0)
-                return r;
-
-        return strv_length(info->aliases) + strv_length(info->wanted_by);
-}
-
-static int unit_file_search(
-                InstallContext *c,
-                InstallInfo *info,
-                LookupPaths *paths,
-                const char *root_dir,
-                bool allow_symlink) {
-
-        char **p;
-        int r;
-
-        assert(c);
-        assert(info);
-        assert(paths);
-
-        if (info->path)
-                return unit_file_load(c, info, info->path, allow_symlink);
-
-        assert(info->name);
-
-        STRV_FOREACH(p, paths->unit_path) {
-                char *path = NULL;
-
-                if (isempty(root_dir))
-                        asprintf(&path, "%s/%s", *p, info->name);
-                else
-                        asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
-
-                if (!path)
-                        return -ENOMEM;
-
-                r = unit_file_load(c, info, path, allow_symlink);
-
-                if (r >= 0)
-                        info->path = path;
-                else
-                        free(path);
-
-                if (r != -ENOENT && r != -ELOOP)
-                        return r;
-        }
-
-        return -ENOENT;
-}
-
-static int unit_file_can_install(
-                LookupPaths *paths,
-                const char *root_dir,
-                const char *name,
-                bool allow_symlink) {
-
-        InstallContext c;
-        InstallInfo *i;
-        int r;
-
-        assert(paths);
-        assert(name);
-
-        zero(c);
-
-        r = install_info_add_auto(&c, name);
-        if (r < 0)
-                return r;
-
-        assert_se(i = hashmap_first(c.will_install));
-
-        r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
-
-        if (r >= 0)
-                r = strv_length(i->aliases) + strv_length(i->wanted_by);
-
-        install_context_done(&c);
-
-        return r;
-}
-
-static int create_symlink(
-                const char *old_path,
-                const char *new_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char *dest;
-        int r;
-
-        assert(old_path);
-        assert(new_path);
-
-        mkdir_parents(new_path, 0755);
-
-        if (symlink(old_path, new_path) >= 0) {
-                add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
-                return 0;
-        }
-
-        if (errno != EEXIST)
-                return -errno;
-
-        r = readlink_and_make_absolute(new_path, &dest);
-        if (r < 0)
-                return r;
-
-        if (path_equal(dest, old_path)) {
-                free(dest);
-                return 0;
-        }
-
-        free(dest);
-
-        if (force)
-                return -EEXIST;
-
-        unlink(new_path);
-
-        if (symlink(old_path, new_path) >= 0) {
-                add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
-                add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
-                return 0;
-        }
-
-        return -errno;
-}
-
-static int install_info_symlink_alias(
-                InstallInfo *i,
-                const char *config_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **s;
-        int r = 0, q;
-
-        assert(i);
-        assert(config_path);
-
-        STRV_FOREACH(s, i->aliases) {
-                char *alias_path;
-
-                alias_path = path_make_absolute(*s, config_path);
-
-                if (!alias_path)
-                        return -ENOMEM;
-
-                q = create_symlink(i->path, alias_path, force, changes, n_changes);
-                free(alias_path);
-
-                if (r == 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-static int install_info_symlink_wants(
-                InstallInfo *i,
-                const char *config_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **s;
-        int r = 0, q;
-
-        assert(i);
-        assert(config_path);
-
-        STRV_FOREACH(s, i->wanted_by) {
-                char *path;
-
-                if (!unit_name_is_valid_no_type(*s, true)) {
-                        r = -EINVAL;
-                        continue;
-                }
-
-                if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
-                        return -ENOMEM;
-
-                q = create_symlink(i->path, path, force, changes, n_changes);
-                free(path);
-
-                if (r == 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-static int install_info_symlink_link(
-                InstallInfo *i,
-                LookupPaths *paths,
-                const char *config_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        int r;
-        char *path;
-
-        assert(i);
-        assert(paths);
-        assert(config_path);
-        assert(i->path);
-
-        r = in_search_path(i->path, paths->unit_path);
-        if (r != 0)
-                return r;
-
-        if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
-                return -ENOMEM;
-
-        r = create_symlink(i->path, path, force, changes, n_changes);
-        free(path);
-
-        return r;
-}
-
-static int install_info_apply(
-                InstallInfo *i,
-                LookupPaths *paths,
-                const char *config_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        int r, q;
-
-        assert(i);
-        assert(paths);
-        assert(config_path);
-
-        r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
-
-        q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-        q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-        return r;
-}
-
-static int install_context_apply(
-                InstallContext *c,
-                LookupPaths *paths,
-                const char *config_path,
-                const char *root_dir,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        InstallInfo *i;
-        int r = 0, q;
-
-        assert(c);
-        assert(paths);
-        assert(config_path);
-
-        while ((i = hashmap_first(c->will_install))) {
-
-                q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
-                if (q < 0)
-                        return q;
-
-                assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
-
-                q = unit_file_search(c, i, paths, root_dir, false);
-                if (q < 0) {
-                        if (r >= 0)
-                                r = q;
-
-                        return r;
-                } else if (r >= 0)
-                        r += q;
-
-                q = install_info_apply(i, paths, config_path, force, changes, n_changes);
-                if (r >= 0 && q < 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-static int install_context_mark_for_removal(
-                InstallContext *c,
-                LookupPaths *paths,
-                Set **remove_symlinks_to,
-                const char *config_path,
-                const char *root_dir) {
-
-        InstallInfo *i;
-        int r = 0, q;
-
-        assert(c);
-        assert(paths);
-        assert(config_path);
-
-        /* Marks all items for removal */
-
-        while ((i = hashmap_first(c->will_install))) {
-
-                q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
-                if (q < 0)
-                        return q;
-
-                assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
-
-                q = unit_file_search(c, i, paths, root_dir, false);
-                if (q < 0) {
-                        if (r >= 0)
-                                r = q;
-
-                        return r;
-                } else if (r >= 0)
-                        r += q;
-
-                q = mark_symlink_for_removal(remove_symlinks_to, i->name);
-                if (r >= 0 && q < 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-int unit_file_enable(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        LookupPaths paths;
-        InstallContext c;
-        char **i, *config_path = NULL;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        zero(paths);
-        zero(c);
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-                r = install_info_add_auto(&c, *i);
-                if (r < 0)
-                        goto finish;
-        }
-
-        /* This will return the number of symlink rules that were
-        supposed to be created, not the ones actually created. This is
-        useful to determine whether the passed files hat any
-        installation data at all. */
-        r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
-
-finish:
-        install_context_done(&c);
-        lookup_paths_free(&paths);
-        free(config_path);
-
-        return r;
-}
-
-int unit_file_disable(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        LookupPaths paths;
-        InstallContext c;
-        char **i, *config_path = NULL;
-        Set *remove_symlinks_to = NULL;
-        int r, q;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        zero(paths);
-        zero(c);
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-                r = install_info_add_auto(&c, *i);
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
-
-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-finish:
-        install_context_done(&c);
-        lookup_paths_free(&paths);
-        set_free_free(remove_symlinks_to);
-        free(config_path);
-
-        return r;
-}
-
-int unit_file_reenable(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        LookupPaths paths;
-        InstallContext c;
-        char **i, *config_path = NULL;
-        Set *remove_symlinks_to = NULL;
-        int r, q;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        zero(paths);
-        zero(c);
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-                r = mark_symlink_for_removal(&remove_symlinks_to, *i);
-                if (r < 0)
-                        goto finish;
-
-                r = install_info_add_auto(&c, *i);
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
-
-        /* Returns number of symlinks that where supposed to be installed. */
-        q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-finish:
-        lookup_paths_free(&paths);
-        install_context_done(&c);
-        set_free_free(remove_symlinks_to);
-        free(config_path);
-
-        return r;
-}
-
-UnitFileState unit_file_get_state(
-                UnitFileScope scope,
-                const char *root_dir,
-                const char *name) {
-
-        LookupPaths paths;
-        UnitFileState state = _UNIT_FILE_STATE_INVALID;
-        char **i, *path = NULL;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(name);
-
-        zero(paths);
-
-        if (root_dir && scope != UNIT_FILE_SYSTEM)
-                return -EINVAL;
-
-        if (!unit_name_is_valid_no_type(name, true))
-                return -EINVAL;
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(i, paths.unit_path) {
-                struct stat st;
-
-                free(path);
-                path = NULL;
-
-                if (root_dir)
-                        asprintf(&path, "%s/%s/%s", root_dir, *i, name);
-                else
-                        asprintf(&path, "%s/%s", *i, name);
-
-                if (!path) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (lstat(path, &st) < 0) {
-                        r = -errno;
-                        if (errno == ENOENT)
-                                continue;
-
-                        goto finish;
-                }
-
-                if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
-                        r = -ENOENT;
-                        goto finish;
-                }
-
-                r = null_or_empty_path(path);
-                if (r < 0 && r != -ENOENT)
-                        goto finish;
-                else if (r > 0) {
-                        state = path_startswith(*i, "/run") ?
-                                UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
-                        r = 0;
-                        goto finish;
-                }
-
-                r = find_symlinks_in_scope(scope, root_dir, name, &state);
-                if (r < 0) {
-                        goto finish;
-                } else if (r > 0) {
-                        r = 0;
-                        goto finish;
-                }
-
-                r = unit_file_can_install(&paths, root_dir, path, true);
-                if (r < 0 && errno != -ENOENT)
-                        goto finish;
-                else if (r > 0) {
-                        state = UNIT_FILE_DISABLED;
-                        r = 0;
-                        goto finish;
-                } else if (r == 0) {
-                        state = UNIT_FILE_STATIC;
-                        r = 0;
-                        goto finish;
-                }
-        }
-
-finish:
-        lookup_paths_free(&paths);
-        free(path);
-
-        return r < 0 ? r : state;
-}
-
-int unit_file_query_preset(UnitFileScope scope, const char *name) {
-        char **files, **i;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(name);
-
-        if (scope == UNIT_FILE_SYSTEM)
-                r = conf_files_list(&files, ".preset",
-                                    "/etc/systemd/system.preset",
-                                    "/usr/local/lib/systemd/system.preset",
-                                    "/usr/lib/systemd/system.preset",
-                                    "/lib/systemd/system.preset",
-                                    NULL);
-        else if (scope == UNIT_FILE_GLOBAL)
-                r = conf_files_list(&files, ".preset",
-                                    "/etc/systemd/user.preset",
-                                    "/usr/local/lib/systemd/user.preset",
-                                    "/usr/lib/systemd/user.preset",
-                                    NULL);
-        else
-                return 1;
-
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(i, files) {
-                FILE *f;
-
-                f = fopen(*i, "re");
-                if (!f) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        r = -errno;
-                        goto finish;
-                }
-
-                for (;;) {
-                        char line[LINE_MAX], *l;
-
-                        if (!fgets(line, sizeof(line), f))
-                                break;
-
-                        l = strstrip(line);
-                        if (!*l)
-                                continue;
-
-                        if (strchr(COMMENTS, *l))
-                                continue;
-
-                        if (first_word(l, "enable")) {
-                                l += 6;
-                                l += strspn(l, WHITESPACE);
-
-                                if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
-                                        r = 1;
-                                        fclose(f);
-                                        goto finish;
-                                }
-                        } else if (first_word(l, "disable")) {
-                                l += 7;
-                                l += strspn(l, WHITESPACE);
-
-                                if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
-                                        r = 0;
-                                        fclose(f);
-                                        goto finish;
-                                }
-                        } else
-                                log_debug("Couldn't parse line '%s'", l);
-                }
-
-                fclose(f);
-        }
-
-        /* Default is "enable" */
-        r = 1;
-
-finish:
-        strv_free(files);
-
-        return r;
-}
-
-int unit_file_preset(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char *files[],
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        LookupPaths paths;
-        InstallContext plus, minus;
-        char **i, *config_path = NULL;
-        Set *remove_symlinks_to = NULL;
-        int r, q;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        zero(paths);
-        zero(plus);
-        zero(minus);
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-
-                if (!unit_name_is_valid_no_type(*i, true)) {
-                        r = -EINVAL;
-                        goto finish;
-                }
-
-                r = unit_file_query_preset(scope, *i);
-                if (r < 0)
-                        goto finish;
-
-                if (r)
-                        r = install_info_add_auto(&plus, *i);
-                else
-                        r = install_info_add_auto(&minus, *i);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
-
-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-        /* Returns number of symlinks that where supposed to be installed. */
-        q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
-        if (r == 0)
-                r = q;
-
-finish:
-        lookup_paths_free(&paths);
-        install_context_done(&plus);
-        install_context_done(&minus);
-        set_free_free(remove_symlinks_to);
-        free(config_path);
-
-        return r;
-}
-
-int unit_file_get_list(
-                UnitFileScope scope,
-                const char *root_dir,
-                Hashmap *h) {
-
-        LookupPaths paths;
-        char **i, *buf = NULL;
-        DIR *d = NULL;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(h);
-
-        zero(paths);
-
-        if (root_dir && scope != UNIT_FILE_SYSTEM)
-                return -EINVAL;
-
-        r = lookup_paths_init_from_scope(&paths, scope);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(i, paths.unit_path) {
-                struct dirent buffer, *de;
-                const char *units_dir;
-
-                free(buf);
-                buf = NULL;
-
-                if (root_dir) {
-                        if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-                        units_dir = buf;
-                } else
-                        units_dir = *i;
-
-                if (d)
-                        closedir(d);
-
-                d = opendir(units_dir);
-                if (!d) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        r = -errno;
-                        goto finish;
-                }
-
-                for (;;) {
-                        UnitFileList *f;
-
-                        r = readdir_r(d, &buffer, &de);
-                        if (r != 0) {
-                                r = -r;
-                                goto finish;
-                        }
-
-                        if (!de)
-                                break;
-
-                        if (ignore_file(de->d_name))
-                                continue;
-
-                        if (!unit_name_is_valid_no_type(de->d_name, true))
-                                continue;
-
-                        if (hashmap_get(h, de->d_name))
-                                continue;
-
-                        r = dirent_ensure_type(d, de);
-                        if (r < 0) {
-                                if (r == -ENOENT)
-                                        continue;
-
-                                goto finish;
-                        }
-
-                        if (de->d_type != DT_LNK && de->d_type != DT_REG)
-                                continue;
-
-                        f = new0(UnitFileList, 1);
-                        if (!f) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        f->path = path_make_absolute(de->d_name, units_dir);
-                        if (!f->path) {
-                                free(f);
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        r = null_or_empty_path(f->path);
-                        if (r < 0 && r != -ENOENT) {
-                                free(f->path);
-                                free(f);
-                                goto finish;
-                        } else if (r > 0) {
-                                f->state =
-                                        path_startswith(*i, "/run") ?
-                                        UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
-                                goto found;
-                        }
-
-                        r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
-                        if (r < 0) {
-                                free(f->path);
-                                free(f);
-                                goto finish;
-                        } else if (r > 0)
-                                goto found;
-
-                        r = unit_file_can_install(&paths, root_dir, f->path, true);
-                        if (r < 0) {
-                                free(f->path);
-                                free(f);
-                                goto finish;
-                        } else if (r > 0) {
-                                f->state = UNIT_FILE_DISABLED;
-                                goto found;
-                        } else {
-                                f->state = UNIT_FILE_STATIC;
-                                goto found;
-                        }
-
-                        free(f->path);
-                        free(f);
-                        continue;
-
-                found:
-                        r = hashmap_put(h, file_name_from_path(f->path), f);
-                        if (r < 0) {
-                                free(f->path);
-                                free(f);
-                                goto finish;
-                        }
-                }
-        }
-
-finish:
-        lookup_paths_free(&paths);
-        free(buf);
-
-        if (d)
-                closedir(d);
-
-        return r;
-}
-
-static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
-        [UNIT_FILE_ENABLED] = "enabled",
-        [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtie",
-        [UNIT_FILE_LINKED] = "linked",
-        [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
-        [UNIT_FILE_MASKED] = "masked",
-        [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
-        [UNIT_FILE_STATIC] = "static",
-        [UNIT_FILE_DISABLED] = "disabled"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
-
-static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
-        [UNIT_FILE_SYMLINK] = "symlink",
-        [UNIT_FILE_UNLINK] = "unlink",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
diff --git a/src/install.h b/src/install.h
deleted file mode 100644
index d365c01..0000000
--- a/src/install.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooinstallhfoo
-#define fooinstallhfoo
-
-/***
-  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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "hashmap.h"
-
-typedef enum UnitFileScope {
-        UNIT_FILE_SYSTEM,
-        UNIT_FILE_GLOBAL,
-        UNIT_FILE_USER,
-        _UNIT_FILE_SCOPE_MAX,
-        _UNIT_FILE_SCOPE_INVALID = -1
-} UnitFileScope;
-
-typedef enum UnitFileState {
-        UNIT_FILE_ENABLED,
-        UNIT_FILE_ENABLED_RUNTIME,
-        UNIT_FILE_LINKED,
-        UNIT_FILE_LINKED_RUNTIME,
-        UNIT_FILE_MASKED,
-        UNIT_FILE_MASKED_RUNTIME,
-        UNIT_FILE_STATIC,
-        UNIT_FILE_DISABLED,
-        _UNIT_FILE_STATE_MAX,
-        _UNIT_FILE_STATE_INVALID = -1
-} UnitFileState;
-
-typedef enum UnitFileChangeType {
-        UNIT_FILE_SYMLINK,
-        UNIT_FILE_UNLINK,
-        _UNIT_FILE_CHANGE_TYPE_MAX,
-        _UNIT_FILE_CHANGE_TYPE_INVALID = -1
-} UnitFileChangeType;
-
-typedef struct UnitFileChange {
-        UnitFileChangeType type;
-        char *path;
-        char *source;
-} UnitFileChange;
-
-typedef struct UnitFileList {
-        char *path;
-        UnitFileState state;
-} UnitFileList;
-
-int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
-int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
-
-UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename);
-
-int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
-
-void unit_file_list_free(Hashmap *h);
-void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
-
-int unit_file_query_preset(UnitFileScope scope, const char *name);
-
-const char *unit_file_state_to_string(UnitFileState s);
-UnitFileState unit_file_state_from_string(const char *s);
-
-const char *unit_file_change_type_to_string(UnitFileChangeType s);
-UnitFileChangeType unit_file_change_type_from_string(const char *s);
-
-#endif
diff --git a/src/logs-show.c b/src/logs-show.c
deleted file mode 100644
index fedb453..0000000
--- a/src/logs-show.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <time.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/poll.h>
-#include <string.h>
-
-#include "logs-show.h"
-#include "log.h"
-#include "util.h"
-
-#define PRINT_THRESHOLD 128
-
-static bool contains_unprintable(const void *p, size_t l) {
-        const char *j;
-
-        for (j = p; j < (const char *) p + l; j++)
-                if (*j < ' ' || *j >= 127)
-                        return true;
-
-        return false;
-}
-
-static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
-        size_t fl, nl;
-        void *buf;
-
-        assert(data);
-        assert(field);
-        assert(target);
-        assert(target_size);
-
-        fl = strlen(field);
-        if (length < fl)
-                return 0;
-
-        if (memcmp(data, field, fl))
-                return 0;
-
-        nl = length - fl;
-        buf = malloc(nl+1);
-        memcpy(buf, (const char*) data + fl, nl);
-        ((char*)buf)[nl] = 0;
-        if (!buf) {
-                log_error("Out of memory");
-                return -ENOMEM;
-        }
-
-        free(*target);
-        *target = buf;
-        *target_size = nl;
-
-        return 1;
-}
-
-static bool shall_print(bool show_all, char *p, size_t l) {
-        if (show_all)
-                return true;
-
-        if (l > PRINT_THRESHOLD)
-                return false;
-
-        if (contains_unprintable(p, l))
-                return false;
-
-        return true;
-}
-
-static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) {
-        int r;
-        const void *data;
-        size_t length;
-        size_t n = 0;
-        char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
-        size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0;
-
-        assert(j);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-
-                r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "_COMM=", &comm, &comm_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "_PID=", &pid, &pid_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
-                if (r < 0)
-                        goto finish;
-                else if (r > 0)
-                        continue;
-
-                r = parse_field(data, length, "MESSAGE=", &message, &message_len);
-                if (r < 0)
-                        goto finish;
-        }
-
-        if (!message) {
-                r = 0;
-                goto finish;
-        }
-
-        if (monotonic_mode) {
-                uint64_t t;
-                sd_id128_t boot_id;
-
-                r = -ENOENT;
-
-                if (monotonic)
-                        r = safe_atou64(monotonic, &t);
-
-                if (r < 0)
-                        r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
-
-                if (r < 0) {
-                        log_error("Failed to get monotonic: %s", strerror(-r));
-                        goto finish;
-                }
-
-                printf("[%5llu.%06llu]",
-                       (unsigned long long) (t / USEC_PER_SEC),
-                       (unsigned long long) (t % USEC_PER_SEC));
-
-                n += 1 + 5 + 1 + 6 + 1;
-
-        } else {
-                char buf[64];
-                uint64_t x;
-                time_t t;
-                struct tm tm;
-
-                r = -ENOENT;
-
-                if (realtime)
-                        r = safe_atou64(realtime, &x);
-
-                if (r < 0)
-                        r = sd_journal_get_realtime_usec(j, &x);
-
-                if (r < 0) {
-                        log_error("Failed to get realtime: %s", strerror(-r));
-                        goto finish;
-                }
-
-                t = (time_t) (x / USEC_PER_SEC);
-                if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
-                        log_error("Failed to format time.");
-                        goto finish;
-                }
-
-                fputs(buf, stdout);
-                n += strlen(buf);
-        }
-
-        if (hostname && shall_print(show_all, hostname, hostname_len)) {
-                printf(" %.*s", (int) hostname_len, hostname);
-                n += hostname_len + 1;
-        }
-
-        if (identifier && shall_print(show_all, identifier, identifier_len)) {
-                printf(" %.*s", (int) identifier_len, identifier);
-                n += identifier_len + 1;
-        } else if (comm && shall_print(show_all, comm, comm_len)) {
-                printf(" %.*s", (int) comm_len, comm);
-                n += comm_len + 1;
-        } else
-                putchar(' ');
-
-        if (pid && shall_print(show_all, pid, pid_len)) {
-                printf("[%.*s]", (int) pid_len, pid);
-                n += pid_len + 2;
-        } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) {
-                printf("[%.*s]", (int) fake_pid_len, fake_pid);
-                n += fake_pid_len + 2;
-        }
-
-        if (show_all)
-                printf(": %.*s\n", (int) message_len, message);
-        else if (contains_unprintable(message, message_len)) {
-                char bytes[FORMAT_BYTES_MAX];
-                printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
-        } else if (message_len + n < n_columns)
-                printf(": %.*s\n", (int) message_len, message);
-        else if (n < n_columns) {
-                char *e;
-
-                e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
-
-                if (!e)
-                        printf(": %.*s\n", (int) message_len, message);
-                else
-                        printf(": %s\n", e);
-
-                free(e);
-        } else
-                fputs("\n", stdout);
-
-        r = 0;
-
-finish:
-        free(hostname);
-        free(identifier);
-        free(comm);
-        free(pid);
-        free(fake_pid);
-        free(message);
-        free(monotonic);
-        free(realtime);
-
-        return r;
-}
-
-static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
-        return output_short(j, line, n_columns, show_all, false);
-}
-
-static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
-        return output_short(j, line, n_columns, show_all, true);
-}
-
-static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
-        const void *data;
-        size_t length;
-        char *cursor;
-        uint64_t realtime;
-        char ts[FORMAT_TIMESTAMP_MAX];
-        int r;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_cursor(j, &cursor);
-        if (r < 0) {
-                log_error("Failed to get cursor: %s", strerror(-r));
-                return r;
-        }
-
-        printf("%s [%s]\n",
-               format_timestamp(ts, sizeof(ts), realtime),
-               cursor);
-
-        free(cursor);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-                if (!show_all && (length > PRINT_THRESHOLD ||
-                                  contains_unprintable(data, length))) {
-                        const char *c;
-                        char bytes[FORMAT_BYTES_MAX];
-
-                        c = memchr(data, '=', length);
-                        if (!c) {
-                                log_error("Invalid field.");
-                                return -EINVAL;
-                        }
-
-                        printf("\t%.*s=[%s blob data]\n",
-                               (int) (c - (const char*) data),
-                               (const char*) data,
-                               format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
-                } else
-                        printf("\t%.*s\n", (int) length, (const char*) data);
-        }
-
-        return 0;
-}
-
-static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
-        sd_id128_t boot_id;
-        char sid[33];
-        int r;
-        usec_t realtime, monotonic;
-        char *cursor;
-        const void *data;
-        size_t length;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
-        if (r < 0) {
-                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_cursor(j, &cursor);
-        if (r < 0) {
-                log_error("Failed to get cursor: %s", strerror(-r));
-                return r;
-        }
-
-        printf("__CURSOR=%s\n"
-               "__REALTIME_TIMESTAMP=%llu\n"
-               "__MONOTONIC_TIMESTAMP=%llu\n"
-               "_BOOT_ID=%s\n",
-               cursor,
-               (unsigned long long) realtime,
-               (unsigned long long) monotonic,
-               sd_id128_to_string(boot_id, sid));
-
-        free(cursor);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-
-                /* We already printed the boot id, from the data in
-                 * the header, hence let's suppress it here */
-                if (length >= 9 &&
-                    memcmp(data, "_BOOT_ID=", 9) == 0)
-                        continue;
-
-                if (contains_unprintable(data, length)) {
-                        const char *c;
-                        uint64_t le64;
-
-                        c = memchr(data, '=', length);
-                        if (!c) {
-                                log_error("Invalid field.");
-                                return -EINVAL;
-                        }
-
-                        fwrite(data, c - (const char*) data, 1, stdout);
-                        fputc('\n', stdout);
-                        le64 = htole64(length - (c - (const char*) data) - 1);
-                        fwrite(&le64, sizeof(le64), 1, stdout);
-                        fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
-                } else
-                        fwrite(data, length, 1, stdout);
-
-                fputc('\n', stdout);
-        }
-
-        fputc('\n', stdout);
-
-        return 0;
-}
-
-static void json_escape(const char* p, size_t l) {
-
-        if (contains_unprintable(p, l)) {
-                bool not_first = false;
-
-                fputs("[ ", stdout);
-
-                while (l > 0) {
-                        if (not_first)
-                                printf(", %u", (uint8_t) *p);
-                        else {
-                                not_first = true;
-                                printf("%u", (uint8_t) *p);
-                        }
-
-                        p++;
-                        l--;
-                }
-
-                fputs(" ]", stdout);
-        } else {
-                fputc('\"', stdout);
-
-                while (l > 0) {
-                        if (*p == '"' || *p == '\\') {
-                                fputc('\\', stdout);
-                                fputc(*p, stdout);
-                        } else
-                                fputc(*p, stdout);
-
-                        p++;
-                        l--;
-                }
-
-                fputc('\"', stdout);
-        }
-}
-
-static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
-        uint64_t realtime, monotonic;
-        char *cursor;
-        const void *data;
-        size_t length;
-        sd_id128_t boot_id;
-        char sid[33];
-        int r;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
-        if (r < 0) {
-                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_cursor(j, &cursor);
-        if (r < 0) {
-                log_error("Failed to get cursor: %s", strerror(-r));
-                return r;
-        }
-
-        if (line == 1)
-                fputc('\n', stdout);
-        else
-                fputs(",\n", stdout);
-
-        printf("{\n"
-               "\t\"__CURSOR\" : \"%s\",\n"
-               "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
-               "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
-               "\t\"_BOOT_ID\" : \"%s\"",
-               cursor,
-               (unsigned long long) realtime,
-               (unsigned long long) monotonic,
-               sd_id128_to_string(boot_id, sid));
-
-        free(cursor);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-                const char *c;
-
-                /* We already printed the boot id, from the data in
-                 * the header, hence let's suppress it here */
-                if (length >= 9 &&
-                    memcmp(data, "_BOOT_ID=", 9) == 0)
-                        continue;
-
-                c = memchr(data, '=', length);
-                if (!c) {
-                        log_error("Invalid field.");
-                        return -EINVAL;
-                }
-
-                fputs(",\n\t", stdout);
-                json_escape(data, c - (const char*) data);
-                fputs(" : ", stdout);
-                json_escape(c + 1, length - (c - (const char*) data) - 1);
-        }
-
-        fputs("\n}", stdout);
-        fflush(stdout);
-
-        return 0;
-}
-
-static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
-        const void *data;
-        size_t l;
-        int r;
-
-        assert(j);
-
-        r = sd_journal_get_data(j, "MESSAGE", &data, &l);
-        if (r < 0) {
-                log_error("Failed to get data: %s", strerror(-r));
-                return r;
-        }
-
-        assert(l >= 8);
-
-        fwrite((const char*) data + 8, 1, l - 8, stdout);
-        putchar('\n');
-
-        return 0;
-}
-
-static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = {
-        [OUTPUT_SHORT] = output_short_realtime,
-        [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
-        [OUTPUT_VERBOSE] = output_verbose,
-        [OUTPUT_EXPORT] = output_export,
-        [OUTPUT_JSON] = output_json,
-        [OUTPUT_CAT] = output_cat
-};
-
-int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) {
-        assert(mode >= 0);
-        assert(mode < _OUTPUT_MODE_MAX);
-
-        if (n_columns <= 0)
-                n_columns = columns();
-
-        return output_funcs[mode](j, line, n_columns, show_all);
-}
-
-int show_journal_by_unit(
-                const char *unit,
-                OutputMode mode,
-                unsigned n_columns,
-                usec_t not_before,
-                unsigned how_many,
-                bool show_all,
-                bool follow) {
-
-        char *m = NULL;
-        sd_journal *j;
-        int r;
-        int fd;
-        unsigned line = 0;
-        bool need_seek = false;
-
-        assert(mode >= 0);
-        assert(mode < _OUTPUT_MODE_MAX);
-        assert(unit);
-
-        if (!endswith(unit, ".service") &&
-            !endswith(unit, ".socket") &&
-            !endswith(unit, ".mount") &&
-            !endswith(unit, ".swap"))
-                return 0;
-
-        if (how_many <= 0)
-                return 0;
-
-        if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
-        if (r < 0)
-                goto finish;
-
-        fd = sd_journal_get_fd(j);
-        if (fd < 0)
-                goto finish;
-
-        r = sd_journal_add_match(j, m, strlen(m));
-        if (r < 0)
-                goto finish;
-
-        r = sd_journal_seek_tail(j);
-        if (r < 0)
-                goto finish;
-
-        r = sd_journal_previous_skip(j, how_many);
-        if (r < 0)
-                goto finish;
-
-        if (mode == OUTPUT_JSON) {
-                fputc('[', stdout);
-                fflush(stdout);
-        }
-
-        for (;;) {
-                for (;;) {
-                        usec_t usec;
-
-                        if (need_seek) {
-                                r = sd_journal_next(j);
-                                if (r < 0)
-                                        goto finish;
-                        }
-
-                        if (r == 0)
-                                break;
-
-                        need_seek = true;
-
-                        if (not_before > 0) {
-                                r = sd_journal_get_monotonic_usec(j, &usec, NULL);
-
-                                /* -ESTALE is returned if the
-                                   timestamp is not from this boot */
-                                if (r == -ESTALE)
-                                        continue;
-                                else if (r < 0)
-                                        goto finish;
-
-                                if (usec < not_before)
-                                        continue;
-                        }
-
-                        line ++;
-
-                        r = output_journal(j, mode, line, n_columns, show_all);
-                        if (r < 0)
-                                goto finish;
-                }
-
-                if (!follow)
-                        break;
-
-                r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
-                if (r < 0)
-                        goto finish;
-
-                r = sd_journal_process(j);
-                if (r < 0)
-                        goto finish;
-
-        }
-
-        if (mode == OUTPUT_JSON)
-                fputs("\n]\n", stdout);
-
-finish:
-        if (m)
-                free(m);
-
-        if (j)
-                sd_journal_close(j);
-
-        return r;
-}
-
-static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
-        [OUTPUT_SHORT] = "short",
-        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
-        [OUTPUT_VERBOSE] = "verbose",
-        [OUTPUT_EXPORT] = "export",
-        [OUTPUT_JSON] = "json",
-        [OUTPUT_CAT] = "cat"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
diff --git a/src/logs-show.h b/src/logs-show.h
deleted file mode 100644
index 94caed5..0000000
--- a/src/logs-show.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologsshowhfoo
-#define foologsshowhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#include <systemd/sd-journal.h>
-
-#include "util.h"
-
-typedef enum OutputMode {
-        OUTPUT_SHORT,
-        OUTPUT_SHORT_MONOTONIC,
-        OUTPUT_VERBOSE,
-        OUTPUT_EXPORT,
-        OUTPUT_JSON,
-        OUTPUT_CAT,
-        _OUTPUT_MODE_MAX,
-        _OUTPUT_MODE_INVALID = -1
-} OutputMode;
-
-int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all);
-
-int show_journal_by_unit(
-                const char *unit,
-                OutputMode mode,
-                unsigned n_columns,
-                usec_t not_before,
-                unsigned how_many,
-                bool show_all,
-                bool follow);
-
-const char* output_mode_to_string(OutputMode m);
-OutputMode output_mode_from_string(const char *s);
-
-#endif
diff --git a/src/loopback-setup.c b/src/loopback-setup.c
deleted file mode 100644
index 46c1fc8..0000000
--- a/src/loopback-setup.c
+++ /dev/null
@@ -1,274 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <asm/types.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#include "util.h"
-#include "macro.h"
-#include "loopback-setup.h"
-#include "socket-util.h"
-
-#define NLMSG_TAIL(nmsg)                                                \
-        ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
-
-static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) {
-        size_t length;
-        struct rtattr *rta;
-
-        length = RTA_LENGTH(data_length);
-
-        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
-                return -E2BIG;
-
-        rta = NLMSG_TAIL(n);
-        rta->rta_type = type;
-        rta->rta_len = length;
-        memcpy(RTA_DATA(rta), data, data_length);
-        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
-
-        return 0;
-}
-
-static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) {
-
-        for (;;) {
-                ssize_t l;
-
-                if ((l = sendto(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
-                        return l;
-
-                if (errno != EINTR)
-                        return -errno;
-        }
-}
-
-static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) {
-
-        for (;;) {
-                ssize_t l;
-
-                if ((l = recvfrom(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
-                        return l;
-
-                if (errno != EINTR)
-                        return -errno;
-        }
-}
-
-static int add_adresses(int fd, int if_loopback, unsigned *requests) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sa;
-        union {
-                struct nlmsghdr header;
-                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
-                            NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
-                            RTA_LENGTH(sizeof(struct in6_addr))];
-        } request;
-
-        struct ifaddrmsg *ifaddrmsg;
-        uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
-        int r;
-
-        zero(request);
-
-        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-        request.header.nlmsg_type = RTM_NEWADDR;
-        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
-        request.header.nlmsg_seq = *requests + 1;
-
-        ifaddrmsg = NLMSG_DATA(&request.header);
-        ifaddrmsg->ifa_family = AF_INET;
-        ifaddrmsg->ifa_prefixlen = 8;
-        ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
-        ifaddrmsg->ifa_scope = RT_SCOPE_HOST;
-        ifaddrmsg->ifa_index = if_loopback;
-
-        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address))) < 0)
-                return r;
-
-        zero(sa);
-        sa.nl.nl_family = AF_NETLINK;
-
-        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
-                return -errno;
-        (*requests)++;
-
-        if (!socket_ipv6_is_supported())
-                return 0;
-
-        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-        request.header.nlmsg_seq = *requests + 1;
-
-        ifaddrmsg->ifa_family = AF_INET6;
-        ifaddrmsg->ifa_prefixlen = 128;
-
-        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback))) < 0)
-                return r;
-
-        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
-                return -errno;
-        (*requests)++;
-
-        return 0;
-}
-
-static int start_interface(int fd, int if_loopback, unsigned *requests) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sa;
-        union {
-                struct nlmsghdr header;
-                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
-                            NLMSG_ALIGN(sizeof(struct ifinfomsg))];
-        } request;
-
-        struct ifinfomsg *ifinfomsg;
-
-        zero(request);
-
-        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-        request.header.nlmsg_type = RTM_NEWLINK;
-        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
-        request.header.nlmsg_seq = *requests + 1;
-
-        ifinfomsg = NLMSG_DATA(&request.header);
-        ifinfomsg->ifi_family = AF_UNSPEC;
-        ifinfomsg->ifi_index = if_loopback;
-        ifinfomsg->ifi_flags = IFF_UP;
-        ifinfomsg->ifi_change = IFF_UP;
-
-        zero(sa);
-        sa.nl.nl_family = AF_NETLINK;
-
-        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
-                return -errno;
-
-        (*requests)++;
-
-        return 0;
-}
-
-static int read_response(int fd, unsigned requests_max) {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-        } sa;
-        union {
-                struct nlmsghdr header;
-                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
-                            NLMSG_ALIGN(sizeof(struct nlmsgerr))];
-        } response;
-
-        ssize_t l;
-        socklen_t sa_len = sizeof(sa);
-        struct nlmsgerr *nlmsgerr;
-
-        if ((l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len)) < 0)
-                return -errno;
-
-        if (sa_len != sizeof(sa.nl) ||
-            sa.nl.nl_family != AF_NETLINK)
-                return -EIO;
-
-        if (sa.nl.nl_pid != 0)
-                return 0;
-
-        if ((size_t) l < sizeof(struct nlmsghdr))
-                return -EIO;
-
-        if (response.header.nlmsg_type != NLMSG_ERROR ||
-            (pid_t) response.header.nlmsg_pid != getpid() ||
-            response.header.nlmsg_seq >= requests_max)
-                return 0;
-
-        if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
-            response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
-                return -EIO;
-
-        nlmsgerr = NLMSG_DATA(&response.header);
-
-        if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST) {
-                log_warning("Netlink failure for request %i: %s", response.header.nlmsg_seq, strerror(-nlmsgerr->error));
-                return nlmsgerr->error;
-        }
-
-        return response.header.nlmsg_seq;
-}
-
-int loopback_setup(void) {
-        int r, if_loopback;
-        union {
-                struct sockaddr sa;
-                struct sockaddr_nl nl;
-                struct sockaddr_storage storage;
-        } sa;
-        unsigned requests = 0, i;
-        int fd;
-
-        errno = 0;
-        if ((if_loopback = (int) if_nametoindex("lo")) <= 0)
-                return errno ? -errno : -ENODEV;
-
-        if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
-                return -errno;
-
-        zero(sa);
-        sa.nl.nl_family = AF_NETLINK;
-
-        if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if ((r = add_adresses(fd, if_loopback, &requests)) < 0)
-                goto finish;
-
-        if ((r = start_interface(fd, if_loopback, &requests)) < 0)
-                goto finish;
-
-        for (i = 0; i < requests; i++) {
-                if ((r = read_response(fd, requests)) < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        if (r < 0)
-                log_warning("Failed to configure loopback device: %s", strerror(-r));
-
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
diff --git a/src/loopback-setup.h b/src/loopback-setup.h
deleted file mode 100644
index cbb969e..0000000
--- a/src/loopback-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooloopbacksetuphfoo
-#define fooloopbacksetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int loopback_setup(void);
-
-#endif
diff --git a/src/machine-id-setup.c b/src/machine-id-setup.c
deleted file mode 100644
index 9e84ac0..0000000
--- a/src/machine-id-setup.c
+++ /dev/null
@@ -1,265 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/mount.h>
-
-#include <systemd/sd-id128.h>
-
-#include "machine-id-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "mkdir.h"
-#include "log.h"
-#include "virt.h"
-
-static int shorten_uuid(char destination[36], const char *source) {
-        unsigned i, j;
-
-        for (i = 0, j = 0; i < 36 && j < 32; i++) {
-                int t;
-
-                t = unhexchar(source[i]);
-                if (t < 0)
-                        continue;
-
-                destination[j++] = hexchar(t);
-        }
-
-        if (i == 36 && j == 32) {
-                destination[32] = '\n';
-                destination[33] = 0;
-                return 0;
-        }
-
-        return -EINVAL;
-}
-
-static int generate(char id[34]) {
-        int fd, r;
-        unsigned char *p;
-        sd_id128_t buf;
-        char *q;
-        ssize_t k;
-        const char *vm_id;
-
-        assert(id);
-
-        /* First, try reading the D-Bus machine id, unless it is a symlink */
-        fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
-        if (fd >= 0) {
-
-                k = loop_read(fd, id, 32, false);
-                close_nointr_nofail(fd);
-
-                if (k >= 32) {
-                        id[32] = '\n';
-                        id[33] = 0;
-
-                        log_info("Initializing machine ID from D-Bus machine ID.");
-                        return 0;
-                }
-        }
-
-        /* If that didn't work, see if we are running in qemu/kvm and a
-         * machine ID was passed in via -uuid on the qemu/kvm command
-         * line */
-
-        r = detect_vm(&vm_id);
-        if (r > 0 && streq(vm_id, "kvm")) {
-                char uuid[37];
-
-                fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
-                if (fd >= 0) {
-                        k = loop_read(fd, uuid, 36, false);
-                        close_nointr_nofail(fd);
-
-                        if (k >= 36) {
-                                r = shorten_uuid(id, uuid);
-                                if (r >= 0) {
-                                        log_info("Initializing machine ID from KVM UUID");
-                                        return 0;
-                                }
-                        }
-                }
-        }
-
-        /* If that didn't work either, see if we are running in a
-         * container, and a machine ID was passed in via
-         * $container_uuid the way libvirt/LXC does it */
-
-        r = detect_container(NULL);
-        if (r > 0) {
-                FILE *f;
-
-                f = fopen("/proc/1/environ", "re");
-                if (f) {
-                        bool done = false;
-
-                        do {
-                                char line[LINE_MAX];
-                                unsigned i;
-
-                                for (i = 0; i < sizeof(line)-1; i++) {
-                                        int c;
-
-                                        c = getc(f);
-                                        if (_unlikely_(c == EOF)) {
-                                                done = true;
-                                                break;
-                                        } else if (c == 0)
-                                                break;
-
-                                        line[i] = c;
-                                }
-                                line[i] = 0;
-
-                                if (startswith(line, "container_uuid=") &&
-                                    strlen(line + 15) >= 36) {
-                                        r = shorten_uuid(id, line + 15);
-                                        if (r >= 0) {
-                                                log_info("Initializing machine ID from container UUID");
-                                                return 0;
-                                        }
-                                }
-
-                        } while (!done);
-
-                        fclose(f);
-                }
-        }
-
-        /* If that didn't work, generate a random machine id */
-        r = sd_id128_randomize(&buf);
-        if (r < 0) {
-                log_error("Failed to open /dev/urandom: %s", strerror(-r));
-                return r;
-        }
-
-        for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
-                q[0] = hexchar(*p >> 4);
-                q[1] = hexchar(*p & 15);
-        }
-
-        id[32] = '\n';
-        id[33] = 0;
-
-        log_info("Initializing machine ID from random generator.");
-
-        return 0;
-}
-
-int machine_id_setup(void) {
-        int fd, r;
-        bool writable;
-        struct stat st;
-        char id[34]; /* 32 + \n + \0 */
-        mode_t m;
-
-        m = umask(0000);
-
-        /* We create this 0444, to indicate that this isn't really
-         * something you should ever modify. Of course, since the file
-         * will be owned by root it doesn't matter much, but maybe
-         * people look. */
-
-        fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
-        if (fd >= 0)
-                writable = true;
-        else {
-                fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0) {
-                        umask(m);
-                        log_error("Cannot open /etc/machine-id: %m");
-                        return -errno;
-                }
-
-                writable = false;
-        }
-
-        umask(m);
-
-        if (fstat(fd, &st) < 0) {
-                log_error("fstat() failed: %m");
-                r = -errno;
-                goto finish;
-        }
-
-        if (S_ISREG(st.st_mode)) {
-                if (loop_read(fd, id, 32, false) >= 32) {
-                        r = 0;
-                        goto finish;
-                }
-        }
-
-        /* Hmm, so, the id currently stored is not useful, then let's
-         * generate one */
-
-        r = generate(id);
-        if (r < 0)
-                goto finish;
-
-        if (S_ISREG(st.st_mode) && writable) {
-                lseek(fd, 0, SEEK_SET);
-
-                if (loop_write(fd, id, 33, false) == 33) {
-                        r = 0;
-                        goto finish;
-                }
-        }
-
-        close_nointr_nofail(fd);
-        fd = -1;
-
-        /* Hmm, we couldn't write it? So let's write it to
-         * /run/machine-id as a replacement */
-
-        m = umask(0022);
-        r = write_one_line_file("/run/machine-id", id);
-        umask(m);
-
-        if (r < 0) {
-                log_error("Cannot write /run/machine-id: %s", strerror(-r));
-
-                unlink("/run/machine-id");
-                goto finish;
-        }
-
-        /* And now, let's mount it over */
-        r = mount("/run/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
-        if (r < 0) {
-                unlink("/run/machine-id");
-                log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
-        } else
-                log_info("Installed transient /etc/machine-id file.");
-
-finish:
-
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
diff --git a/src/machine-id-setup.h b/src/machine-id-setup.h
deleted file mode 100644
index 16f45d8..0000000
--- a/src/machine-id-setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foomachineidsetuphfoo
-#define foomachineidsetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int machine_id_setup(void);
-
-#endif
diff --git a/src/mount-setup.c b/src/mount-setup.c
deleted file mode 100644
index 52fe523..0000000
--- a/src/mount-setup.c
+++ /dev/null
@@ -1,423 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/mount.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libgen.h>
-#include <assert.h>
-#include <unistd.h>
-#include <ftw.h>
-
-#include "mount-setup.h"
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "label.h"
-#include "set.h"
-#include "strv.h"
-#include "mkdir.h"
-
-#ifndef TTY_GID
-#define TTY_GID 5
-#endif
-
-typedef struct MountPoint {
-        const char *what;
-        const char *where;
-        const char *type;
-        const char *options;
-        unsigned long flags;
-        bool fatal;
-} MountPoint;
-
-/* The first three entries we might need before SELinux is up. The
- * fourth (securityfs) is needed by IMA to load a custom policy. The
- * other ones we can delay until SELinux and IMA are loaded. */
-#define N_EARLY_MOUNT 4
-
-static const MountPoint mount_table[] = {
-        { "proc",     "/proc",                  "proc",     NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "sysfs",    "/sys",                   "sysfs",    NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "devtmpfs", "/dev",                   "devtmpfs", "mode=755",          MS_NOSUID|MS_STRICTATIME,     true },
-        { "securityfs", "/sys/kernel/security", "securityfs", NULL,              MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-        { "tmpfs",    "/dev/shm",               "tmpfs",    "mode=1777",         MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
-        { "devpts",   "/dev/pts",               "devpts",   "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false },
-        { "tmpfs",    "/run",                   "tmpfs",    "mode=755",          MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
-        { "tmpfs",    "/sys/fs/cgroup",         "tmpfs",    "mode=755",          MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, false },
-        { "cgroup",   "/sys/fs/cgroup/systemd", "cgroup",   "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-};
-
-/* These are API file systems that might be mounted by other software,
- * we just list them here so that we know that we should ignore them */
-
-static const char * const ignore_paths[] = {
-        "/sys/fs/selinux",
-        "/selinux",
-        "/proc/bus/usb"
-};
-
-bool mount_point_is_api(const char *path) {
-        unsigned i;
-
-        /* Checks if this mount point is considered "API", and hence
-         * should be ignored */
-
-        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
-                if (path_equal(path, mount_table[i].where))
-                        return true;
-
-        return path_startswith(path, "/sys/fs/cgroup/");
-}
-
-bool mount_point_ignore(const char *path) {
-        unsigned i;
-
-        for (i = 0; i < ELEMENTSOF(ignore_paths); i++)
-                if (path_equal(path, ignore_paths[i]))
-                        return true;
-
-        return false;
-}
-
-static int mount_one(const MountPoint *p, bool relabel) {
-        int r;
-
-        assert(p);
-
-        /* Relabel first, just in case */
-        if (relabel)
-                label_fix(p->where, true);
-
-        if ((r = path_is_mount_point(p->where, true)) < 0)
-                return r;
-
-        if (r > 0)
-                return 0;
-
-        /* The access mode here doesn't really matter too much, since
-         * the mounted file system will take precedence anyway. */
-        mkdir_p(p->where, 0755);
-
-        log_debug("Mounting %s to %s of type %s with options %s.",
-                  p->what,
-                  p->where,
-                  p->type,
-                  strna(p->options));
-
-        if (mount(p->what,
-                  p->where,
-                  p->type,
-                  p->flags,
-                  p->options) < 0) {
-                log_error("Failed to mount %s: %s", p->where, strerror(errno));
-                return p->fatal ? -errno : 0;
-        }
-
-        /* Relabel again, since we now mounted something fresh here */
-        if (relabel)
-                label_fix(p->where, false);
-
-        return 1;
-}
-
-int mount_setup_early(void) {
-        unsigned i;
-        int r = 0;
-
-        assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
-
-        /* Do a minimal mount of /proc and friends to enable the most
-         * basic stuff, such as SELinux */
-        for (i = 0; i < N_EARLY_MOUNT; i ++)  {
-                int j;
-
-                j = mount_one(mount_table + i, false);
-                if (r == 0)
-                        r = j;
-        }
-
-        return r;
-}
-
-int mount_cgroup_controllers(char ***join_controllers) {
-        int r;
-        FILE *f;
-        char buf[LINE_MAX];
-        Set *controllers;
-
-        /* Mount all available cgroup controllers that are built into the kernel. */
-
-        f = fopen("/proc/cgroups", "re");
-        if (!f) {
-                log_error("Failed to enumerate cgroup controllers: %m");
-                return 0;
-        }
-
-        controllers = set_new(string_hash_func, string_compare_func);
-        if (!controllers) {
-                r = -ENOMEM;
-                log_error("Failed to allocate controller set.");
-                goto finish;
-        }
-
-        /* Ignore the header line */
-        (void) fgets(buf, sizeof(buf), f);
-
-        for (;;) {
-                char *controller;
-                int enabled = 0;
-
-                if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
-
-                        if (feof(f))
-                                break;
-
-                        log_error("Failed to parse /proc/cgroups.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                if (!enabled) {
-                        free(controller);
-                        continue;
-                }
-
-                r = set_put(controllers, controller);
-                if (r < 0) {
-                        log_error("Failed to add controller to set.");
-                        free(controller);
-                        goto finish;
-                }
-        }
-
-        for (;;) {
-                MountPoint p;
-                char *controller, *where, *options;
-                char ***k = NULL;
-
-                controller = set_steal_first(controllers);
-                if (!controller)
-                        break;
-
-                if (join_controllers)
-                        for (k = join_controllers; *k; k++)
-                                if (strv_find(*k, controller))
-                                        break;
-
-                if (k && *k) {
-                        char **i, **j;
-
-                        for (i = *k, j = *k; *i; i++) {
-
-                                if (!streq(*i, controller)) {
-                                        char *t;
-
-                                        t = set_remove(controllers, *i);
-                                        if (!t) {
-                                                free(*i);
-                                                continue;
-                                        }
-                                        free(t);
-                                }
-
-                                *(j++) = *i;
-                        }
-
-                        *j = NULL;
-
-                        options = strv_join(*k, ",");
-                        if (!options) {
-                                log_error("Failed to join options");
-                                free(controller);
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                } else {
-                        options = controller;
-                        controller = NULL;
-                }
-
-                where = strappend("/sys/fs/cgroup/", options);
-                if (!where) {
-                        log_error("Failed to build path");
-                        free(options);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                zero(p);
-                p.what = "cgroup";
-                p.where = where;
-                p.type = "cgroup";
-                p.options = options;
-                p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
-                p.fatal = false;
-
-                r = mount_one(&p, true);
-                free(controller);
-                free(where);
-
-                if (r < 0) {
-                        free(options);
-                        goto finish;
-                }
-
-                if (r > 0 && k && *k) {
-                        char **i;
-
-                        for (i = *k; *i; i++) {
-                                char *t;
-
-                                t = strappend("/sys/fs/cgroup/", *i);
-                                if (!t) {
-                                        log_error("Failed to build path");
-                                        r = -ENOMEM;
-                                        free(options);
-                                        goto finish;
-                                }
-
-                                r = symlink(options, t);
-                                free(t);
-
-                                if (r < 0 && errno != EEXIST) {
-                                        log_error("Failed to create symlink: %m");
-                                        r = -errno;
-                                        free(options);
-                                        goto finish;
-                                }
-                        }
-                }
-
-                free(options);
-        }
-
-        r = 0;
-
-finish:
-        set_free_free(controllers);
-
-        fclose(f);
-
-        return r;
-}
-
-static int symlink_and_label(const char *old_path, const char *new_path) {
-        int r;
-
-        assert(old_path);
-        assert(new_path);
-
-        if ((r = label_symlinkfile_set(new_path)) < 0)
-                return r;
-
-        if (symlink(old_path, new_path) < 0)
-                r = -errno;
-
-        label_file_clear();
-
-        return r;
-}
-
-static int nftw_cb(
-                const char *fpath,
-                const struct stat *sb,
-                int tflag,
-                struct FTW *ftwbuf) {
-
-        /* No need to label /dev twice in a row... */
-        if (_unlikely_(ftwbuf->level == 0))
-                return FTW_CONTINUE;
-
-        label_fix(fpath, true);
-
-        /* /run/initramfs is static data and big, no need to
-         * dynamically relabel its contents at boot... */
-        if (_unlikely_(ftwbuf->level == 1 &&
-                      tflag == FTW_D &&
-                      streq(fpath, "/run/initramfs")))
-                return FTW_SKIP_SUBTREE;
-
-        return FTW_CONTINUE;
-};
-
-int mount_setup(bool loaded_policy) {
-
-        static const char symlinks[] =
-                "/proc/kcore\0"      "/dev/core\0"
-                "/proc/self/fd\0"    "/dev/fd\0"
-                "/proc/self/fd/0\0"  "/dev/stdin\0"
-                "/proc/self/fd/1\0"  "/dev/stdout\0"
-                "/proc/self/fd/2\0"  "/dev/stderr\0";
-
-        static const char relabel[] =
-                "/run/initramfs/root-fsck\0"
-                "/run/initramfs/shutdown\0";
-
-        int r;
-        unsigned i;
-        const char *j, *k;
-
-        for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
-                r = mount_one(mount_table + i, true);
-
-                if (r < 0)
-                        return r;
-        }
-
-        /* Nodes in devtmpfs and /run need to be manually updated for
-         * the appropriate labels, after mounting. The other virtual
-         * API file systems like /sys and /proc do not need that, they
-         * use the same label for all their files. */
-        if (loaded_policy) {
-                usec_t before_relabel, after_relabel;
-                char timespan[FORMAT_TIMESPAN_MAX];
-
-                before_relabel = now(CLOCK_MONOTONIC);
-
-                nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
-                nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
-
-                /* Explicitly relabel these */
-                NULSTR_FOREACH(j, relabel)
-                        label_fix(j, true);
-
-                after_relabel = now(CLOCK_MONOTONIC);
-
-                log_info("Relabelled /dev and /run in %s.",
-                         format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel));
-        }
-
-        /* Create a few default symlinks, which are normally created
-         * by udevd, but some scripts might need them before we start
-         * udevd. */
-        NULSTR_FOREACH_PAIR(j, k, symlinks)
-                symlink_and_label(j, k);
-
-        /* Create a few directories we always want around */
-        label_mkdir("/run/systemd", 0755);
-        label_mkdir("/run/systemd/system", 0755);
-
-        return 0;
-}
diff --git a/src/mount-setup.h b/src/mount-setup.h
deleted file mode 100644
index 720b66f..0000000
--- a/src/mount-setup.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foomountsetuphfoo
-#define foomountsetuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-int mount_setup_early(void);
-
-int mount_setup(bool loaded_policy);
-
-int mount_cgroup_controllers(char ***join_controllers);
-
-bool mount_point_is_api(const char *path);
-bool mount_point_ignore(const char *path);
-
-#endif
diff --git a/src/path-lookup.c b/src/path-lookup.c
deleted file mode 100644
index 1d95f7d..0000000
--- a/src/path-lookup.c
+++ /dev/null
@@ -1,348 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "util.h"
-#include "mkdir.h"
-#include "strv.h"
-
-#include "path-lookup.h"
-
-int user_config_home(char **config_home) {
-        const char *e;
-
-        if ((e = getenv("XDG_CONFIG_HOME"))) {
-                if (asprintf(config_home, "%s/systemd/user", e) < 0)
-                        return -ENOMEM;
-
-                return 1;
-        } else {
-                const char *home;
-
-                if ((home = getenv("HOME"))) {
-                        if (asprintf(config_home, "%s/.config/systemd/user", home) < 0)
-                                return -ENOMEM;
-
-                        return 1;
-                }
-        }
-
-        return 0;
-}
-
-static char** user_dirs(void) {
-        const char * const config_unit_paths[] = {
-                USER_CONFIG_UNIT_PATH,
-                "/etc/systemd/user",
-                "/run/systemd/user",
-                NULL
-        };
-
-        const char * const data_unit_paths[] = {
-                "/usr/local/lib/systemd/user",
-                "/usr/local/share/systemd/user",
-                USER_DATA_UNIT_PATH,
-                "/usr/lib/systemd/user",
-                "/usr/share/systemd/user",
-                NULL
-        };
-
-        const char *home, *e;
-        char *config_home = NULL, *data_home = NULL;
-        char **config_dirs = NULL, **data_dirs = NULL;
-        char **r = NULL, **t;
-
-        /* Implement the mechanisms defined in
-         *
-         * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
-         *
-         * We look in both the config and the data dirs because we
-         * want to encourage that distributors ship their unit files
-         * as data, and allow overriding as configuration.
-         */
-
-        if (user_config_home(&config_home) < 0)
-                goto fail;
-
-        home = getenv("HOME");
-
-        if ((e = getenv("XDG_CONFIG_DIRS")))
-                if (!(config_dirs = strv_split(e, ":")))
-                        goto fail;
-
-        /* We don't treat /etc/xdg/systemd here as the spec
-         * suggests because we assume that that is a link to
-         * /etc/systemd/ anyway. */
-
-        if ((e = getenv("XDG_DATA_HOME"))) {
-                if (asprintf(&data_home, "%s/systemd/user", e) < 0)
-                        goto fail;
-
-        } else if (home) {
-                if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
-                        goto fail;
-
-                /* There is really no need for two unit dirs in $HOME,
-                 * except to be fully compliant with the XDG spec. We
-                 * now try to link the two dirs, so that we can
-                 * minimize disk seeks a little. Further down we'll
-                 * then filter out this link, if it is actually is
-                 * one. */
-
-                mkdir_parents(data_home, 0777);
-                (void) symlink("../../../.config/systemd/user", data_home);
-        }
-
-        if ((e = getenv("XDG_DATA_DIRS")))
-                data_dirs = strv_split(e, ":");
-        else
-                data_dirs = strv_new("/usr/local/share",
-                                     "/usr/share",
-                                     NULL);
-
-        if (!data_dirs)
-                goto fail;
-
-        /* Now merge everything we found. */
-        if (config_home) {
-                if (!(t = strv_append(r, config_home)))
-                        goto fail;
-                strv_free(r);
-                r = t;
-        }
-
-        if (!strv_isempty(config_dirs)) {
-                if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user")))
-                        goto finish;
-                strv_free(r);
-                r = t;
-        }
-
-        if (!(t = strv_merge(r, (char**) config_unit_paths)))
-                goto fail;
-        strv_free(r);
-        r = t;
-
-        if (data_home) {
-                if (!(t = strv_append(r, data_home)))
-                        goto fail;
-                strv_free(r);
-                r = t;
-        }
-
-        if (!strv_isempty(data_dirs)) {
-                if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user")))
-                        goto fail;
-                strv_free(r);
-                r = t;
-        }
-
-        if (!(t = strv_merge(r, (char**) data_unit_paths)))
-                goto fail;
-        strv_free(r);
-        r = t;
-
-        if (!strv_path_make_absolute_cwd(r))
-            goto fail;
-
-finish:
-        free(config_home);
-        strv_free(config_dirs);
-        free(data_home);
-        strv_free(data_dirs);
-
-        return r;
-
-fail:
-        strv_free(r);
-        r = NULL;
-        goto finish;
-}
-
-int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) {
-        const char *e;
-        char *t;
-
-        assert(p);
-
-        /* First priority is whatever has been passed to us via env
-         * vars */
-        if ((e = getenv("SYSTEMD_UNIT_PATH")))
-                if (!(p->unit_path = split_path_and_make_absolute(e)))
-                        return -ENOMEM;
-
-        if (strv_isempty(p->unit_path)) {
-
-                /* Nothing is set, so let's figure something out. */
-                strv_free(p->unit_path);
-
-                if (running_as == MANAGER_USER) {
-
-                        if (personal)
-                                p->unit_path = user_dirs();
-                        else
-                                p->unit_path = strv_new(
-                                                /* If you modify this you also want to modify
-                                                 * systemduserunitpath= in systemd.pc.in, and
-                                                 * the arrays in user_dirs() above! */
-                                                USER_CONFIG_UNIT_PATH,
-                                                "/etc/systemd/user",
-                                                "/run/systemd/user",
-                                                "/usr/local/lib/systemd/user",
-                                                "/usr/local/share/systemd/user",
-                                                USER_DATA_UNIT_PATH,
-                                                "/usr/lib/systemd/user",
-                                                "/usr/share/systemd/user",
-                                                NULL);
-
-                        if (!p->unit_path)
-                                return -ENOMEM;
-
-                } else
-                        if (!(p->unit_path = strv_new(
-                                              /* If you modify this you also want to modify
-                                               * systemdsystemunitpath= in systemd.pc.in! */
-                                              SYSTEM_CONFIG_UNIT_PATH,
-                                              "/etc/systemd/system",
-                                              "/run/systemd/system",
-                                              "/usr/local/lib/systemd/system",
-                                              SYSTEM_DATA_UNIT_PATH,
-                                              "/usr/lib/systemd/system",
-#ifdef HAVE_SPLIT_USR
-                                              "/lib/systemd/system",
-#endif
-                                              NULL)))
-                                return -ENOMEM;
-        }
-
-        if (p->unit_path)
-                if (!strv_path_canonicalize(p->unit_path))
-                        return -ENOMEM;
-
-        strv_uniq(p->unit_path);
-        strv_path_remove_empty(p->unit_path);
-
-        if (!strv_isempty(p->unit_path)) {
-
-                if (!(t = strv_join(p->unit_path, "\n\t")))
-                        return -ENOMEM;
-                log_debug("Looking for unit files in:\n\t%s", t);
-                free(t);
-        } else {
-                log_debug("Ignoring unit files.");
-                strv_free(p->unit_path);
-                p->unit_path = NULL;
-        }
-
-        if (running_as == MANAGER_SYSTEM) {
-#ifdef HAVE_SYSV_COMPAT
-                /* /etc/init.d/ compatibility does not matter to users */
-
-                if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
-                        if (!(p->sysvinit_path = split_path_and_make_absolute(e)))
-                                return -ENOMEM;
-
-                if (strv_isempty(p->sysvinit_path)) {
-                        strv_free(p->sysvinit_path);
-
-                        if (!(p->sysvinit_path = strv_new(
-                                              SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
-                                              NULL)))
-                                return -ENOMEM;
-                }
-
-                if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
-                        if (!(p->sysvrcnd_path = split_path_and_make_absolute(e)))
-                                return -ENOMEM;
-
-                if (strv_isempty(p->sysvrcnd_path)) {
-                        strv_free(p->sysvrcnd_path);
-
-                        if (!(p->sysvrcnd_path = strv_new(
-                                              SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
-                                              NULL)))
-                                return -ENOMEM;
-                }
-
-                if (p->sysvinit_path)
-                        if (!strv_path_canonicalize(p->sysvinit_path))
-                                return -ENOMEM;
-
-                if (p->sysvrcnd_path)
-                        if (!strv_path_canonicalize(p->sysvrcnd_path))
-                                return -ENOMEM;
-
-                strv_uniq(p->sysvinit_path);
-                strv_uniq(p->sysvrcnd_path);
-
-                strv_path_remove_empty(p->sysvinit_path);
-                strv_path_remove_empty(p->sysvrcnd_path);
-
-                if (!strv_isempty(p->sysvinit_path)) {
-
-                        if (!(t = strv_join(p->sysvinit_path, "\n\t")))
-                                return -ENOMEM;
-
-                        log_debug("Looking for SysV init scripts in:\n\t%s", t);
-                        free(t);
-                } else {
-                        log_debug("Ignoring SysV init scripts.");
-                        strv_free(p->sysvinit_path);
-                        p->sysvinit_path = NULL;
-                }
-
-                if (!strv_isempty(p->sysvrcnd_path)) {
-
-                        if (!(t = strv_join(p->sysvrcnd_path, "\n\t")))
-                                return -ENOMEM;
-
-                        log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
-                        free(t);
-                } else {
-                        log_debug("Ignoring SysV rcN.d links.");
-                        strv_free(p->sysvrcnd_path);
-                        p->sysvrcnd_path = NULL;
-                }
-#else
-                log_debug("Disabled SysV init scripts and rcN.d links support");
-#endif
-        }
-
-        return 0;
-}
-
-void lookup_paths_free(LookupPaths *p) {
-        assert(p);
-
-        strv_free(p->unit_path);
-        p->unit_path = NULL;
-
-#ifdef HAVE_SYSV_COMPAT
-        strv_free(p->sysvinit_path);
-        strv_free(p->sysvrcnd_path);
-        p->sysvinit_path = p->sysvrcnd_path = NULL;
-#endif
-}
diff --git a/src/path-lookup.h b/src/path-lookup.h
deleted file mode 100644
index e8a5a77..0000000
--- a/src/path-lookup.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foopathlookuphfoo
-#define foopathlookuphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct LookupPaths {
-        char **unit_path;
-#ifdef HAVE_SYSV_COMPAT
-        char **sysvinit_path;
-        char **sysvrcnd_path;
-#endif
-} LookupPaths;
-
-#include "manager.h"
-
-int user_config_home(char **config_home);
-
-int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal);
-void lookup_paths_free(LookupPaths *p);
-
-#endif
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
new file mode 100644
index 0000000..550a2f5
--- /dev/null
+++ b/src/shared/cgroup-show.c
@@ -0,0 +1,261 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "util.h"
+#include "macro.h"
+#include "cgroup-util.h"
+#include "cgroup-show.h"
+
+static int compare(const void *a, const void *b) {
+        const pid_t *p = a, *q = b;
+
+        if (*p < *q)
+                return -1;
+        if (*p > *q)
+                return 1;
+        return 0;
+}
+
+static unsigned ilog10(unsigned long ul) {
+        int n = 0;
+
+        while (ul > 0) {
+                n++;
+                ul /= 10;
+        }
+
+        return n;
+}
+
+static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
+        char *fn;
+        FILE *f;
+        size_t n = 0, n_allocated = 0;
+        pid_t *pids = NULL;
+        char *p;
+        pid_t pid, biggest = 0;
+        int r;
+
+        if (n_columns <= 0)
+                n_columns = columns();
+
+        if (!prefix)
+                prefix = "";
+
+        if ((r = cg_fix_path(path, &p)) < 0)
+                return r;
+
+        r = asprintf(&fn, "%s/cgroup.procs", p);
+        free(p);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        f = fopen(fn, "re");
+        free(fn);
+
+        if (!f)
+                return -errno;
+
+        while ((r = cg_read_pid(f, &pid)) > 0) {
+
+                if (!kernel_threads && is_kernel_thread(pid) > 0)
+                        continue;
+
+                if (n >= n_allocated) {
+                        pid_t *npids;
+
+                        n_allocated = MAX(16U, n*2U);
+
+                        if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        pids = npids;
+                }
+
+                assert(n < n_allocated);
+                pids[n++] = pid;
+
+                if (pid > biggest)
+                        biggest = pid;
+        }
+
+        if (r < 0)
+                goto finish;
+
+        if (n > 0) {
+                unsigned i, m;
+
+                /* Filter duplicates */
+                m = 0;
+                for (i = 0; i < n; i++) {
+                        unsigned j;
+
+                        for (j = i+1; j < n; j++)
+                                if (pids[i] == pids[j])
+                                        break;
+
+                        if (j >= n)
+                                pids[m++] = pids[i];
+                }
+                n = m;
+
+                /* And sort */
+                qsort(pids, n, sizeof(pid_t), compare);
+
+                if (n_columns > 8)
+                        n_columns -= 8;
+                else
+                        n_columns = 20;
+
+                for (i = 0; i < n; i++) {
+                        char *t = NULL;
+
+                        get_process_cmdline(pids[i], n_columns, true, &t);
+
+                        printf("%s%s %*lu %s\n",
+                               prefix,
+                               (more || i < n-1) ? "\342\224\234" : "\342\224\224",
+                               (int) ilog10(biggest),
+                               (unsigned long) pids[i],
+                               strna(t));
+
+                        free(t);
+                }
+        }
+
+        r = 0;
+
+finish:
+        free(pids);
+
+        if (f)
+                fclose(f);
+
+        return r;
+}
+
+int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
+        DIR *d;
+        char *last = NULL;
+        char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
+        bool shown_pids = false;
+        int r;
+
+        if (n_columns <= 0)
+                n_columns = columns();
+
+        if (!prefix)
+                prefix = "";
+
+        if ((r = cg_fix_path(path, &fn)) < 0)
+                return r;
+
+        if (!(d = opendir(fn))) {
+                free(fn);
+                return -errno;
+        }
+
+        while ((r = cg_read_subgroup(d, &gn)) > 0) {
+
+                if (!shown_pids) {
+                        show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
+                        shown_pids = true;
+                }
+
+                if (last) {
+                        printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
+
+                        if (!p1)
+                                if (!(p1 = strappend(prefix, "\342\224\202 "))) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                        show_cgroup_by_path(last, p1, n_columns-2, kernel_threads);
+
+                        free(last);
+                        last = NULL;
+                }
+
+                r = asprintf(&last, "%s/%s", fn, gn);
+                free(gn);
+
+                if (r < 0) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+        }
+
+        if (r < 0)
+                goto finish;
+
+        if (!shown_pids)
+                show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads);
+
+        if (last) {
+                printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
+
+                if (!p2)
+                        if (!(p2 = strappend(prefix, "  "))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                show_cgroup_by_path(last, p2, n_columns-2, kernel_threads);
+        }
+
+        r = 0;
+
+finish:
+        free(p1);
+        free(p2);
+        free(last);
+        free(fn);
+
+        closedir(d);
+
+        return r;
+}
+
+int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
+        char *p;
+        int r;
+
+        assert(controller);
+        assert(path);
+
+        r = cg_get_path(controller, path, NULL, &p);
+        if (r < 0)
+                return r;
+
+        r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads);
+        free(p);
+
+        return r;
+}
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
new file mode 100644
index 0000000..5433f46
--- /dev/null
+++ b/src/shared/cgroup-show.h
@@ -0,0 +1,30 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foocgroupshowhfoo
+#define foocgroupshowhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads);
+int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads);
+
+#endif
diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c
new file mode 100644
index 0000000..038fdd4
--- /dev/null
+++ b/src/shared/dbus-common.c
@@ -0,0 +1,1096 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dbus/dbus.h>
+#include <string.h>
+#include <sys/epoll.h>
+
+#include "log.h"
+#include "dbus-common.h"
+#include "util.h"
+#include "def.h"
+#include "strv.h"
+
+int bus_check_peercred(DBusConnection *c) {
+        int fd;
+        struct ucred ucred;
+        socklen_t l;
+
+        assert(c);
+
+        assert_se(dbus_connection_get_unix_fd(c, &fd));
+
+        l = sizeof(struct ucred);
+        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
+                log_error("SO_PEERCRED failed: %m");
+                return -errno;
+        }
+
+        if (l != sizeof(struct ucred)) {
+                log_error("SO_PEERCRED returned wrong size.");
+                return -E2BIG;
+        }
+
+        if (ucred.uid != 0 && ucred.uid != geteuid())
+                return -EPERM;
+
+        return 1;
+}
+
+static int sync_auth(DBusConnection *bus, DBusError *error) {
+        usec_t begin, tstamp;
+
+        assert(bus);
+
+        /* This complexity should probably move into D-Bus itself:
+         *
+         * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
+
+        begin = tstamp = now(CLOCK_MONOTONIC);
+        for (;;) {
+
+                if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
+                        break;
+
+                if (dbus_connection_get_is_authenticated(bus))
+                        break;
+
+                if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
+                        break;
+
+                tstamp = now(CLOCK_MONOTONIC);
+        }
+
+        if (!dbus_connection_get_is_connected(bus)) {
+                dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
+                return -ECONNREFUSED;
+        }
+
+        if (!dbus_connection_get_is_authenticated(bus)) {
+                dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
+                return -EACCES;
+        }
+
+        return 0;
+}
+
+int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
+        DBusConnection *bus = NULL;
+        int r;
+        bool private = true;
+
+        assert(_bus);
+
+        if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
+                /* If we are root, then let's talk directly to the
+                 * system instance, instead of going via the bus */
+
+                bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
+                if (!bus)
+                        return -EIO;
+
+        } else {
+                if (t == DBUS_BUS_SESSION) {
+                        const char *e;
+
+                        /* If we are supposed to talk to the instance,
+                         * try via XDG_RUNTIME_DIR first, then
+                         * fallback to normal bus access */
+
+                        e = getenv("XDG_RUNTIME_DIR");
+                        if (e) {
+                                char *p;
+
+                                if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
+                                        return -ENOMEM;
+
+                                bus = dbus_connection_open_private(p, NULL);
+                                free(p);
+                        }
+                }
+
+                if (!bus) {
+                        bus = dbus_bus_get_private(t, error);
+                        if (!bus)
+                                return -EIO;
+
+                        private = false;
+                }
+        }
+
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if (private) {
+                if (bus_check_peercred(bus) < 0) {
+                        dbus_connection_close(bus);
+                        dbus_connection_unref(bus);
+
+                        dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
+                        return -EACCES;
+                }
+        }
+
+        r = sync_auth(bus, error);
+        if (r < 0) {
+                dbus_connection_close(bus);
+                dbus_connection_unref(bus);
+                return r;
+        }
+
+        if (_private)
+                *_private = private;
+
+        *_bus = bus;
+        return 0;
+}
+
+int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
+        DBusConnection *bus;
+        char *p = NULL;
+        int r;
+
+        assert(_bus);
+        assert(user || host);
+
+        if (user && host)
+                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
+        else if (user)
+                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s at localhost,argv3=systemd-stdio-bridge", user);
+        else if (host)
+                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
+
+        if (!p) {
+                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+                return -ENOMEM;
+        }
+
+        bus = dbus_connection_open_private(p, error);
+        free(p);
+
+        if (!bus)
+                return -EIO;
+
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if ((r = sync_auth(bus, error)) < 0) {
+                dbus_connection_close(bus);
+                dbus_connection_unref(bus);
+                return r;
+        }
+
+        if (!dbus_bus_register(bus, error)) {
+                dbus_connection_close(bus);
+                dbus_connection_unref(bus);
+                return r;
+        }
+
+        *_bus = bus;
+        return 0;
+}
+
+int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
+        DBusConnection *bus;
+        int r;
+
+        assert(_bus);
+
+        /* Don't bother with PolicyKit if we are root */
+        if (geteuid() == 0)
+                return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
+
+        bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
+        if (!bus)
+                return -EIO;
+
+        dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+        if ((r = sync_auth(bus, error)) < 0) {
+                dbus_connection_close(bus);
+                dbus_connection_unref(bus);
+                return r;
+        }
+
+        if (!dbus_bus_register(bus, error)) {
+                dbus_connection_close(bus);
+                dbus_connection_unref(bus);
+                return r;
+        }
+
+        *_bus = bus;
+        return 0;
+}
+
+const char *bus_error_message(const DBusError *error) {
+        assert(error);
+
+        /* Sometimes the D-Bus server is a little bit too verbose with
+         * its error messages, so let's override them here */
+        if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
+                return "Access denied";
+
+        return error->message;
+}
+
+DBusHandlerResult bus_default_message_handler(
+                DBusConnection *c,
+                DBusMessage *message,
+                const char *introspection,
+                const char *interfaces,
+                const BusBoundProperties *bound_properties) {
+
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
+        assert(c);
+        assert(message);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
+                const char *interface, *property;
+                const BusBoundProperties *bp;
+                const BusProperty *p;
+                void *data;
+                DBusMessageIter iter, sub;
+
+                if (!dbus_message_get_args(
+                            message,
+                            &error,
+                            DBUS_TYPE_STRING, &interface,
+                            DBUS_TYPE_STRING, &property,
+                            DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(c, message, &error, -EINVAL);
+
+                for (bp = bound_properties; bp->interface; bp++) {
+                        if (!streq(bp->interface, interface))
+                                continue;
+
+                        for (p = bp->properties; p->property; p++)
+                                if (streq(p->property, property))
+                                        goto get_prop;
+                }
+
+                /* no match */
+                if (!nulstr_contains(interfaces, interface))
+                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+                else
+                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
+
+                return bus_send_error_reply(c, message, &error, -EINVAL);
+
+get_prop:
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
+                        goto oom;
+
+                data = (char*)bp->base + p->offset;
+                if (p->indirect)
+                        data = *(void**)data;
+                r = p->append(&sub, property, data);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+
+                        dbus_message_unref(reply);
+                        return bus_send_error_reply(c, message, NULL, r);
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
+                const char *interface;
+                const BusBoundProperties *bp;
+                const BusProperty *p;
+                DBusMessageIter iter, sub, sub2, sub3;
+
+                if (!dbus_message_get_args(
+                            message,
+                            &error,
+                            DBUS_TYPE_STRING, &interface,
+                            DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(c, message, &error, -EINVAL);
+
+                if (interface[0] && !nulstr_contains(interfaces, interface)) {
+                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+                        return bus_send_error_reply(c, message, &error, -EINVAL);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
+                        goto oom;
+
+                for (bp = bound_properties; bp->interface; bp++) {
+                        if (interface[0] && !streq(bp->interface, interface))
+                                continue;
+
+                        for (p = bp->properties; p->property; p++) {
+                                void *data;
+
+                                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
+                                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
+                                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
+                                        goto oom;
+
+                                data = (char*)bp->base + p->offset;
+                                if (p->indirect)
+                                        data = *(void**)data;
+                                r = p->append(&sub3, p->property, data);
+                                if (r < 0) {
+                                        if (r == -ENOMEM)
+                                                goto oom;
+
+                                        dbus_message_unref(reply);
+                                        return bus_send_error_reply(c, message, NULL, r);
+                                }
+
+                                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
+                                    !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.DBus.Properties", "Set") && bound_properties) {
+                const char *interface, *property;
+                DBusMessageIter iter;
+                const BusBoundProperties *bp;
+                const BusProperty *p;
+                DBusMessageIter sub;
+                char *sig;
+                void *data;
+
+                if (!dbus_message_iter_init(message, &iter) ||
+                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                        return bus_send_error_reply(c, message, NULL, -EINVAL);
+
+                dbus_message_iter_get_basic(&iter, &interface);
+
+                if (!dbus_message_iter_next(&iter) ||
+                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                        return bus_send_error_reply(c, message, NULL, -EINVAL);
+
+                dbus_message_iter_get_basic(&iter, &property);
+
+                if (!dbus_message_iter_next(&iter) ||
+                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
+                    dbus_message_iter_has_next(&iter))
+                        return bus_send_error_reply(c, message, NULL, -EINVAL);
+
+                for (bp = bound_properties; bp->interface; bp++) {
+                        if (!streq(bp->interface, interface))
+                                continue;
+
+                        for (p = bp->properties; p->property; p++)
+                                if (streq(p->property, property))
+                                        goto set_prop;
+                }
+
+                /* no match */
+                if (!nulstr_contains(interfaces, interface))
+                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+                else
+                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
+
+                return bus_send_error_reply(c, message, &error, -EINVAL);
+
+set_prop:
+                if (!p->set) {
+                        dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
+                        return bus_send_error_reply(c, message, &error, -EINVAL);
+                }
+
+                dbus_message_iter_recurse(&iter, &sub);
+
+                sig = dbus_message_iter_get_signature(&sub);
+                if (!sig)
+                        goto oom;
+
+                if (!streq(sig, p->signature)) {
+                        dbus_free(sig);
+                        return bus_send_error_reply(c, message, NULL, -EINVAL);
+                }
+
+                dbus_free(sig);
+
+                data = (char*)bp->base + p->offset;
+                if (p->indirect)
+                        data = *(void**)data;
+                r = p->set(&sub, property, data);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                goto oom;
+                        return bus_send_error_reply(c, message, NULL, r);
+                }
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+        } else {
+                const char *interface = dbus_message_get_interface(message);
+
+                if (!interface || !nulstr_contains(interfaces, interface)) {
+                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+                        return bus_send_error_reply(c, message, &error, -EINVAL);
+                }
+        }
+
+        if (reply) {
+                if (!dbus_connection_send(c, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+                return DBUS_HANDLER_RESULT_HANDLED;
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
+        const char *t = data;
+
+        assert(i);
+        assert(property);
+
+        if (!t)
+                t = "";
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
+        char **t = data;
+
+        assert(i);
+        assert(property);
+
+        return bus_append_strv_iter(i, t);
+}
+
+int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
+        bool *b = data;
+        dbus_bool_t db;
+
+        assert(i);
+        assert(property);
+        assert(b);
+
+        db = *b;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
+        int *b = data;
+        dbus_bool_t db;
+
+        assert(i);
+        assert(property);
+        assert(b);
+
+        db = *b > 0;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
+        assert(i);
+        assert(property);
+        assert(data);
+
+        /* Let's ensure that usec_t is actually 64bit, and hence this
+         * function can be used for usec_t */
+        assert_cc(sizeof(uint64_t) == sizeof(usec_t));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
+        assert(i);
+        assert(property);
+        assert(data);
+
+        /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
+         * 32bit, and hence this function can be used for
+         * pid_t/mode_t/uid_t/gid_t */
+        assert_cc(sizeof(uint32_t) == sizeof(pid_t));
+        assert_cc(sizeof(uint32_t) == sizeof(mode_t));
+        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+        assert_cc(sizeof(uint32_t) == sizeof(uid_t));
+        assert_cc(sizeof(uint32_t) == sizeof(gid_t));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
+        assert(i);
+        assert(property);
+        assert(data);
+
+        assert_cc(sizeof(int32_t) == sizeof(int));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
+        uint64_t u;
+
+        assert(i);
+        assert(property);
+        assert(data);
+
+        u = (uint64_t) *(size_t*) data;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
+        uint64_t u;
+
+        assert(i);
+        assert(property);
+        assert(data);
+
+        u = (uint64_t) *(unsigned long*) data;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
+        int64_t l;
+
+        assert(i);
+        assert(property);
+        assert(data);
+
+        l = (int64_t) *(long*) data;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
+                return -ENOMEM;
+
+        return 0;
+}
+
+const char *bus_errno_to_dbus(int error) {
+
+        switch(error) {
+
+        case -EINVAL:
+                return DBUS_ERROR_INVALID_ARGS;
+
+        case -ENOMEM:
+                return DBUS_ERROR_NO_MEMORY;
+
+        case -EPERM:
+        case -EACCES:
+                return DBUS_ERROR_ACCESS_DENIED;
+
+        case -ESRCH:
+                return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
+
+        case -ENOENT:
+                return DBUS_ERROR_FILE_NOT_FOUND;
+
+        case -EEXIST:
+                return DBUS_ERROR_FILE_EXISTS;
+
+        case -ETIMEDOUT:
+        case -ETIME:
+                return DBUS_ERROR_TIMEOUT;
+
+        case -EIO:
+                return DBUS_ERROR_IO_ERROR;
+
+        case -ENETRESET:
+        case -ECONNABORTED:
+        case -ECONNRESET:
+                return DBUS_ERROR_DISCONNECTED;
+        }
+
+        return DBUS_ERROR_FAILED;
+}
+
+DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
+        DBusMessage *reply = NULL;
+        const char *name, *text;
+
+        if (berror && dbus_error_is_set(berror)) {
+                name = berror->name;
+                text = berror->message;
+        } else {
+                name = bus_errno_to_dbus(error);
+                text = strerror(-error);
+        }
+
+        if (!(reply = dbus_message_new_error(message, name, text)))
+                goto oom;
+
+        if (!dbus_connection_send(c, reply, NULL))
+                goto oom;
+
+        dbus_message_unref(reply);
+
+        if (berror)
+                dbus_error_free(berror);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        if (berror)
+                dbus_error_free(berror);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
+        DBusMessage *m;
+        DBusMessageIter iter, sub;
+        const char *i;
+
+        assert(interface);
+        assert(properties);
+
+        if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
+                goto oom;
+
+        dbus_message_iter_init_append(m, &iter);
+
+        /* We won't send any property values, since they might be
+         * large and sometimes not cheap to generated */
+
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
+            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
+            !dbus_message_iter_close_container(&iter, &sub) ||
+            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
+                goto oom;
+
+        NULSTR_FOREACH(i, properties)
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
+                        goto oom;
+
+        if (!dbus_message_iter_close_container(&iter, &sub))
+                goto oom;
+
+        return m;
+
+oom:
+        if (m)
+                dbus_message_unref(m);
+
+        return NULL;
+}
+
+uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
+        unsigned flags;
+        uint32_t events = 0;
+
+        assert(bus_watch);
+
+        /* no watch flags for disabled watches */
+        if (!dbus_watch_get_enabled(bus_watch))
+                return 0;
+
+        flags = dbus_watch_get_flags(bus_watch);
+
+        if (flags & DBUS_WATCH_READABLE)
+                events |= EPOLLIN;
+        if (flags & DBUS_WATCH_WRITABLE)
+                events |= EPOLLOUT;
+
+        return events | EPOLLHUP | EPOLLERR;
+}
+
+unsigned bus_events_to_flags(uint32_t events) {
+        unsigned flags = 0;
+
+        if (events & EPOLLIN)
+                flags |= DBUS_WATCH_READABLE;
+        if (events & EPOLLOUT)
+                flags |= DBUS_WATCH_WRITABLE;
+        if (events & EPOLLHUP)
+                flags |= DBUS_WATCH_HANGUP;
+        if (events & EPOLLERR)
+                flags |= DBUS_WATCH_ERROR;
+
+        return flags;
+}
+
+int bus_parse_strv(DBusMessage *m, char ***_l) {
+        DBusMessageIter iter;
+
+        assert(m);
+        assert(_l);
+
+        if (!dbus_message_iter_init(m, &iter))
+                return -EINVAL;
+
+        return bus_parse_strv_iter(&iter, _l);
+}
+
+int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
+        DBusMessageIter sub;
+        unsigned n = 0, i = 0;
+        char **l;
+
+        assert(iter);
+        assert(_l);
+
+        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
+            return -EINVAL;
+
+        dbus_message_iter_recurse(iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                n++;
+                dbus_message_iter_next(&sub);
+        }
+
+        if (!(l = new(char*, n+1)))
+                return -ENOMEM;
+
+        dbus_message_iter_recurse(iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *s;
+
+                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+                dbus_message_iter_get_basic(&sub, &s);
+
+                if (!(l[i++] = strdup(s))) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+                dbus_message_iter_next(&sub);
+        }
+
+        assert(i == n);
+        l[i] = NULL;
+
+        if (_l)
+                *_l = l;
+
+        return 0;
+}
+
+int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
+        DBusMessageIter sub;
+
+        assert(iter);
+
+        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
+                return -ENOMEM;
+
+        STRV_FOREACH(l, l)
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
+                        return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(iter, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
+
+        assert(iter);
+        assert(data);
+
+        if (dbus_message_iter_get_arg_type(iter) != type)
+                return -EIO;
+
+        dbus_message_iter_get_basic(iter, data);
+
+        if (!dbus_message_iter_next(iter) != !next)
+                return -EIO;
+
+        return 0;
+}
+
+int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
+        assert(name);
+        assert(iter);
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRING: {
+                const char *s;
+                dbus_message_iter_get_basic(iter, &s);
+
+                if (all || !isempty(s))
+                        printf("%s=%s\n", name, s);
+
+                return 1;
+        }
+
+        case DBUS_TYPE_BOOLEAN: {
+                dbus_bool_t b;
+
+                dbus_message_iter_get_basic(iter, &b);
+                printf("%s=%s\n", name, yes_no(b));
+
+                return 1;
+        }
+
+        case DBUS_TYPE_UINT64: {
+                uint64_t u;
+                dbus_message_iter_get_basic(iter, &u);
+
+                /* Yes, heuristics! But we can change this check
+                 * should it turn out to not be sufficient */
+
+                if (endswith(name, "Timestamp")) {
+                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
+
+                        t = format_timestamp(timestamp, sizeof(timestamp), u);
+                        if (t || all)
+                                printf("%s=%s\n", name, strempty(t));
+
+                } else if (strstr(name, "USec")) {
+                        char timespan[FORMAT_TIMESPAN_MAX];
+
+                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
+                } else
+                        printf("%s=%llu\n", name, (unsigned long long) u);
+
+                return 1;
+        }
+
+        case DBUS_TYPE_UINT32: {
+                uint32_t u;
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (strstr(name, "UMask") || strstr(name, "Mode"))
+                        printf("%s=%04o\n", name, u);
+                else
+                        printf("%s=%u\n", name, (unsigned) u);
+
+                return 1;
+        }
+
+        case DBUS_TYPE_INT32: {
+                int32_t i;
+                dbus_message_iter_get_basic(iter, &i);
+
+                printf("%s=%i\n", name, (int) i);
+                return 1;
+        }
+
+        case DBUS_TYPE_DOUBLE: {
+                double d;
+                dbus_message_iter_get_basic(iter, &d);
+
+                printf("%s=%g\n", name, d);
+                return 1;
+        }
+
+        case DBUS_TYPE_ARRAY:
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
+                        DBusMessageIter sub;
+                        bool space = false;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        if (all ||
+                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                printf("%s=", name);
+
+                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                        const char *s;
+
+                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+                                        dbus_message_iter_get_basic(&sub, &s);
+                                        printf("%s%s", space ? " " : "", s);
+
+                                        space = true;
+                                        dbus_message_iter_next(&sub);
+                                }
+
+                                puts("");
+                        }
+
+                        return 1;
+
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
+                        DBusMessageIter sub;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        if (all ||
+                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                printf("%s=", name);
+
+                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                        uint8_t u;
+
+                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
+                                        dbus_message_iter_get_basic(&sub, &u);
+                                        printf("%02x", u);
+
+                                        dbus_message_iter_next(&sub);
+                                }
+
+                                puts("");
+                        }
+
+                        return 1;
+                }
+
+                break;
+        }
+
+        return 0;
+}
+
+static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
+        DBusMessage *reply;
+        DBusConnection *bus = userdata;
+
+        assert_se(reply = dbus_pending_call_steal_reply(pending));
+        dbus_message_unref(reply);
+
+        dbus_connection_close(bus);
+}
+
+void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
+        DBusMessage *m = NULL;
+        DBusPendingCall *pending = NULL;
+
+        assert(bus);
+
+        /* We unregister the name here, but we continue to process
+         * requests, until we get the response for it, so that all
+         * requests are guaranteed to be processed. */
+
+        m = dbus_message_new_method_call(
+                        DBUS_SERVICE_DBUS,
+                        DBUS_PATH_DBUS,
+                        DBUS_INTERFACE_DBUS,
+                        "ReleaseName");
+        if (!m)
+                goto oom;
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_STRING,
+                            &name,
+                            DBUS_TYPE_INVALID))
+                goto oom;
+
+        if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
+                goto oom;
+
+        if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
+                goto oom;
+
+        dbus_message_unref(m);
+        dbus_pending_call_unref(pending);
+
+        return;
+
+oom:
+        log_error("Out of memory");
+
+        if (pending) {
+                dbus_pending_call_cancel(pending);
+                dbus_pending_call_unref(pending);
+        }
+
+        if (m)
+                dbus_message_unref(m);
+}
+
+DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
+        usec_t *remain_until = userdata;
+
+        assert(bus);
+        assert(m);
+        assert(remain_until);
+
+        /* Everytime we get a new message we reset out timeout */
+        *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
+
+        if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
+                dbus_connection_close(bus);
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
diff --git a/src/shared/dbus-common.h b/src/shared/dbus-common.h
new file mode 100644
index 0000000..38d8e65
--- /dev/null
+++ b/src/shared/dbus-common.h
@@ -0,0 +1,198 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foodbuscommonhfoo
+#define foodbuscommonhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#ifndef DBUS_ERROR_UNKNOWN_OBJECT
+#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject"
+#endif
+
+#ifndef DBUS_ERROR_UNKNOWN_INTERFACE
+#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface"
+#endif
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif
+
+#define BUS_PROPERTIES_INTERFACE                                        \
+        " <interface name=\"org.freedesktop.DBus.Properties\">\n"       \
+        "  <method name=\"Get\">\n"                                     \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
+        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetAll\">\n"                                  \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"Set\">\n"                                     \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
+        "   <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <signal name=\"PropertiesChanged\">\n"                       \
+        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
+        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
+        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
+        "  </signal>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECTABLE_INTERFACE                                    \
+        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"   \
+        "  <method name=\"Introspect\">\n"                              \
+        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_PEER_INTERFACE                                              \
+        "<interface name=\"org.freedesktop.DBus.Peer\">\n"              \
+        " <method name=\"Ping\"/>\n"                                    \
+        " <method name=\"GetMachineId\">\n"                             \
+        "  <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
+        " </method>\n"                                                  \
+        "</interface>\n"
+
+#define BUS_GENERIC_INTERFACES_LIST             \
+        "org.freedesktop.DBus.Properties\0"     \
+        "org.freedesktop.DBus.Introspectable\0" \
+        "org.freedesktop.DBus.Peer\0"
+
+int bus_check_peercred(DBusConnection *c);
+
+int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error);
+
+int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error);
+int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error);
+
+const char *bus_error_message(const DBusError *error);
+
+typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data);
+typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property, void *data);
+
+typedef struct BusProperty {
+        const char *property;            /* name of the property */
+        BusPropertyCallback append;      /* Function that is called to serialize this property */
+        const char *signature;
+        const uint16_t offset;           /* Offset from BusBoundProperties::base address to the property data.
+                                          * uint16_t is sufficient, because we have no structs too big.
+                                          * -Werror=overflow will catch it if this does not hold. */
+        bool indirect;                   /* data is indirect, ie. not base+offset, but *(base+offset) */
+        BusPropertySetCallback set;      /* Optional: Function that is called to set this property */
+} BusProperty;
+
+typedef struct BusBoundProperties {
+        const char *interface;           /* interface of the properties */
+        const BusProperty *properties;   /* array of properties, ended by a NULL-filled element */
+        const void *const base;          /* base pointer to which the offset must be added to reach data */
+} BusBoundProperties;
+
+DBusHandlerResult bus_send_error_reply(
+                DBusConnection *c,
+                DBusMessage *message,
+                DBusError *bus_error,
+                int error);
+
+DBusHandlerResult bus_default_message_handler(
+                DBusConnection *c,
+                DBusMessage *message,
+                const char *introspection,
+                const char *interfaces,
+                const BusBoundProperties *bound_properties);
+
+int bus_property_append_string(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_size(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_long(DBusMessageIter *i, const char *property, void *data);
+
+#define bus_property_append_int bus_property_append_int32
+#define bus_property_append_pid bus_property_append_uint32
+#define bus_property_append_uid bus_property_append_uint32
+#define bus_property_append_gid bus_property_append_uint32
+#define bus_property_append_mode bus_property_append_uint32
+#define bus_property_append_unsigned bus_property_append_uint32
+#define bus_property_append_usec bus_property_append_uint64
+
+#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type)             \
+        int function(DBusMessageIter *i, const char *property, void *data) { \
+                const char *value;                                      \
+                type *field = data;                                     \
+                                                                        \
+                assert(i);                                              \
+                assert(property);                                       \
+                                                                        \
+                value = name##_to_string(*field);                       \
+                                                                        \
+                if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \
+                        return -ENOMEM;                                 \
+                                                                        \
+                return 0;                                               \
+        }
+
+#define DEFINE_BUS_PROPERTY_SET_ENUM(function,name,type)                \
+        int function(DBusMessageIter *i, const char *property, void *data) { \
+                const char *value;                                      \
+                type *field = data;                                     \
+                                                                        \
+                assert(i);                                              \
+                assert(property);                                       \
+                                                                        \
+                dbus_message_iter_get_basic(i, &value);                 \
+                                                                        \
+                *field = name##_from_string(value);                     \
+                                                                        \
+                return 0;                                               \
+        }
+
+const char *bus_errno_to_dbus(int error);
+
+DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties);
+
+uint32_t bus_flags_to_events(DBusWatch *bus_watch);
+unsigned bus_events_to_flags(uint32_t events);
+
+int bus_parse_strv(DBusMessage *m, char ***_l);
+int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l);
+
+int bus_append_strv_iter(DBusMessageIter *iter, char **l);
+
+int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next);
+
+int generic_print_property(const char *name, DBusMessageIter *iter, bool all);
+
+void bus_async_unregister_and_exit(DBusConnection *bus, const char *name);
+
+DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata);
+
+#endif
diff --git a/src/shared/hostname-setup.c b/src/shared/hostname-setup.c
new file mode 100644
index 0000000..550d3c2
--- /dev/null
+++ b/src/shared/hostname-setup.c
@@ -0,0 +1,187 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "hostname-setup.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+
+#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
+#define FILENAME "/etc/sysconfig/network"
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
+#define FILENAME "/etc/HOSTNAME"
+#elif defined(TARGET_ARCH)
+#define FILENAME "/etc/rc.conf"
+#elif defined(TARGET_GENTOO)
+#define FILENAME "/etc/conf.d/hostname"
+#endif
+
+static int read_and_strip_hostname(const char *path, char **hn) {
+        char *s;
+        int r;
+
+        assert(path);
+        assert(hn);
+
+        if ((r = read_one_line_file(path, &s)) < 0)
+                return r;
+
+        hostname_cleanup(s);
+
+        if (isempty(s)) {
+                free(s);
+                return -ENOENT;
+        }
+
+        *hn = s;
+
+        return 0;
+}
+
+static int read_distro_hostname(char **hn) {
+
+#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
+        int r;
+        FILE *f;
+
+        assert(hn);
+
+        if (!(f = fopen(FILENAME, "re")))
+                return -errno;
+
+        for (;;) {
+                char line[LINE_MAX];
+                char *s, *k;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                break;
+
+                        r = -errno;
+                        goto finish;
+                }
+
+                s = strstrip(line);
+
+                if (!startswith_no_case(s, "HOSTNAME="))
+                        continue;
+
+                if (!(k = strdup(s+9))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                hostname_cleanup(k);
+
+                if (isempty(k)) {
+                        free(k);
+                        r = -ENOENT;
+                        goto finish;
+                }
+
+                *hn = k;
+                r = 0;
+                goto finish;
+        }
+
+        r = -ENOENT;
+
+finish:
+        fclose(f);
+        return r;
+
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
+        return read_and_strip_hostname(FILENAME, hn);
+#else
+        return -ENOENT;
+#endif
+}
+
+static int read_hostname(char **hn) {
+        int r;
+
+        assert(hn);
+
+        /* First, try to load the generic hostname configuration file,
+         * that we support on all distributions */
+
+        if ((r = read_and_strip_hostname("/etc/hostname", hn)) < 0) {
+
+                if (r == -ENOENT)
+                        return read_distro_hostname(hn);
+
+                return r;
+        }
+
+        return 0;
+}
+
+int hostname_setup(void) {
+        int r;
+        char *b = NULL;
+        const char *hn = NULL;
+
+        if ((r = read_hostname(&b)) < 0) {
+                if (r == -ENOENT)
+                        log_info("No hostname configured.");
+                else
+                        log_warning("Failed to read configured hostname: %s", strerror(-r));
+
+                hn = NULL;
+        } else
+                hn = b;
+
+        if (!hn) {
+                /* Don't override the hostname if it is unset and not
+                 * explicitly configured */
+
+                char *old_hostname = NULL;
+
+                if ((old_hostname = gethostname_malloc())) {
+                        bool already_set;
+
+                        already_set = old_hostname[0] != 0;
+                        free(old_hostname);
+
+                        if (already_set)
+                                goto finish;
+                }
+
+                hn = "localhost";
+        }
+
+        if (sethostname(hn, strlen(hn)) < 0) {
+                log_warning("Failed to set hostname to <%s>: %m", hn);
+                r = -errno;
+        } else
+                log_info("Set hostname to <%s>.", hn);
+
+finish:
+        free(b);
+
+        return r;
+}
diff --git a/src/shared/hostname-setup.h b/src/shared/hostname-setup.h
new file mode 100644
index 0000000..9550b8c
--- /dev/null
+++ b/src/shared/hostname-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foohostnamesetuphfoo
+#define foohostnamesetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int hostname_setup(void);
+
+#endif
diff --git a/src/shared/install.c b/src/shared/install.c
new file mode 100644
index 0000000..080ae6a
--- /dev/null
+++ b/src/shared/install.c
@@ -0,0 +1,1954 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty <of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#include "util.h"
+#include "mkdir.h"
+#include "hashmap.h"
+#include "set.h"
+#include "path-lookup.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "install.h"
+#include "conf-parser.h"
+
+typedef struct {
+        char *name;
+        char *path;
+
+        char **aliases;
+        char **wanted_by;
+} InstallInfo;
+
+typedef struct {
+        Hashmap *will_install;
+        Hashmap *have_installed;
+} InstallContext;
+
+static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
+        assert(paths);
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        zero(*paths);
+
+        return lookup_paths_init(paths,
+                                 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
+                                 scope == UNIT_FILE_USER);
+}
+
+static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
+        char *p = NULL;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(ret);
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:
+
+                if (root_dir && runtime)
+                        asprintf(&p, "%s/run/systemd/system", root_dir);
+                else if (runtime)
+                        p = strdup("/run/systemd/system");
+                else if (root_dir)
+                        asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
+                else
+                        p = strdup(SYSTEM_CONFIG_UNIT_PATH);
+
+                break;
+
+        case UNIT_FILE_GLOBAL:
+
+                if (root_dir)
+                        return -EINVAL;
+
+                if (runtime)
+                        p = strdup("/run/systemd/user");
+                else
+                        p = strdup(USER_CONFIG_UNIT_PATH);
+                break;
+
+        case UNIT_FILE_USER:
+
+                if (root_dir || runtime)
+                        return -EINVAL;
+
+                r = user_config_home(&p);
+                if (r <= 0)
+                        return r < 0 ? r : -ENOENT;
+
+                break;
+
+        default:
+                assert_not_reached("Bad scope");
+        }
+
+        if (!p)
+                return -ENOMEM;
+
+        *ret = p;
+        return 0;
+}
+
+static int add_file_change(
+                UnitFileChange **changes,
+                unsigned *n_changes,
+                UnitFileChangeType type,
+                const char *path,
+                const char *source) {
+
+        UnitFileChange *c;
+        unsigned i;
+
+        assert(path);
+        assert(!changes == !n_changes);
+
+        if (!changes)
+                return 0;
+
+        c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
+        if (!c)
+                return -ENOMEM;
+
+        *changes = c;
+        i = *n_changes;
+
+        c[i].type = type;
+        c[i].path = strdup(path);
+        if (!c[i].path)
+                return -ENOMEM;
+
+        if (source) {
+                c[i].source = strdup(source);
+                if (!c[i].source) {
+                        free(c[i].path);
+                        return -ENOMEM;
+                }
+        } else
+                c[i].source = NULL;
+
+        *n_changes = i+1;
+        return 0;
+}
+
+static int mark_symlink_for_removal(
+                Set **remove_symlinks_to,
+                const char *p) {
+
+        char *n;
+        int r;
+
+        assert(p);
+
+        r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
+        if (r < 0)
+                return r;
+
+        n = strdup(p);
+        if (!n)
+                return -ENOMEM;
+
+        path_kill_slashes(n);
+
+        r = set_put(*remove_symlinks_to, n);
+        if (r < 0) {
+                free(n);
+                return r == -EEXIST ? 0 : r;
+        }
+
+        return 0;
+}
+
+static int remove_marked_symlinks_fd(
+                Set *remove_symlinks_to,
+                int fd,
+                const char *path,
+                const char *config_path,
+                bool *deleted,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        int r = 0;
+        DIR *d;
+        struct dirent buffer, *de;
+
+        assert(remove_symlinks_to);
+        assert(fd >= 0);
+        assert(path);
+        assert(config_path);
+        assert(deleted);
+
+        d = fdopendir(fd);
+        if (!d) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        rewinddir(d);
+
+        for (;;) {
+                int k;
+
+                k = readdir_r(d, &buffer, &de);
+                if (k != 0) {
+                        r = -errno;
+                        break;
+                }
+
+                if (!de)
+                        break;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                dirent_ensure_type(d, de);
+
+                if (de->d_type == DT_DIR) {
+                        int nfd, q;
+                        char *p;
+
+                        nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+                        if (nfd < 0) {
+                                if (errno == ENOENT)
+                                        continue;
+
+                                if (r == 0)
+                                        r = -errno;
+                                continue;
+                        }
+
+                        p = path_make_absolute(de->d_name, path);
+                        if (!p) {
+                                close_nointr_nofail(nfd);
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        /* This will close nfd, regardless whether it succeeds or not */
+                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
+                        free(p);
+
+                        if (r == 0)
+                                r = q;
+
+                } else if (de->d_type == DT_LNK) {
+                        char *p, *dest;
+                        int q;
+                        bool found;
+
+                        p = path_make_absolute(de->d_name, path);
+                        if (!p) {
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        q = readlink_and_canonicalize(p, &dest);
+                        if (q < 0) {
+                                free(p);
+
+                                if (q == -ENOENT)
+                                        continue;
+
+                                if (r == 0)
+                                        r = q;
+                                continue;
+                        }
+
+                        found =
+                                set_get(remove_symlinks_to, dest) ||
+                                set_get(remove_symlinks_to, file_name_from_path(dest));
+
+                        if (found) {
+
+                                if (unlink(p) < 0 && errno != ENOENT) {
+
+                                        if (r == 0)
+                                                r = -errno;
+                                } else {
+                                        rmdir_parents(p, config_path);
+                                        path_kill_slashes(p);
+
+                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
+
+                                        if (!set_get(remove_symlinks_to, p)) {
+
+                                                q = mark_symlink_for_removal(&remove_symlinks_to, p);
+                                                if (q < 0) {
+                                                        if (r == 0)
+                                                                r = q;
+                                                } else
+                                                        *deleted = true;
+                                        }
+                                }
+                        }
+
+                        free(p);
+                        free(dest);
+                }
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+static int remove_marked_symlinks(
+                Set *remove_symlinks_to,
+                const char *config_path,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        int fd, r = 0;
+        bool deleted;
+
+        assert(config_path);
+
+        if (set_size(remove_symlinks_to) <= 0)
+                return 0;
+
+        fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        do {
+                int q, cfd;
+                deleted = false;
+
+                cfd = dup(fd);
+                if (cfd < 0) {
+                        r = -errno;
+                        break;
+                }
+
+                /* This takes possession of cfd and closes it */
+                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
+                if (r == 0)
+                        r = q;
+        } while (deleted);
+
+        close_nointr_nofail(fd);
+
+        return r;
+}
+
+static int find_symlinks_fd(
+                const char *name,
+                int fd,
+                const char *path,
+                const char *config_path,
+                bool *same_name_link) {
+
+        int r = 0;
+        DIR *d;
+        struct dirent buffer, *de;
+
+        assert(name);
+        assert(fd >= 0);
+        assert(path);
+        assert(config_path);
+        assert(same_name_link);
+
+        d = fdopendir(fd);
+        if (!d) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        for (;;) {
+                int k;
+
+                k = readdir_r(d, &buffer, &de);
+                if (k != 0) {
+                        r = -errno;
+                        break;
+                }
+
+                if (!de)
+                        break;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                dirent_ensure_type(d, de);
+
+                if (de->d_type == DT_DIR) {
+                        int nfd, q;
+                        char *p;
+
+                        nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+                        if (nfd < 0) {
+                                if (errno == ENOENT)
+                                        continue;
+
+                                if (r == 0)
+                                        r = -errno;
+                                continue;
+                        }
+
+                        p = path_make_absolute(de->d_name, path);
+                        if (!p) {
+                                close_nointr_nofail(nfd);
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        /* This will close nfd, regardless whether it succeeds or not */
+                        q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
+                        free(p);
+
+                        if (q > 0) {
+                                r = 1;
+                                break;
+                        }
+
+                        if (r == 0)
+                                r = q;
+
+                } else if (de->d_type == DT_LNK) {
+                        char *p, *dest;
+                        bool found_path, found_dest, b = false;
+                        int q;
+
+                        /* Acquire symlink name */
+                        p = path_make_absolute(de->d_name, path);
+                        if (!p) {
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        /* Acquire symlink destination */
+                        q = readlink_and_canonicalize(p, &dest);
+                        if (q < 0) {
+                                free(p);
+
+                                if (q == -ENOENT)
+                                        continue;
+
+                                if (r == 0)
+                                        r = q;
+                                continue;
+                        }
+
+                        /* Check if the symlink itself matches what we
+                         * are looking for */
+                        if (path_is_absolute(name))
+                                found_path = path_equal(p, name);
+                        else
+                                found_path = streq(de->d_name, name);
+
+                        /* Check if what the symlink points to
+                         * matches what we are looking for */
+                        if (path_is_absolute(name))
+                                found_dest = path_equal(dest, name);
+                        else
+                                found_dest = streq(file_name_from_path(dest), name);
+
+                        free(dest);
+
+                        if (found_path && found_dest) {
+                                char *t;
+
+                                /* Filter out same name links in the main
+                                 * config path */
+                                t = path_make_absolute(name, config_path);
+                                if (!t) {
+                                        free(p);
+                                        r = -ENOMEM;
+                                        break;
+                                }
+
+                                b = path_equal(t, p);
+                                free(t);
+                        }
+
+                        free(p);
+
+                        if (b)
+                                *same_name_link = true;
+                        else if (found_path || found_dest) {
+                                r = 1;
+                                break;
+                        }
+                }
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+static int find_symlinks(
+                const char *name,
+                const char *config_path,
+                bool *same_name_link) {
+
+        int fd;
+
+        assert(name);
+        assert(config_path);
+        assert(same_name_link);
+
+        fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        /* This takes possession of fd and closes it */
+        return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
+}
+
+static int find_symlinks_in_scope(
+                UnitFileScope scope,
+                const char *root_dir,
+                const char *name,
+                UnitFileState *state) {
+
+        int r;
+        char *path;
+        bool same_name_link_runtime = false, same_name_link = false;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(name);
+
+        if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
+
+                /* First look in runtime config path */
+                r = get_config_path(scope, true, root_dir, &path);
+                if (r < 0)
+                        return r;
+
+                r = find_symlinks(name, path, &same_name_link_runtime);
+                free(path);
+
+                if (r < 0)
+                        return r;
+                else if (r > 0) {
+                        *state = UNIT_FILE_ENABLED_RUNTIME;
+                        return r;
+                }
+        }
+
+        /* Then look in the normal config path */
+        r = get_config_path(scope, false, root_dir, &path);
+        if (r < 0)
+                return r;
+
+        r = find_symlinks(name, path, &same_name_link);
+        free(path);
+
+        if (r < 0)
+                return r;
+        else if (r > 0) {
+                *state = UNIT_FILE_ENABLED;
+                return r;
+        }
+
+        /* Hmm, we didn't find it, but maybe we found the same name
+         * link? */
+        if (same_name_link_runtime) {
+                *state = UNIT_FILE_LINKED_RUNTIME;
+                return 1;
+        } else if (same_name_link) {
+                *state = UNIT_FILE_LINKED;
+                return 1;
+        }
+
+        return 0;
+}
+
+int unit_file_mask(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        char **i, *prefix;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        r = get_config_path(scope, runtime, root_dir, &prefix);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, files) {
+                char *path;
+
+                if (!unit_name_is_valid_no_type(*i, true)) {
+                        if (r == 0)
+                                r = -EINVAL;
+                        continue;
+                }
+
+                path = path_make_absolute(*i, prefix);
+                if (!path) {
+                        r = -ENOMEM;
+                        break;
+                }
+
+                if (symlink("/dev/null", path) >= 0) {
+                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
+
+                        free(path);
+                        continue;
+                }
+
+                if (errno == EEXIST) {
+
+                        if (null_or_empty_path(path) > 0) {
+                                free(path);
+                                continue;
+                        }
+
+                        if (force) {
+                                unlink(path);
+
+                                if (symlink("/dev/null", path) >= 0) {
+
+                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+                                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
+
+                                        free(path);
+                                        continue;
+                                }
+                        }
+
+                        if (r == 0)
+                                r = -EEXIST;
+                } else {
+                        if (r == 0)
+                                r = -errno;
+                }
+
+                free(path);
+        }
+
+        free(prefix);
+
+        return r;
+}
+
+int unit_file_unmask(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        char **i, *config_path = NULL;
+        int r, q;
+        Set *remove_symlinks_to = NULL;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                goto finish;
+
+        STRV_FOREACH(i, files) {
+                char *path;
+
+                if (!unit_name_is_valid_no_type(*i, true)) {
+                        if (r == 0)
+                                r = -EINVAL;
+                        continue;
+                }
+
+                path = path_make_absolute(*i, config_path);
+                if (!path) {
+                        r = -ENOMEM;
+                        break;
+                }
+
+                q = null_or_empty_path(path);
+                if (q > 0) {
+                        if (unlink(path) >= 0) {
+                                mark_symlink_for_removal(&remove_symlinks_to, path);
+                                add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+
+                                free(path);
+                                continue;
+                        }
+
+                        q = -errno;
+                }
+
+                if (q != -ENOENT && r == 0)
+                        r = q;
+
+                free(path);
+        }
+
+
+finish:
+        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+        set_free_free(remove_symlinks_to);
+        free(config_path);
+
+        return r;
+}
+
+int unit_file_link(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        LookupPaths paths;
+        char **i, *config_path = NULL;
+        int r, q;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        zero(paths);
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                goto finish;
+
+        STRV_FOREACH(i, files) {
+                char *path, *fn;
+                struct stat st;
+
+                fn = file_name_from_path(*i);
+
+                if (!path_is_absolute(*i) ||
+                    !unit_name_is_valid_no_type(fn, true)) {
+                        if (r == 0)
+                                r = -EINVAL;
+                        continue;
+                }
+
+                if (lstat(*i, &st) < 0) {
+                        if (r == 0)
+                                r = -errno;
+                        continue;
+                }
+
+                if (!S_ISREG(st.st_mode)) {
+                        r = -ENOENT;
+                        continue;
+                }
+
+                q = in_search_path(*i, paths.unit_path);
+                if (q < 0) {
+                        r = q;
+                        break;
+                }
+
+                if (q > 0)
+                        continue;
+
+                path = path_make_absolute(fn, config_path);
+                if (!path) {
+                        r = -ENOMEM;
+                        break;
+                }
+
+                if (symlink(*i, path) >= 0) {
+                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
+
+                        free(path);
+                        continue;
+                }
+
+                if (errno == EEXIST) {
+                        char *dest = NULL;
+
+                        q = readlink_and_make_absolute(path, &dest);
+
+                        if (q < 0 && errno != ENOENT) {
+                                free(path);
+
+                                if (r == 0)
+                                        r = q;
+
+                                continue;
+                        }
+
+                        if (q >= 0 && path_equal(dest, *i)) {
+                                free(dest);
+                                free(path);
+                                continue;
+                        }
+
+                        free(dest);
+
+                        if (force) {
+                                unlink(path);
+
+                                if (symlink(*i, path) >= 0) {
+
+                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+                                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
+
+                                        free(path);
+                                        continue;
+                                }
+                        }
+
+                        if (r == 0)
+                                r = -EEXIST;
+                } else {
+                        if (r == 0)
+                                r = -errno;
+                }
+
+                free(path);
+        }
+
+                finish:
+        lookup_paths_free(&paths);
+        free(config_path);
+
+        return r;
+}
+
+void unit_file_list_free(Hashmap *h) {
+        UnitFileList *i;
+
+        while ((i = hashmap_steal_first(h))) {
+                free(i->path);
+                free(i);
+        }
+
+        hashmap_free(h);
+}
+
+void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
+        unsigned i;
+
+        assert(changes || n_changes == 0);
+
+        if (!changes)
+                return;
+
+        for (i = 0; i < n_changes; i++) {
+                free(changes[i].path);
+                free(changes[i].source);
+        }
+
+        free(changes);
+}
+
+static void install_info_free(InstallInfo *i) {
+        assert(i);
+
+        free(i->name);
+        free(i->path);
+        strv_free(i->aliases);
+        strv_free(i->wanted_by);
+        free(i);
+}
+
+static void install_info_hashmap_free(Hashmap *m) {
+        InstallInfo *i;
+
+        if (!m)
+                return;
+
+        while ((i = hashmap_steal_first(m)))
+                install_info_free(i);
+
+        hashmap_free(m);
+}
+
+static void install_context_done(InstallContext *c) {
+        assert(c);
+
+        install_info_hashmap_free(c->will_install);
+        install_info_hashmap_free(c->have_installed);
+
+        c->will_install = c->have_installed = NULL;
+}
+
+static int install_info_add(
+                InstallContext *c,
+                const char *name,
+                const char *path) {
+        InstallInfo *i = NULL;
+        int r;
+
+        assert(c);
+        assert(name || path);
+
+        if (!name)
+                name = file_name_from_path(path);
+
+        if (!unit_name_is_valid_no_type(name, true))
+                return -EINVAL;
+
+        if (hashmap_get(c->have_installed, name) ||
+            hashmap_get(c->will_install, name))
+                return 0;
+
+        r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
+        if (r < 0)
+                return r;
+
+        i = new0(InstallInfo, 1);
+        if (!i)
+                return -ENOMEM;
+
+        i->name = strdup(name);
+        if (!i->name) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (path) {
+                i->path = strdup(path);
+                if (!i->path) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        r = hashmap_put(c->will_install, i->name, i);
+        if (r < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        if (i)
+                install_info_free(i);
+
+        return r;
+}
+
+static int install_info_add_auto(
+                InstallContext *c,
+                const char *name_or_path) {
+
+        assert(c);
+        assert(name_or_path);
+
+        if (path_is_absolute(name_or_path))
+                return install_info_add(c, NULL, name_or_path);
+        else
+                return install_info_add(c, name_or_path, NULL);
+}
+
+static int config_parse_also(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char *w;
+        size_t l;
+        char *state;
+        InstallContext *c = data;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                char *n;
+                int r;
+
+                n = strndup(w, l);
+                if (!n)
+                        return -ENOMEM;
+
+                r = install_info_add(c, n, NULL);
+                if (r < 0) {
+                        free(n);
+                        return r;
+                }
+
+                free(n);
+        }
+
+        return 0;
+}
+
+static int unit_file_load(
+                InstallContext *c,
+                InstallInfo *info,
+                const char *path,
+                bool allow_symlink) {
+
+        const ConfigTableItem items[] = {
+                { "Install", "Alias",    config_parse_strv, 0, &info->aliases   },
+                { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
+                { "Install", "Also",     config_parse_also, 0, c                },
+                { NULL, NULL, NULL, 0, NULL }
+        };
+
+        int fd;
+        FILE *f;
+        int r;
+
+        assert(c);
+        assert(info);
+        assert(path);
+
+        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
+        if (fd < 0)
+                return -errno;
+
+        f = fdopen(fd, "re");
+        if (!f) {
+                close_nointr_nofail(fd);
+                return -ENOMEM;
+        }
+
+        r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
+        fclose(f);
+        if (r < 0)
+                return r;
+
+        return strv_length(info->aliases) + strv_length(info->wanted_by);
+}
+
+static int unit_file_search(
+                InstallContext *c,
+                InstallInfo *info,
+                LookupPaths *paths,
+                const char *root_dir,
+                bool allow_symlink) {
+
+        char **p;
+        int r;
+
+        assert(c);
+        assert(info);
+        assert(paths);
+
+        if (info->path)
+                return unit_file_load(c, info, info->path, allow_symlink);
+
+        assert(info->name);
+
+        STRV_FOREACH(p, paths->unit_path) {
+                char *path = NULL;
+
+                if (isempty(root_dir))
+                        asprintf(&path, "%s/%s", *p, info->name);
+                else
+                        asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
+
+                if (!path)
+                        return -ENOMEM;
+
+                r = unit_file_load(c, info, path, allow_symlink);
+
+                if (r >= 0)
+                        info->path = path;
+                else
+                        free(path);
+
+                if (r != -ENOENT && r != -ELOOP)
+                        return r;
+        }
+
+        return -ENOENT;
+}
+
+static int unit_file_can_install(
+                LookupPaths *paths,
+                const char *root_dir,
+                const char *name,
+                bool allow_symlink) {
+
+        InstallContext c;
+        InstallInfo *i;
+        int r;
+
+        assert(paths);
+        assert(name);
+
+        zero(c);
+
+        r = install_info_add_auto(&c, name);
+        if (r < 0)
+                return r;
+
+        assert_se(i = hashmap_first(c.will_install));
+
+        r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
+
+        if (r >= 0)
+                r = strv_length(i->aliases) + strv_length(i->wanted_by);
+
+        install_context_done(&c);
+
+        return r;
+}
+
+static int create_symlink(
+                const char *old_path,
+                const char *new_path,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        char *dest;
+        int r;
+
+        assert(old_path);
+        assert(new_path);
+
+        mkdir_parents(new_path, 0755);
+
+        if (symlink(old_path, new_path) >= 0) {
+                add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+                return 0;
+        }
+
+        if (errno != EEXIST)
+                return -errno;
+
+        r = readlink_and_make_absolute(new_path, &dest);
+        if (r < 0)
+                return r;
+
+        if (path_equal(dest, old_path)) {
+                free(dest);
+                return 0;
+        }
+
+        free(dest);
+
+        if (force)
+                return -EEXIST;
+
+        unlink(new_path);
+
+        if (symlink(old_path, new_path) >= 0) {
+                add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
+                add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+                return 0;
+        }
+
+        return -errno;
+}
+
+static int install_info_symlink_alias(
+                InstallInfo *i,
+                const char *config_path,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        char **s;
+        int r = 0, q;
+
+        assert(i);
+        assert(config_path);
+
+        STRV_FOREACH(s, i->aliases) {
+                char *alias_path;
+
+                alias_path = path_make_absolute(*s, config_path);
+
+                if (!alias_path)
+                        return -ENOMEM;
+
+                q = create_symlink(i->path, alias_path, force, changes, n_changes);
+                free(alias_path);
+
+                if (r == 0)
+                        r = q;
+        }
+
+        return r;
+}
+
+static int install_info_symlink_wants(
+                InstallInfo *i,
+                const char *config_path,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        char **s;
+        int r = 0, q;
+
+        assert(i);
+        assert(config_path);
+
+        STRV_FOREACH(s, i->wanted_by) {
+                char *path;
+
+                if (!unit_name_is_valid_no_type(*s, true)) {
+                        r = -EINVAL;
+                        continue;
+                }
+
+                if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
+                        return -ENOMEM;
+
+                q = create_symlink(i->path, path, force, changes, n_changes);
+                free(path);
+
+                if (r == 0)
+                        r = q;
+        }
+
+        return r;
+}
+
+static int install_info_symlink_link(
+                InstallInfo *i,
+                LookupPaths *paths,
+                const char *config_path,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        int r;
+        char *path;
+
+        assert(i);
+        assert(paths);
+        assert(config_path);
+        assert(i->path);
+
+        r = in_search_path(i->path, paths->unit_path);
+        if (r != 0)
+                return r;
+
+        if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
+                return -ENOMEM;
+
+        r = create_symlink(i->path, path, force, changes, n_changes);
+        free(path);
+
+        return r;
+}
+
+static int install_info_apply(
+                InstallInfo *i,
+                LookupPaths *paths,
+                const char *config_path,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        int r, q;
+
+        assert(i);
+        assert(paths);
+        assert(config_path);
+
+        r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
+
+        q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+        q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+        return r;
+}
+
+static int install_context_apply(
+                InstallContext *c,
+                LookupPaths *paths,
+                const char *config_path,
+                const char *root_dir,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        InstallInfo *i;
+        int r = 0, q;
+
+        assert(c);
+        assert(paths);
+        assert(config_path);
+
+        while ((i = hashmap_first(c->will_install))) {
+
+                q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
+                if (q < 0)
+                        return q;
+
+                assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
+
+                q = unit_file_search(c, i, paths, root_dir, false);
+                if (q < 0) {
+                        if (r >= 0)
+                                r = q;
+
+                        return r;
+                } else if (r >= 0)
+                        r += q;
+
+                q = install_info_apply(i, paths, config_path, force, changes, n_changes);
+                if (r >= 0 && q < 0)
+                        r = q;
+        }
+
+        return r;
+}
+
+static int install_context_mark_for_removal(
+                InstallContext *c,
+                LookupPaths *paths,
+                Set **remove_symlinks_to,
+                const char *config_path,
+                const char *root_dir) {
+
+        InstallInfo *i;
+        int r = 0, q;
+
+        assert(c);
+        assert(paths);
+        assert(config_path);
+
+        /* Marks all items for removal */
+
+        while ((i = hashmap_first(c->will_install))) {
+
+                q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
+                if (q < 0)
+                        return q;
+
+                assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
+
+                q = unit_file_search(c, i, paths, root_dir, false);
+                if (q < 0) {
+                        if (r >= 0)
+                                r = q;
+
+                        return r;
+                } else if (r >= 0)
+                        r += q;
+
+                q = mark_symlink_for_removal(remove_symlinks_to, i->name);
+                if (r >= 0 && q < 0)
+                        r = q;
+        }
+
+        return r;
+}
+
+int unit_file_enable(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        LookupPaths paths;
+        InstallContext c;
+        char **i, *config_path = NULL;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        zero(paths);
+        zero(c);
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                goto finish;
+
+        STRV_FOREACH(i, files) {
+                r = install_info_add_auto(&c, *i);
+                if (r < 0)
+                        goto finish;
+        }
+
+        /* This will return the number of symlink rules that were
+        supposed to be created, not the ones actually created. This is
+        useful to determine whether the passed files hat any
+        installation data at all. */
+        r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
+
+finish:
+        install_context_done(&c);
+        lookup_paths_free(&paths);
+        free(config_path);
+
+        return r;
+}
+
+int unit_file_disable(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        LookupPaths paths;
+        InstallContext c;
+        char **i, *config_path = NULL;
+        Set *remove_symlinks_to = NULL;
+        int r, q;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        zero(paths);
+        zero(c);
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                goto finish;
+
+        STRV_FOREACH(i, files) {
+                r = install_info_add_auto(&c, *i);
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
+
+        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+finish:
+        install_context_done(&c);
+        lookup_paths_free(&paths);
+        set_free_free(remove_symlinks_to);
+        free(config_path);
+
+        return r;
+}
+
+int unit_file_reenable(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        LookupPaths paths;
+        InstallContext c;
+        char **i, *config_path = NULL;
+        Set *remove_symlinks_to = NULL;
+        int r, q;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        zero(paths);
+        zero(c);
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                goto finish;
+
+        STRV_FOREACH(i, files) {
+                r = mark_symlink_for_removal(&remove_symlinks_to, *i);
+                if (r < 0)
+                        goto finish;
+
+                r = install_info_add_auto(&c, *i);
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+
+        /* Returns number of symlinks that where supposed to be installed. */
+        q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+finish:
+        lookup_paths_free(&paths);
+        install_context_done(&c);
+        set_free_free(remove_symlinks_to);
+        free(config_path);
+
+        return r;
+}
+
+UnitFileState unit_file_get_state(
+                UnitFileScope scope,
+                const char *root_dir,
+                const char *name) {
+
+        LookupPaths paths;
+        UnitFileState state = _UNIT_FILE_STATE_INVALID;
+        char **i, *path = NULL;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(name);
+
+        zero(paths);
+
+        if (root_dir && scope != UNIT_FILE_SYSTEM)
+                return -EINVAL;
+
+        if (!unit_name_is_valid_no_type(name, true))
+                return -EINVAL;
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, paths.unit_path) {
+                struct stat st;
+
+                free(path);
+                path = NULL;
+
+                if (root_dir)
+                        asprintf(&path, "%s/%s/%s", root_dir, *i, name);
+                else
+                        asprintf(&path, "%s/%s", *i, name);
+
+                if (!path) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (lstat(path, &st) < 0) {
+                        r = -errno;
+                        if (errno == ENOENT)
+                                continue;
+
+                        goto finish;
+                }
+
+                if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                        r = -ENOENT;
+                        goto finish;
+                }
+
+                r = null_or_empty_path(path);
+                if (r < 0 && r != -ENOENT)
+                        goto finish;
+                else if (r > 0) {
+                        state = path_startswith(*i, "/run") ?
+                                UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+                        r = 0;
+                        goto finish;
+                }
+
+                r = find_symlinks_in_scope(scope, root_dir, name, &state);
+                if (r < 0) {
+                        goto finish;
+                } else if (r > 0) {
+                        r = 0;
+                        goto finish;
+                }
+
+                r = unit_file_can_install(&paths, root_dir, path, true);
+                if (r < 0 && errno != -ENOENT)
+                        goto finish;
+                else if (r > 0) {
+                        state = UNIT_FILE_DISABLED;
+                        r = 0;
+                        goto finish;
+                } else if (r == 0) {
+                        state = UNIT_FILE_STATIC;
+                        r = 0;
+                        goto finish;
+                }
+        }
+
+finish:
+        lookup_paths_free(&paths);
+        free(path);
+
+        return r < 0 ? r : state;
+}
+
+int unit_file_query_preset(UnitFileScope scope, const char *name) {
+        char **files, **i;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(name);
+
+        if (scope == UNIT_FILE_SYSTEM)
+                r = conf_files_list(&files, ".preset",
+                                    "/etc/systemd/system.preset",
+                                    "/usr/local/lib/systemd/system.preset",
+                                    "/usr/lib/systemd/system.preset",
+                                    "/lib/systemd/system.preset",
+                                    NULL);
+        else if (scope == UNIT_FILE_GLOBAL)
+                r = conf_files_list(&files, ".preset",
+                                    "/etc/systemd/user.preset",
+                                    "/usr/local/lib/systemd/user.preset",
+                                    "/usr/lib/systemd/user.preset",
+                                    NULL);
+        else
+                return 1;
+
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, files) {
+                FILE *f;
+
+                f = fopen(*i, "re");
+                if (!f) {
+                        if (errno == ENOENT)
+                                continue;
+
+                        r = -errno;
+                        goto finish;
+                }
+
+                for (;;) {
+                        char line[LINE_MAX], *l;
+
+                        if (!fgets(line, sizeof(line), f))
+                                break;
+
+                        l = strstrip(line);
+                        if (!*l)
+                                continue;
+
+                        if (strchr(COMMENTS, *l))
+                                continue;
+
+                        if (first_word(l, "enable")) {
+                                l += 6;
+                                l += strspn(l, WHITESPACE);
+
+                                if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
+                                        r = 1;
+                                        fclose(f);
+                                        goto finish;
+                                }
+                        } else if (first_word(l, "disable")) {
+                                l += 7;
+                                l += strspn(l, WHITESPACE);
+
+                                if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
+                                        r = 0;
+                                        fclose(f);
+                                        goto finish;
+                                }
+                        } else
+                                log_debug("Couldn't parse line '%s'", l);
+                }
+
+                fclose(f);
+        }
+
+        /* Default is "enable" */
+        r = 1;
+
+finish:
+        strv_free(files);
+
+        return r;
+}
+
+int unit_file_preset(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char *files[],
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        LookupPaths paths;
+        InstallContext plus, minus;
+        char **i, *config_path = NULL;
+        Set *remove_symlinks_to = NULL;
+        int r, q;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        zero(paths);
+        zero(plus);
+        zero(minus);
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                goto finish;
+
+        STRV_FOREACH(i, files) {
+
+                if (!unit_name_is_valid_no_type(*i, true)) {
+                        r = -EINVAL;
+                        goto finish;
+                }
+
+                r = unit_file_query_preset(scope, *i);
+                if (r < 0)
+                        goto finish;
+
+                if (r)
+                        r = install_info_add_auto(&plus, *i);
+                else
+                        r = install_info_add_auto(&minus, *i);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
+
+        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+        /* Returns number of symlinks that where supposed to be installed. */
+        q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
+        if (r == 0)
+                r = q;
+
+finish:
+        lookup_paths_free(&paths);
+        install_context_done(&plus);
+        install_context_done(&minus);
+        set_free_free(remove_symlinks_to);
+        free(config_path);
+
+        return r;
+}
+
+int unit_file_get_list(
+                UnitFileScope scope,
+                const char *root_dir,
+                Hashmap *h) {
+
+        LookupPaths paths;
+        char **i, *buf = NULL;
+        DIR *d = NULL;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(h);
+
+        zero(paths);
+
+        if (root_dir && scope != UNIT_FILE_SYSTEM)
+                return -EINVAL;
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, paths.unit_path) {
+                struct dirent buffer, *de;
+                const char *units_dir;
+
+                free(buf);
+                buf = NULL;
+
+                if (root_dir) {
+                        if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+                        units_dir = buf;
+                } else
+                        units_dir = *i;
+
+                if (d)
+                        closedir(d);
+
+                d = opendir(units_dir);
+                if (!d) {
+                        if (errno == ENOENT)
+                                continue;
+
+                        r = -errno;
+                        goto finish;
+                }
+
+                for (;;) {
+                        UnitFileList *f;
+
+                        r = readdir_r(d, &buffer, &de);
+                        if (r != 0) {
+                                r = -r;
+                                goto finish;
+                        }
+
+                        if (!de)
+                                break;
+
+                        if (ignore_file(de->d_name))
+                                continue;
+
+                        if (!unit_name_is_valid_no_type(de->d_name, true))
+                                continue;
+
+                        if (hashmap_get(h, de->d_name))
+                                continue;
+
+                        r = dirent_ensure_type(d, de);
+                        if (r < 0) {
+                                if (r == -ENOENT)
+                                        continue;
+
+                                goto finish;
+                        }
+
+                        if (de->d_type != DT_LNK && de->d_type != DT_REG)
+                                continue;
+
+                        f = new0(UnitFileList, 1);
+                        if (!f) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        f->path = path_make_absolute(de->d_name, units_dir);
+                        if (!f->path) {
+                                free(f);
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        r = null_or_empty_path(f->path);
+                        if (r < 0 && r != -ENOENT) {
+                                free(f->path);
+                                free(f);
+                                goto finish;
+                        } else if (r > 0) {
+                                f->state =
+                                        path_startswith(*i, "/run") ?
+                                        UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+                                goto found;
+                        }
+
+                        r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
+                        if (r < 0) {
+                                free(f->path);
+                                free(f);
+                                goto finish;
+                        } else if (r > 0)
+                                goto found;
+
+                        r = unit_file_can_install(&paths, root_dir, f->path, true);
+                        if (r < 0) {
+                                free(f->path);
+                                free(f);
+                                goto finish;
+                        } else if (r > 0) {
+                                f->state = UNIT_FILE_DISABLED;
+                                goto found;
+                        } else {
+                                f->state = UNIT_FILE_STATIC;
+                                goto found;
+                        }
+
+                        free(f->path);
+                        free(f);
+                        continue;
+
+                found:
+                        r = hashmap_put(h, file_name_from_path(f->path), f);
+                        if (r < 0) {
+                                free(f->path);
+                                free(f);
+                                goto finish;
+                        }
+                }
+        }
+
+finish:
+        lookup_paths_free(&paths);
+        free(buf);
+
+        if (d)
+                closedir(d);
+
+        return r;
+}
+
+static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
+        [UNIT_FILE_ENABLED] = "enabled",
+        [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtie",
+        [UNIT_FILE_LINKED] = "linked",
+        [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
+        [UNIT_FILE_MASKED] = "masked",
+        [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
+        [UNIT_FILE_STATIC] = "static",
+        [UNIT_FILE_DISABLED] = "disabled"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
+
+static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
+        [UNIT_FILE_SYMLINK] = "symlink",
+        [UNIT_FILE_UNLINK] = "unlink",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
diff --git a/src/shared/install.h b/src/shared/install.h
new file mode 100644
index 0000000..d365c01
--- /dev/null
+++ b/src/shared/install.h
@@ -0,0 +1,89 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooinstallhfoo
+#define fooinstallhfoo
+
+/***
+  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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "hashmap.h"
+
+typedef enum UnitFileScope {
+        UNIT_FILE_SYSTEM,
+        UNIT_FILE_GLOBAL,
+        UNIT_FILE_USER,
+        _UNIT_FILE_SCOPE_MAX,
+        _UNIT_FILE_SCOPE_INVALID = -1
+} UnitFileScope;
+
+typedef enum UnitFileState {
+        UNIT_FILE_ENABLED,
+        UNIT_FILE_ENABLED_RUNTIME,
+        UNIT_FILE_LINKED,
+        UNIT_FILE_LINKED_RUNTIME,
+        UNIT_FILE_MASKED,
+        UNIT_FILE_MASKED_RUNTIME,
+        UNIT_FILE_STATIC,
+        UNIT_FILE_DISABLED,
+        _UNIT_FILE_STATE_MAX,
+        _UNIT_FILE_STATE_INVALID = -1
+} UnitFileState;
+
+typedef enum UnitFileChangeType {
+        UNIT_FILE_SYMLINK,
+        UNIT_FILE_UNLINK,
+        _UNIT_FILE_CHANGE_TYPE_MAX,
+        _UNIT_FILE_CHANGE_TYPE_INVALID = -1
+} UnitFileChangeType;
+
+typedef struct UnitFileChange {
+        UnitFileChangeType type;
+        char *path;
+        char *source;
+} UnitFileChange;
+
+typedef struct UnitFileList {
+        char *path;
+        UnitFileState state;
+} UnitFileList;
+
+int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
+int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
+int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
+int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
+int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
+int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
+int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
+
+UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename);
+
+int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
+
+void unit_file_list_free(Hashmap *h);
+void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
+
+int unit_file_query_preset(UnitFileScope scope, const char *name);
+
+const char *unit_file_state_to_string(UnitFileState s);
+UnitFileState unit_file_state_from_string(const char *s);
+
+const char *unit_file_change_type_to_string(UnitFileChangeType s);
+UnitFileChangeType unit_file_change_type_from_string(const char *s);
+
+#endif
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
new file mode 100644
index 0000000..fedb453
--- /dev/null
+++ b/src/shared/logs-show.c
@@ -0,0 +1,677 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/poll.h>
+#include <string.h>
+
+#include "logs-show.h"
+#include "log.h"
+#include "util.h"
+
+#define PRINT_THRESHOLD 128
+
+static bool contains_unprintable(const void *p, size_t l) {
+        const char *j;
+
+        for (j = p; j < (const char *) p + l; j++)
+                if (*j < ' ' || *j >= 127)
+                        return true;
+
+        return false;
+}
+
+static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
+        size_t fl, nl;
+        void *buf;
+
+        assert(data);
+        assert(field);
+        assert(target);
+        assert(target_size);
+
+        fl = strlen(field);
+        if (length < fl)
+                return 0;
+
+        if (memcmp(data, field, fl))
+                return 0;
+
+        nl = length - fl;
+        buf = malloc(nl+1);
+        memcpy(buf, (const char*) data + fl, nl);
+        ((char*)buf)[nl] = 0;
+        if (!buf) {
+                log_error("Out of memory");
+                return -ENOMEM;
+        }
+
+        free(*target);
+        *target = buf;
+        *target_size = nl;
+
+        return 1;
+}
+
+static bool shall_print(bool show_all, char *p, size_t l) {
+        if (show_all)
+                return true;
+
+        if (l > PRINT_THRESHOLD)
+                return false;
+
+        if (contains_unprintable(p, l))
+                return false;
+
+        return true;
+}
+
+static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) {
+        int r;
+        const void *data;
+        size_t length;
+        size_t n = 0;
+        char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
+        size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0;
+
+        assert(j);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+
+                r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_COMM=", &comm, &comm_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_PID=", &pid, &pid_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
+                if (r < 0)
+                        goto finish;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "MESSAGE=", &message, &message_len);
+                if (r < 0)
+                        goto finish;
+        }
+
+        if (!message) {
+                r = 0;
+                goto finish;
+        }
+
+        if (monotonic_mode) {
+                uint64_t t;
+                sd_id128_t boot_id;
+
+                r = -ENOENT;
+
+                if (monotonic)
+                        r = safe_atou64(monotonic, &t);
+
+                if (r < 0)
+                        r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
+
+                if (r < 0) {
+                        log_error("Failed to get monotonic: %s", strerror(-r));
+                        goto finish;
+                }
+
+                printf("[%5llu.%06llu]",
+                       (unsigned long long) (t / USEC_PER_SEC),
+                       (unsigned long long) (t % USEC_PER_SEC));
+
+                n += 1 + 5 + 1 + 6 + 1;
+
+        } else {
+                char buf[64];
+                uint64_t x;
+                time_t t;
+                struct tm tm;
+
+                r = -ENOENT;
+
+                if (realtime)
+                        r = safe_atou64(realtime, &x);
+
+                if (r < 0)
+                        r = sd_journal_get_realtime_usec(j, &x);
+
+                if (r < 0) {
+                        log_error("Failed to get realtime: %s", strerror(-r));
+                        goto finish;
+                }
+
+                t = (time_t) (x / USEC_PER_SEC);
+                if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
+                        log_error("Failed to format time.");
+                        goto finish;
+                }
+
+                fputs(buf, stdout);
+                n += strlen(buf);
+        }
+
+        if (hostname && shall_print(show_all, hostname, hostname_len)) {
+                printf(" %.*s", (int) hostname_len, hostname);
+                n += hostname_len + 1;
+        }
+
+        if (identifier && shall_print(show_all, identifier, identifier_len)) {
+                printf(" %.*s", (int) identifier_len, identifier);
+                n += identifier_len + 1;
+        } else if (comm && shall_print(show_all, comm, comm_len)) {
+                printf(" %.*s", (int) comm_len, comm);
+                n += comm_len + 1;
+        } else
+                putchar(' ');
+
+        if (pid && shall_print(show_all, pid, pid_len)) {
+                printf("[%.*s]", (int) pid_len, pid);
+                n += pid_len + 2;
+        } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) {
+                printf("[%.*s]", (int) fake_pid_len, fake_pid);
+                n += fake_pid_len + 2;
+        }
+
+        if (show_all)
+                printf(": %.*s\n", (int) message_len, message);
+        else if (contains_unprintable(message, message_len)) {
+                char bytes[FORMAT_BYTES_MAX];
+                printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
+        } else if (message_len + n < n_columns)
+                printf(": %.*s\n", (int) message_len, message);
+        else if (n < n_columns) {
+                char *e;
+
+                e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
+
+                if (!e)
+                        printf(": %.*s\n", (int) message_len, message);
+                else
+                        printf(": %s\n", e);
+
+                free(e);
+        } else
+                fputs("\n", stdout);
+
+        r = 0;
+
+finish:
+        free(hostname);
+        free(identifier);
+        free(comm);
+        free(pid);
+        free(fake_pid);
+        free(message);
+        free(monotonic);
+        free(realtime);
+
+        return r;
+}
+
+static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
+        return output_short(j, line, n_columns, show_all, false);
+}
+
+static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
+        return output_short(j, line, n_columns, show_all, true);
+}
+
+static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
+        const void *data;
+        size_t length;
+        char *cursor;
+        uint64_t realtime;
+        char ts[FORMAT_TIMESTAMP_MAX];
+        int r;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_cursor(j, &cursor);
+        if (r < 0) {
+                log_error("Failed to get cursor: %s", strerror(-r));
+                return r;
+        }
+
+        printf("%s [%s]\n",
+               format_timestamp(ts, sizeof(ts), realtime),
+               cursor);
+
+        free(cursor);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+                if (!show_all && (length > PRINT_THRESHOLD ||
+                                  contains_unprintable(data, length))) {
+                        const char *c;
+                        char bytes[FORMAT_BYTES_MAX];
+
+                        c = memchr(data, '=', length);
+                        if (!c) {
+                                log_error("Invalid field.");
+                                return -EINVAL;
+                        }
+
+                        printf("\t%.*s=[%s blob data]\n",
+                               (int) (c - (const char*) data),
+                               (const char*) data,
+                               format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
+                } else
+                        printf("\t%.*s\n", (int) length, (const char*) data);
+        }
+
+        return 0;
+}
+
+static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
+        sd_id128_t boot_id;
+        char sid[33];
+        int r;
+        usec_t realtime, monotonic;
+        char *cursor;
+        const void *data;
+        size_t length;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
+        if (r < 0) {
+                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_cursor(j, &cursor);
+        if (r < 0) {
+                log_error("Failed to get cursor: %s", strerror(-r));
+                return r;
+        }
+
+        printf("__CURSOR=%s\n"
+               "__REALTIME_TIMESTAMP=%llu\n"
+               "__MONOTONIC_TIMESTAMP=%llu\n"
+               "_BOOT_ID=%s\n",
+               cursor,
+               (unsigned long long) realtime,
+               (unsigned long long) monotonic,
+               sd_id128_to_string(boot_id, sid));
+
+        free(cursor);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+
+                /* We already printed the boot id, from the data in
+                 * the header, hence let's suppress it here */
+                if (length >= 9 &&
+                    memcmp(data, "_BOOT_ID=", 9) == 0)
+                        continue;
+
+                if (contains_unprintable(data, length)) {
+                        const char *c;
+                        uint64_t le64;
+
+                        c = memchr(data, '=', length);
+                        if (!c) {
+                                log_error("Invalid field.");
+                                return -EINVAL;
+                        }
+
+                        fwrite(data, c - (const char*) data, 1, stdout);
+                        fputc('\n', stdout);
+                        le64 = htole64(length - (c - (const char*) data) - 1);
+                        fwrite(&le64, sizeof(le64), 1, stdout);
+                        fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
+                } else
+                        fwrite(data, length, 1, stdout);
+
+                fputc('\n', stdout);
+        }
+
+        fputc('\n', stdout);
+
+        return 0;
+}
+
+static void json_escape(const char* p, size_t l) {
+
+        if (contains_unprintable(p, l)) {
+                bool not_first = false;
+
+                fputs("[ ", stdout);
+
+                while (l > 0) {
+                        if (not_first)
+                                printf(", %u", (uint8_t) *p);
+                        else {
+                                not_first = true;
+                                printf("%u", (uint8_t) *p);
+                        }
+
+                        p++;
+                        l--;
+                }
+
+                fputs(" ]", stdout);
+        } else {
+                fputc('\"', stdout);
+
+                while (l > 0) {
+                        if (*p == '"' || *p == '\\') {
+                                fputc('\\', stdout);
+                                fputc(*p, stdout);
+                        } else
+                                fputc(*p, stdout);
+
+                        p++;
+                        l--;
+                }
+
+                fputc('\"', stdout);
+        }
+}
+
+static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
+        uint64_t realtime, monotonic;
+        char *cursor;
+        const void *data;
+        size_t length;
+        sd_id128_t boot_id;
+        char sid[33];
+        int r;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
+        if (r < 0) {
+                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_cursor(j, &cursor);
+        if (r < 0) {
+                log_error("Failed to get cursor: %s", strerror(-r));
+                return r;
+        }
+
+        if (line == 1)
+                fputc('\n', stdout);
+        else
+                fputs(",\n", stdout);
+
+        printf("{\n"
+               "\t\"__CURSOR\" : \"%s\",\n"
+               "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
+               "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
+               "\t\"_BOOT_ID\" : \"%s\"",
+               cursor,
+               (unsigned long long) realtime,
+               (unsigned long long) monotonic,
+               sd_id128_to_string(boot_id, sid));
+
+        free(cursor);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+                const char *c;
+
+                /* We already printed the boot id, from the data in
+                 * the header, hence let's suppress it here */
+                if (length >= 9 &&
+                    memcmp(data, "_BOOT_ID=", 9) == 0)
+                        continue;
+
+                c = memchr(data, '=', length);
+                if (!c) {
+                        log_error("Invalid field.");
+                        return -EINVAL;
+                }
+
+                fputs(",\n\t", stdout);
+                json_escape(data, c - (const char*) data);
+                fputs(" : ", stdout);
+                json_escape(c + 1, length - (c - (const char*) data) - 1);
+        }
+
+        fputs("\n}", stdout);
+        fflush(stdout);
+
+        return 0;
+}
+
+static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
+        const void *data;
+        size_t l;
+        int r;
+
+        assert(j);
+
+        r = sd_journal_get_data(j, "MESSAGE", &data, &l);
+        if (r < 0) {
+                log_error("Failed to get data: %s", strerror(-r));
+                return r;
+        }
+
+        assert(l >= 8);
+
+        fwrite((const char*) data + 8, 1, l - 8, stdout);
+        putchar('\n');
+
+        return 0;
+}
+
+static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = {
+        [OUTPUT_SHORT] = output_short_realtime,
+        [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
+        [OUTPUT_VERBOSE] = output_verbose,
+        [OUTPUT_EXPORT] = output_export,
+        [OUTPUT_JSON] = output_json,
+        [OUTPUT_CAT] = output_cat
+};
+
+int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) {
+        assert(mode >= 0);
+        assert(mode < _OUTPUT_MODE_MAX);
+
+        if (n_columns <= 0)
+                n_columns = columns();
+
+        return output_funcs[mode](j, line, n_columns, show_all);
+}
+
+int show_journal_by_unit(
+                const char *unit,
+                OutputMode mode,
+                unsigned n_columns,
+                usec_t not_before,
+                unsigned how_many,
+                bool show_all,
+                bool follow) {
+
+        char *m = NULL;
+        sd_journal *j;
+        int r;
+        int fd;
+        unsigned line = 0;
+        bool need_seek = false;
+
+        assert(mode >= 0);
+        assert(mode < _OUTPUT_MODE_MAX);
+        assert(unit);
+
+        if (!endswith(unit, ".service") &&
+            !endswith(unit, ".socket") &&
+            !endswith(unit, ".mount") &&
+            !endswith(unit, ".swap"))
+                return 0;
+
+        if (how_many <= 0)
+                return 0;
+
+        if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
+        if (r < 0)
+                goto finish;
+
+        fd = sd_journal_get_fd(j);
+        if (fd < 0)
+                goto finish;
+
+        r = sd_journal_add_match(j, m, strlen(m));
+        if (r < 0)
+                goto finish;
+
+        r = sd_journal_seek_tail(j);
+        if (r < 0)
+                goto finish;
+
+        r = sd_journal_previous_skip(j, how_many);
+        if (r < 0)
+                goto finish;
+
+        if (mode == OUTPUT_JSON) {
+                fputc('[', stdout);
+                fflush(stdout);
+        }
+
+        for (;;) {
+                for (;;) {
+                        usec_t usec;
+
+                        if (need_seek) {
+                                r = sd_journal_next(j);
+                                if (r < 0)
+                                        goto finish;
+                        }
+
+                        if (r == 0)
+                                break;
+
+                        need_seek = true;
+
+                        if (not_before > 0) {
+                                r = sd_journal_get_monotonic_usec(j, &usec, NULL);
+
+                                /* -ESTALE is returned if the
+                                   timestamp is not from this boot */
+                                if (r == -ESTALE)
+                                        continue;
+                                else if (r < 0)
+                                        goto finish;
+
+                                if (usec < not_before)
+                                        continue;
+                        }
+
+                        line ++;
+
+                        r = output_journal(j, mode, line, n_columns, show_all);
+                        if (r < 0)
+                                goto finish;
+                }
+
+                if (!follow)
+                        break;
+
+                r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
+                if (r < 0)
+                        goto finish;
+
+                r = sd_journal_process(j);
+                if (r < 0)
+                        goto finish;
+
+        }
+
+        if (mode == OUTPUT_JSON)
+                fputs("\n]\n", stdout);
+
+finish:
+        if (m)
+                free(m);
+
+        if (j)
+                sd_journal_close(j);
+
+        return r;
+}
+
+static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
+        [OUTPUT_SHORT] = "short",
+        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
+        [OUTPUT_VERBOSE] = "verbose",
+        [OUTPUT_EXPORT] = "export",
+        [OUTPUT_JSON] = "json",
+        [OUTPUT_CAT] = "cat"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h
new file mode 100644
index 0000000..94caed5
--- /dev/null
+++ b/src/shared/logs-show.h
@@ -0,0 +1,56 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologsshowhfoo
+#define foologsshowhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include <systemd/sd-journal.h>
+
+#include "util.h"
+
+typedef enum OutputMode {
+        OUTPUT_SHORT,
+        OUTPUT_SHORT_MONOTONIC,
+        OUTPUT_VERBOSE,
+        OUTPUT_EXPORT,
+        OUTPUT_JSON,
+        OUTPUT_CAT,
+        _OUTPUT_MODE_MAX,
+        _OUTPUT_MODE_INVALID = -1
+} OutputMode;
+
+int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all);
+
+int show_journal_by_unit(
+                const char *unit,
+                OutputMode mode,
+                unsigned n_columns,
+                usec_t not_before,
+                unsigned how_many,
+                bool show_all,
+                bool follow);
+
+const char* output_mode_to_string(OutputMode m);
+OutputMode output_mode_from_string(const char *s);
+
+#endif
diff --git a/src/shared/loopback-setup.c b/src/shared/loopback-setup.c
new file mode 100644
index 0000000..46c1fc8
--- /dev/null
+++ b/src/shared/loopback-setup.c
@@ -0,0 +1,274 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <asm/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "util.h"
+#include "macro.h"
+#include "loopback-setup.h"
+#include "socket-util.h"
+
+#define NLMSG_TAIL(nmsg)                                                \
+        ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) {
+        size_t length;
+        struct rtattr *rta;
+
+        length = RTA_LENGTH(data_length);
+
+        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
+                return -E2BIG;
+
+        rta = NLMSG_TAIL(n);
+        rta->rta_type = type;
+        rta->rta_len = length;
+        memcpy(RTA_DATA(rta), data, data_length);
+        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
+
+        return 0;
+}
+
+static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) {
+
+        for (;;) {
+                ssize_t l;
+
+                if ((l = sendto(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
+                        return l;
+
+                if (errno != EINTR)
+                        return -errno;
+        }
+}
+
+static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) {
+
+        for (;;) {
+                ssize_t l;
+
+                if ((l = recvfrom(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
+                        return l;
+
+                if (errno != EINTR)
+                        return -errno;
+        }
+}
+
+static int add_adresses(int fd, int if_loopback, unsigned *requests) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sa;
+        union {
+                struct nlmsghdr header;
+                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                            NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
+                            RTA_LENGTH(sizeof(struct in6_addr))];
+        } request;
+
+        struct ifaddrmsg *ifaddrmsg;
+        uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
+        int r;
+
+        zero(request);
+
+        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        request.header.nlmsg_type = RTM_NEWADDR;
+        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
+        request.header.nlmsg_seq = *requests + 1;
+
+        ifaddrmsg = NLMSG_DATA(&request.header);
+        ifaddrmsg->ifa_family = AF_INET;
+        ifaddrmsg->ifa_prefixlen = 8;
+        ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
+        ifaddrmsg->ifa_scope = RT_SCOPE_HOST;
+        ifaddrmsg->ifa_index = if_loopback;
+
+        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address))) < 0)
+                return r;
+
+        zero(sa);
+        sa.nl.nl_family = AF_NETLINK;
+
+        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
+                return -errno;
+        (*requests)++;
+
+        if (!socket_ipv6_is_supported())
+                return 0;
+
+        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        request.header.nlmsg_seq = *requests + 1;
+
+        ifaddrmsg->ifa_family = AF_INET6;
+        ifaddrmsg->ifa_prefixlen = 128;
+
+        if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback))) < 0)
+                return r;
+
+        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
+                return -errno;
+        (*requests)++;
+
+        return 0;
+}
+
+static int start_interface(int fd, int if_loopback, unsigned *requests) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sa;
+        union {
+                struct nlmsghdr header;
+                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                            NLMSG_ALIGN(sizeof(struct ifinfomsg))];
+        } request;
+
+        struct ifinfomsg *ifinfomsg;
+
+        zero(request);
+
+        request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+        request.header.nlmsg_type = RTM_NEWLINK;
+        request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+        request.header.nlmsg_seq = *requests + 1;
+
+        ifinfomsg = NLMSG_DATA(&request.header);
+        ifinfomsg->ifi_family = AF_UNSPEC;
+        ifinfomsg->ifi_index = if_loopback;
+        ifinfomsg->ifi_flags = IFF_UP;
+        ifinfomsg->ifi_change = IFF_UP;
+
+        zero(sa);
+        sa.nl.nl_family = AF_NETLINK;
+
+        if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
+                return -errno;
+
+        (*requests)++;
+
+        return 0;
+}
+
+static int read_response(int fd, unsigned requests_max) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } sa;
+        union {
+                struct nlmsghdr header;
+                uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                            NLMSG_ALIGN(sizeof(struct nlmsgerr))];
+        } response;
+
+        ssize_t l;
+        socklen_t sa_len = sizeof(sa);
+        struct nlmsgerr *nlmsgerr;
+
+        if ((l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len)) < 0)
+                return -errno;
+
+        if (sa_len != sizeof(sa.nl) ||
+            sa.nl.nl_family != AF_NETLINK)
+                return -EIO;
+
+        if (sa.nl.nl_pid != 0)
+                return 0;
+
+        if ((size_t) l < sizeof(struct nlmsghdr))
+                return -EIO;
+
+        if (response.header.nlmsg_type != NLMSG_ERROR ||
+            (pid_t) response.header.nlmsg_pid != getpid() ||
+            response.header.nlmsg_seq >= requests_max)
+                return 0;
+
+        if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
+            response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+                return -EIO;
+
+        nlmsgerr = NLMSG_DATA(&response.header);
+
+        if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST) {
+                log_warning("Netlink failure for request %i: %s", response.header.nlmsg_seq, strerror(-nlmsgerr->error));
+                return nlmsgerr->error;
+        }
+
+        return response.header.nlmsg_seq;
+}
+
+int loopback_setup(void) {
+        int r, if_loopback;
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+                struct sockaddr_storage storage;
+        } sa;
+        unsigned requests = 0, i;
+        int fd;
+
+        errno = 0;
+        if ((if_loopback = (int) if_nametoindex("lo")) <= 0)
+                return errno ? -errno : -ENODEV;
+
+        if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
+                return -errno;
+
+        zero(sa);
+        sa.nl.nl_family = AF_NETLINK;
+
+        if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if ((r = add_adresses(fd, if_loopback, &requests)) < 0)
+                goto finish;
+
+        if ((r = start_interface(fd, if_loopback, &requests)) < 0)
+                goto finish;
+
+        for (i = 0; i < requests; i++) {
+                if ((r = read_response(fd, requests)) < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (r < 0)
+                log_warning("Failed to configure loopback device: %s", strerror(-r));
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
diff --git a/src/shared/loopback-setup.h b/src/shared/loopback-setup.h
new file mode 100644
index 0000000..cbb969e
--- /dev/null
+++ b/src/shared/loopback-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooloopbacksetuphfoo
+#define fooloopbacksetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int loopback_setup(void);
+
+#endif
diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c
new file mode 100644
index 0000000..9e84ac0
--- /dev/null
+++ b/src/shared/machine-id-setup.c
@@ -0,0 +1,265 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+
+#include <systemd/sd-id128.h>
+
+#include "machine-id-setup.h"
+#include "macro.h"
+#include "util.h"
+#include "mkdir.h"
+#include "log.h"
+#include "virt.h"
+
+static int shorten_uuid(char destination[36], const char *source) {
+        unsigned i, j;
+
+        for (i = 0, j = 0; i < 36 && j < 32; i++) {
+                int t;
+
+                t = unhexchar(source[i]);
+                if (t < 0)
+                        continue;
+
+                destination[j++] = hexchar(t);
+        }
+
+        if (i == 36 && j == 32) {
+                destination[32] = '\n';
+                destination[33] = 0;
+                return 0;
+        }
+
+        return -EINVAL;
+}
+
+static int generate(char id[34]) {
+        int fd, r;
+        unsigned char *p;
+        sd_id128_t buf;
+        char *q;
+        ssize_t k;
+        const char *vm_id;
+
+        assert(id);
+
+        /* First, try reading the D-Bus machine id, unless it is a symlink */
+        fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd >= 0) {
+
+                k = loop_read(fd, id, 32, false);
+                close_nointr_nofail(fd);
+
+                if (k >= 32) {
+                        id[32] = '\n';
+                        id[33] = 0;
+
+                        log_info("Initializing machine ID from D-Bus machine ID.");
+                        return 0;
+                }
+        }
+
+        /* If that didn't work, see if we are running in qemu/kvm and a
+         * machine ID was passed in via -uuid on the qemu/kvm command
+         * line */
+
+        r = detect_vm(&vm_id);
+        if (r > 0 && streq(vm_id, "kvm")) {
+                char uuid[37];
+
+                fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+                if (fd >= 0) {
+                        k = loop_read(fd, uuid, 36, false);
+                        close_nointr_nofail(fd);
+
+                        if (k >= 36) {
+                                r = shorten_uuid(id, uuid);
+                                if (r >= 0) {
+                                        log_info("Initializing machine ID from KVM UUID");
+                                        return 0;
+                                }
+                        }
+                }
+        }
+
+        /* If that didn't work either, see if we are running in a
+         * container, and a machine ID was passed in via
+         * $container_uuid the way libvirt/LXC does it */
+
+        r = detect_container(NULL);
+        if (r > 0) {
+                FILE *f;
+
+                f = fopen("/proc/1/environ", "re");
+                if (f) {
+                        bool done = false;
+
+                        do {
+                                char line[LINE_MAX];
+                                unsigned i;
+
+                                for (i = 0; i < sizeof(line)-1; i++) {
+                                        int c;
+
+                                        c = getc(f);
+                                        if (_unlikely_(c == EOF)) {
+                                                done = true;
+                                                break;
+                                        } else if (c == 0)
+                                                break;
+
+                                        line[i] = c;
+                                }
+                                line[i] = 0;
+
+                                if (startswith(line, "container_uuid=") &&
+                                    strlen(line + 15) >= 36) {
+                                        r = shorten_uuid(id, line + 15);
+                                        if (r >= 0) {
+                                                log_info("Initializing machine ID from container UUID");
+                                                return 0;
+                                        }
+                                }
+
+                        } while (!done);
+
+                        fclose(f);
+                }
+        }
+
+        /* If that didn't work, generate a random machine id */
+        r = sd_id128_randomize(&buf);
+        if (r < 0) {
+                log_error("Failed to open /dev/urandom: %s", strerror(-r));
+                return r;
+        }
+
+        for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
+                q[0] = hexchar(*p >> 4);
+                q[1] = hexchar(*p & 15);
+        }
+
+        id[32] = '\n';
+        id[33] = 0;
+
+        log_info("Initializing machine ID from random generator.");
+
+        return 0;
+}
+
+int machine_id_setup(void) {
+        int fd, r;
+        bool writable;
+        struct stat st;
+        char id[34]; /* 32 + \n + \0 */
+        mode_t m;
+
+        m = umask(0000);
+
+        /* We create this 0444, to indicate that this isn't really
+         * something you should ever modify. Of course, since the file
+         * will be owned by root it doesn't matter much, but maybe
+         * people look. */
+
+        fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
+        if (fd >= 0)
+                writable = true;
+        else {
+                fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        umask(m);
+                        log_error("Cannot open /etc/machine-id: %m");
+                        return -errno;
+                }
+
+                writable = false;
+        }
+
+        umask(m);
+
+        if (fstat(fd, &st) < 0) {
+                log_error("fstat() failed: %m");
+                r = -errno;
+                goto finish;
+        }
+
+        if (S_ISREG(st.st_mode)) {
+                if (loop_read(fd, id, 32, false) >= 32) {
+                        r = 0;
+                        goto finish;
+                }
+        }
+
+        /* Hmm, so, the id currently stored is not useful, then let's
+         * generate one */
+
+        r = generate(id);
+        if (r < 0)
+                goto finish;
+
+        if (S_ISREG(st.st_mode) && writable) {
+                lseek(fd, 0, SEEK_SET);
+
+                if (loop_write(fd, id, 33, false) == 33) {
+                        r = 0;
+                        goto finish;
+                }
+        }
+
+        close_nointr_nofail(fd);
+        fd = -1;
+
+        /* Hmm, we couldn't write it? So let's write it to
+         * /run/machine-id as a replacement */
+
+        m = umask(0022);
+        r = write_one_line_file("/run/machine-id", id);
+        umask(m);
+
+        if (r < 0) {
+                log_error("Cannot write /run/machine-id: %s", strerror(-r));
+
+                unlink("/run/machine-id");
+                goto finish;
+        }
+
+        /* And now, let's mount it over */
+        r = mount("/run/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
+        if (r < 0) {
+                unlink("/run/machine-id");
+                log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
+        } else
+                log_info("Installed transient /etc/machine-id file.");
+
+finish:
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
diff --git a/src/shared/machine-id-setup.h b/src/shared/machine-id-setup.h
new file mode 100644
index 0000000..16f45d8
--- /dev/null
+++ b/src/shared/machine-id-setup.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foomachineidsetuphfoo
+#define foomachineidsetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int machine_id_setup(void);
+
+#endif
diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
new file mode 100644
index 0000000..52fe523
--- /dev/null
+++ b/src/shared/mount-setup.c
@@ -0,0 +1,423 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/mount.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <assert.h>
+#include <unistd.h>
+#include <ftw.h>
+
+#include "mount-setup.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "label.h"
+#include "set.h"
+#include "strv.h"
+#include "mkdir.h"
+
+#ifndef TTY_GID
+#define TTY_GID 5
+#endif
+
+typedef struct MountPoint {
+        const char *what;
+        const char *where;
+        const char *type;
+        const char *options;
+        unsigned long flags;
+        bool fatal;
+} MountPoint;
+
+/* The first three entries we might need before SELinux is up. The
+ * fourth (securityfs) is needed by IMA to load a custom policy. The
+ * other ones we can delay until SELinux and IMA are loaded. */
+#define N_EARLY_MOUNT 4
+
+static const MountPoint mount_table[] = {
+        { "proc",     "/proc",                  "proc",     NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "sysfs",    "/sys",                   "sysfs",    NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "devtmpfs", "/dev",                   "devtmpfs", "mode=755",          MS_NOSUID|MS_STRICTATIME,     true },
+        { "securityfs", "/sys/kernel/security", "securityfs", NULL,              MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "tmpfs",    "/dev/shm",               "tmpfs",    "mode=1777",         MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
+        { "devpts",   "/dev/pts",               "devpts",   "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false },
+        { "tmpfs",    "/run",                   "tmpfs",    "mode=755",          MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
+        { "tmpfs",    "/sys/fs/cgroup",         "tmpfs",    "mode=755",          MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, false },
+        { "cgroup",   "/sys/fs/cgroup/systemd", "cgroup",   "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+};
+
+/* These are API file systems that might be mounted by other software,
+ * we just list them here so that we know that we should ignore them */
+
+static const char * const ignore_paths[] = {
+        "/sys/fs/selinux",
+        "/selinux",
+        "/proc/bus/usb"
+};
+
+bool mount_point_is_api(const char *path) {
+        unsigned i;
+
+        /* Checks if this mount point is considered "API", and hence
+         * should be ignored */
+
+        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
+                if (path_equal(path, mount_table[i].where))
+                        return true;
+
+        return path_startswith(path, "/sys/fs/cgroup/");
+}
+
+bool mount_point_ignore(const char *path) {
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(ignore_paths); i++)
+                if (path_equal(path, ignore_paths[i]))
+                        return true;
+
+        return false;
+}
+
+static int mount_one(const MountPoint *p, bool relabel) {
+        int r;
+
+        assert(p);
+
+        /* Relabel first, just in case */
+        if (relabel)
+                label_fix(p->where, true);
+
+        if ((r = path_is_mount_point(p->where, true)) < 0)
+                return r;
+
+        if (r > 0)
+                return 0;
+
+        /* The access mode here doesn't really matter too much, since
+         * the mounted file system will take precedence anyway. */
+        mkdir_p(p->where, 0755);
+
+        log_debug("Mounting %s to %s of type %s with options %s.",
+                  p->what,
+                  p->where,
+                  p->type,
+                  strna(p->options));
+
+        if (mount(p->what,
+                  p->where,
+                  p->type,
+                  p->flags,
+                  p->options) < 0) {
+                log_error("Failed to mount %s: %s", p->where, strerror(errno));
+                return p->fatal ? -errno : 0;
+        }
+
+        /* Relabel again, since we now mounted something fresh here */
+        if (relabel)
+                label_fix(p->where, false);
+
+        return 1;
+}
+
+int mount_setup_early(void) {
+        unsigned i;
+        int r = 0;
+
+        assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
+
+        /* Do a minimal mount of /proc and friends to enable the most
+         * basic stuff, such as SELinux */
+        for (i = 0; i < N_EARLY_MOUNT; i ++)  {
+                int j;
+
+                j = mount_one(mount_table + i, false);
+                if (r == 0)
+                        r = j;
+        }
+
+        return r;
+}
+
+int mount_cgroup_controllers(char ***join_controllers) {
+        int r;
+        FILE *f;
+        char buf[LINE_MAX];
+        Set *controllers;
+
+        /* Mount all available cgroup controllers that are built into the kernel. */
+
+        f = fopen("/proc/cgroups", "re");
+        if (!f) {
+                log_error("Failed to enumerate cgroup controllers: %m");
+                return 0;
+        }
+
+        controllers = set_new(string_hash_func, string_compare_func);
+        if (!controllers) {
+                r = -ENOMEM;
+                log_error("Failed to allocate controller set.");
+                goto finish;
+        }
+
+        /* Ignore the header line */
+        (void) fgets(buf, sizeof(buf), f);
+
+        for (;;) {
+                char *controller;
+                int enabled = 0;
+
+                if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
+
+                        if (feof(f))
+                                break;
+
+                        log_error("Failed to parse /proc/cgroups.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (!enabled) {
+                        free(controller);
+                        continue;
+                }
+
+                r = set_put(controllers, controller);
+                if (r < 0) {
+                        log_error("Failed to add controller to set.");
+                        free(controller);
+                        goto finish;
+                }
+        }
+
+        for (;;) {
+                MountPoint p;
+                char *controller, *where, *options;
+                char ***k = NULL;
+
+                controller = set_steal_first(controllers);
+                if (!controller)
+                        break;
+
+                if (join_controllers)
+                        for (k = join_controllers; *k; k++)
+                                if (strv_find(*k, controller))
+                                        break;
+
+                if (k && *k) {
+                        char **i, **j;
+
+                        for (i = *k, j = *k; *i; i++) {
+
+                                if (!streq(*i, controller)) {
+                                        char *t;
+
+                                        t = set_remove(controllers, *i);
+                                        if (!t) {
+                                                free(*i);
+                                                continue;
+                                        }
+                                        free(t);
+                                }
+
+                                *(j++) = *i;
+                        }
+
+                        *j = NULL;
+
+                        options = strv_join(*k, ",");
+                        if (!options) {
+                                log_error("Failed to join options");
+                                free(controller);
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                } else {
+                        options = controller;
+                        controller = NULL;
+                }
+
+                where = strappend("/sys/fs/cgroup/", options);
+                if (!where) {
+                        log_error("Failed to build path");
+                        free(options);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                zero(p);
+                p.what = "cgroup";
+                p.where = where;
+                p.type = "cgroup";
+                p.options = options;
+                p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
+                p.fatal = false;
+
+                r = mount_one(&p, true);
+                free(controller);
+                free(where);
+
+                if (r < 0) {
+                        free(options);
+                        goto finish;
+                }
+
+                if (r > 0 && k && *k) {
+                        char **i;
+
+                        for (i = *k; *i; i++) {
+                                char *t;
+
+                                t = strappend("/sys/fs/cgroup/", *i);
+                                if (!t) {
+                                        log_error("Failed to build path");
+                                        r = -ENOMEM;
+                                        free(options);
+                                        goto finish;
+                                }
+
+                                r = symlink(options, t);
+                                free(t);
+
+                                if (r < 0 && errno != EEXIST) {
+                                        log_error("Failed to create symlink: %m");
+                                        r = -errno;
+                                        free(options);
+                                        goto finish;
+                                }
+                        }
+                }
+
+                free(options);
+        }
+
+        r = 0;
+
+finish:
+        set_free_free(controllers);
+
+        fclose(f);
+
+        return r;
+}
+
+static int symlink_and_label(const char *old_path, const char *new_path) {
+        int r;
+
+        assert(old_path);
+        assert(new_path);
+
+        if ((r = label_symlinkfile_set(new_path)) < 0)
+                return r;
+
+        if (symlink(old_path, new_path) < 0)
+                r = -errno;
+
+        label_file_clear();
+
+        return r;
+}
+
+static int nftw_cb(
+                const char *fpath,
+                const struct stat *sb,
+                int tflag,
+                struct FTW *ftwbuf) {
+
+        /* No need to label /dev twice in a row... */
+        if (_unlikely_(ftwbuf->level == 0))
+                return FTW_CONTINUE;
+
+        label_fix(fpath, true);
+
+        /* /run/initramfs is static data and big, no need to
+         * dynamically relabel its contents at boot... */
+        if (_unlikely_(ftwbuf->level == 1 &&
+                      tflag == FTW_D &&
+                      streq(fpath, "/run/initramfs")))
+                return FTW_SKIP_SUBTREE;
+
+        return FTW_CONTINUE;
+};
+
+int mount_setup(bool loaded_policy) {
+
+        static const char symlinks[] =
+                "/proc/kcore\0"      "/dev/core\0"
+                "/proc/self/fd\0"    "/dev/fd\0"
+                "/proc/self/fd/0\0"  "/dev/stdin\0"
+                "/proc/self/fd/1\0"  "/dev/stdout\0"
+                "/proc/self/fd/2\0"  "/dev/stderr\0";
+
+        static const char relabel[] =
+                "/run/initramfs/root-fsck\0"
+                "/run/initramfs/shutdown\0";
+
+        int r;
+        unsigned i;
+        const char *j, *k;
+
+        for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
+                r = mount_one(mount_table + i, true);
+
+                if (r < 0)
+                        return r;
+        }
+
+        /* Nodes in devtmpfs and /run need to be manually updated for
+         * the appropriate labels, after mounting. The other virtual
+         * API file systems like /sys and /proc do not need that, they
+         * use the same label for all their files. */
+        if (loaded_policy) {
+                usec_t before_relabel, after_relabel;
+                char timespan[FORMAT_TIMESPAN_MAX];
+
+                before_relabel = now(CLOCK_MONOTONIC);
+
+                nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+                nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+
+                /* Explicitly relabel these */
+                NULSTR_FOREACH(j, relabel)
+                        label_fix(j, true);
+
+                after_relabel = now(CLOCK_MONOTONIC);
+
+                log_info("Relabelled /dev and /run in %s.",
+                         format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel));
+        }
+
+        /* Create a few default symlinks, which are normally created
+         * by udevd, but some scripts might need them before we start
+         * udevd. */
+        NULSTR_FOREACH_PAIR(j, k, symlinks)
+                symlink_and_label(j, k);
+
+        /* Create a few directories we always want around */
+        label_mkdir("/run/systemd", 0755);
+        label_mkdir("/run/systemd/system", 0755);
+
+        return 0;
+}
diff --git a/src/shared/mount-setup.h b/src/shared/mount-setup.h
new file mode 100644
index 0000000..720b66f
--- /dev/null
+++ b/src/shared/mount-setup.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foomountsetuphfoo
+#define foomountsetuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+int mount_setup_early(void);
+
+int mount_setup(bool loaded_policy);
+
+int mount_cgroup_controllers(char ***join_controllers);
+
+bool mount_point_is_api(const char *path);
+bool mount_point_ignore(const char *path);
+
+#endif
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
new file mode 100644
index 0000000..1d95f7d
--- /dev/null
+++ b/src/shared/path-lookup.c
@@ -0,0 +1,348 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "mkdir.h"
+#include "strv.h"
+
+#include "path-lookup.h"
+
+int user_config_home(char **config_home) {
+        const char *e;
+
+        if ((e = getenv("XDG_CONFIG_HOME"))) {
+                if (asprintf(config_home, "%s/systemd/user", e) < 0)
+                        return -ENOMEM;
+
+                return 1;
+        } else {
+                const char *home;
+
+                if ((home = getenv("HOME"))) {
+                        if (asprintf(config_home, "%s/.config/systemd/user", home) < 0)
+                                return -ENOMEM;
+
+                        return 1;
+                }
+        }
+
+        return 0;
+}
+
+static char** user_dirs(void) {
+        const char * const config_unit_paths[] = {
+                USER_CONFIG_UNIT_PATH,
+                "/etc/systemd/user",
+                "/run/systemd/user",
+                NULL
+        };
+
+        const char * const data_unit_paths[] = {
+                "/usr/local/lib/systemd/user",
+                "/usr/local/share/systemd/user",
+                USER_DATA_UNIT_PATH,
+                "/usr/lib/systemd/user",
+                "/usr/share/systemd/user",
+                NULL
+        };
+
+        const char *home, *e;
+        char *config_home = NULL, *data_home = NULL;
+        char **config_dirs = NULL, **data_dirs = NULL;
+        char **r = NULL, **t;
+
+        /* Implement the mechanisms defined in
+         *
+         * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
+         *
+         * We look in both the config and the data dirs because we
+         * want to encourage that distributors ship their unit files
+         * as data, and allow overriding as configuration.
+         */
+
+        if (user_config_home(&config_home) < 0)
+                goto fail;
+
+        home = getenv("HOME");
+
+        if ((e = getenv("XDG_CONFIG_DIRS")))
+                if (!(config_dirs = strv_split(e, ":")))
+                        goto fail;
+
+        /* We don't treat /etc/xdg/systemd here as the spec
+         * suggests because we assume that that is a link to
+         * /etc/systemd/ anyway. */
+
+        if ((e = getenv("XDG_DATA_HOME"))) {
+                if (asprintf(&data_home, "%s/systemd/user", e) < 0)
+                        goto fail;
+
+        } else if (home) {
+                if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
+                        goto fail;
+
+                /* There is really no need for two unit dirs in $HOME,
+                 * except to be fully compliant with the XDG spec. We
+                 * now try to link the two dirs, so that we can
+                 * minimize disk seeks a little. Further down we'll
+                 * then filter out this link, if it is actually is
+                 * one. */
+
+                mkdir_parents(data_home, 0777);
+                (void) symlink("../../../.config/systemd/user", data_home);
+        }
+
+        if ((e = getenv("XDG_DATA_DIRS")))
+                data_dirs = strv_split(e, ":");
+        else
+                data_dirs = strv_new("/usr/local/share",
+                                     "/usr/share",
+                                     NULL);
+
+        if (!data_dirs)
+                goto fail;
+
+        /* Now merge everything we found. */
+        if (config_home) {
+                if (!(t = strv_append(r, config_home)))
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
+        if (!strv_isempty(config_dirs)) {
+                if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user")))
+                        goto finish;
+                strv_free(r);
+                r = t;
+        }
+
+        if (!(t = strv_merge(r, (char**) config_unit_paths)))
+                goto fail;
+        strv_free(r);
+        r = t;
+
+        if (data_home) {
+                if (!(t = strv_append(r, data_home)))
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
+        if (!strv_isempty(data_dirs)) {
+                if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user")))
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
+        if (!(t = strv_merge(r, (char**) data_unit_paths)))
+                goto fail;
+        strv_free(r);
+        r = t;
+
+        if (!strv_path_make_absolute_cwd(r))
+            goto fail;
+
+finish:
+        free(config_home);
+        strv_free(config_dirs);
+        free(data_home);
+        strv_free(data_dirs);
+
+        return r;
+
+fail:
+        strv_free(r);
+        r = NULL;
+        goto finish;
+}
+
+int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) {
+        const char *e;
+        char *t;
+
+        assert(p);
+
+        /* First priority is whatever has been passed to us via env
+         * vars */
+        if ((e = getenv("SYSTEMD_UNIT_PATH")))
+                if (!(p->unit_path = split_path_and_make_absolute(e)))
+                        return -ENOMEM;
+
+        if (strv_isempty(p->unit_path)) {
+
+                /* Nothing is set, so let's figure something out. */
+                strv_free(p->unit_path);
+
+                if (running_as == MANAGER_USER) {
+
+                        if (personal)
+                                p->unit_path = user_dirs();
+                        else
+                                p->unit_path = strv_new(
+                                                /* If you modify this you also want to modify
+                                                 * systemduserunitpath= in systemd.pc.in, and
+                                                 * the arrays in user_dirs() above! */
+                                                USER_CONFIG_UNIT_PATH,
+                                                "/etc/systemd/user",
+                                                "/run/systemd/user",
+                                                "/usr/local/lib/systemd/user",
+                                                "/usr/local/share/systemd/user",
+                                                USER_DATA_UNIT_PATH,
+                                                "/usr/lib/systemd/user",
+                                                "/usr/share/systemd/user",
+                                                NULL);
+
+                        if (!p->unit_path)
+                                return -ENOMEM;
+
+                } else
+                        if (!(p->unit_path = strv_new(
+                                              /* If you modify this you also want to modify
+                                               * systemdsystemunitpath= in systemd.pc.in! */
+                                              SYSTEM_CONFIG_UNIT_PATH,
+                                              "/etc/systemd/system",
+                                              "/run/systemd/system",
+                                              "/usr/local/lib/systemd/system",
+                                              SYSTEM_DATA_UNIT_PATH,
+                                              "/usr/lib/systemd/system",
+#ifdef HAVE_SPLIT_USR
+                                              "/lib/systemd/system",
+#endif
+                                              NULL)))
+                                return -ENOMEM;
+        }
+
+        if (p->unit_path)
+                if (!strv_path_canonicalize(p->unit_path))
+                        return -ENOMEM;
+
+        strv_uniq(p->unit_path);
+        strv_path_remove_empty(p->unit_path);
+
+        if (!strv_isempty(p->unit_path)) {
+
+                if (!(t = strv_join(p->unit_path, "\n\t")))
+                        return -ENOMEM;
+                log_debug("Looking for unit files in:\n\t%s", t);
+                free(t);
+        } else {
+                log_debug("Ignoring unit files.");
+                strv_free(p->unit_path);
+                p->unit_path = NULL;
+        }
+
+        if (running_as == MANAGER_SYSTEM) {
+#ifdef HAVE_SYSV_COMPAT
+                /* /etc/init.d/ compatibility does not matter to users */
+
+                if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
+                        if (!(p->sysvinit_path = split_path_and_make_absolute(e)))
+                                return -ENOMEM;
+
+                if (strv_isempty(p->sysvinit_path)) {
+                        strv_free(p->sysvinit_path);
+
+                        if (!(p->sysvinit_path = strv_new(
+                                              SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
+                                              NULL)))
+                                return -ENOMEM;
+                }
+
+                if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
+                        if (!(p->sysvrcnd_path = split_path_and_make_absolute(e)))
+                                return -ENOMEM;
+
+                if (strv_isempty(p->sysvrcnd_path)) {
+                        strv_free(p->sysvrcnd_path);
+
+                        if (!(p->sysvrcnd_path = strv_new(
+                                              SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
+                                              NULL)))
+                                return -ENOMEM;
+                }
+
+                if (p->sysvinit_path)
+                        if (!strv_path_canonicalize(p->sysvinit_path))
+                                return -ENOMEM;
+
+                if (p->sysvrcnd_path)
+                        if (!strv_path_canonicalize(p->sysvrcnd_path))
+                                return -ENOMEM;
+
+                strv_uniq(p->sysvinit_path);
+                strv_uniq(p->sysvrcnd_path);
+
+                strv_path_remove_empty(p->sysvinit_path);
+                strv_path_remove_empty(p->sysvrcnd_path);
+
+                if (!strv_isempty(p->sysvinit_path)) {
+
+                        if (!(t = strv_join(p->sysvinit_path, "\n\t")))
+                                return -ENOMEM;
+
+                        log_debug("Looking for SysV init scripts in:\n\t%s", t);
+                        free(t);
+                } else {
+                        log_debug("Ignoring SysV init scripts.");
+                        strv_free(p->sysvinit_path);
+                        p->sysvinit_path = NULL;
+                }
+
+                if (!strv_isempty(p->sysvrcnd_path)) {
+
+                        if (!(t = strv_join(p->sysvrcnd_path, "\n\t")))
+                                return -ENOMEM;
+
+                        log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
+                        free(t);
+                } else {
+                        log_debug("Ignoring SysV rcN.d links.");
+                        strv_free(p->sysvrcnd_path);
+                        p->sysvrcnd_path = NULL;
+                }
+#else
+                log_debug("Disabled SysV init scripts and rcN.d links support");
+#endif
+        }
+
+        return 0;
+}
+
+void lookup_paths_free(LookupPaths *p) {
+        assert(p);
+
+        strv_free(p->unit_path);
+        p->unit_path = NULL;
+
+#ifdef HAVE_SYSV_COMPAT
+        strv_free(p->sysvinit_path);
+        strv_free(p->sysvrcnd_path);
+        p->sysvinit_path = p->sysvrcnd_path = NULL;
+#endif
+}
diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h
new file mode 100644
index 0000000..e8a5a77
--- /dev/null
+++ b/src/shared/path-lookup.h
@@ -0,0 +1,40 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foopathlookuphfoo
+#define foopathlookuphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct LookupPaths {
+        char **unit_path;
+#ifdef HAVE_SYSV_COMPAT
+        char **sysvinit_path;
+        char **sysvrcnd_path;
+#endif
+} LookupPaths;
+
+#include "manager.h"
+
+int user_config_home(char **config_home);
+
+int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal);
+void lookup_paths_free(LookupPaths *p);
+
+#endif
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
new file mode 100644
index 0000000..c1a9c58
--- /dev/null
+++ b/src/shared/spawn-ask-password-agent.c
@@ -0,0 +1,67 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include "log.h"
+#include "util.h"
+#include "spawn-ask-password-agent.h"
+
+static pid_t agent_pid = 0;
+
+int ask_password_agent_open(void) {
+        int r;
+
+        if (agent_pid > 0)
+                return 0;
+
+        /* We check STDIN here, not STDOUT, since this is about input,
+         * not output */
+        if (!isatty(STDIN_FILENO))
+                return 0;
+
+        r = fork_agent(&agent_pid,
+                       NULL, 0,
+                       SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
+                       SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
+        if (r < 0)
+                log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
+
+        return r;
+}
+
+void ask_password_agent_close(void) {
+
+        if (agent_pid <= 0)
+                return;
+
+        /* Inform agent that we are done */
+        kill(agent_pid, SIGTERM);
+        kill(agent_pid, SIGCONT);
+        wait_for_terminate(agent_pid, NULL);
+        agent_pid = 0;
+}
diff --git a/src/shared/spawn-ask-password-agent.h b/src/shared/spawn-ask-password-agent.h
new file mode 100644
index 0000000..fa5e7b0
--- /dev/null
+++ b/src/shared/spawn-ask-password-agent.h
@@ -0,0 +1,28 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foospawnaskpasswordagenthfoo
+#define foospawnaskpasswordagenthfoo
+
+/***
+  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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int ask_password_agent_open(void);
+void ask_password_agent_close(void);
+
+#endif
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
new file mode 100644
index 0000000..fd72588
--- /dev/null
+++ b/src/shared/spawn-polkit-agent.c
@@ -0,0 +1,86 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/poll.h>
+
+#include "log.h"
+#include "util.h"
+#include "spawn-polkit-agent.h"
+
+static pid_t agent_pid = 0;
+
+int polkit_agent_open(void) {
+        int r;
+        int pipe_fd[2];
+        char notify_fd[10 + 1];
+
+        if (agent_pid > 0)
+                return 0;
+
+        /* We check STDIN here, not STDOUT, since this is about input,
+         * not output */
+        if (!isatty(STDIN_FILENO))
+                return 0;
+
+        if (pipe2(pipe_fd, 0) < 0)
+                return -errno;
+
+        snprintf(notify_fd, sizeof(notify_fd), "%i", pipe_fd[1]);
+        char_array_0(notify_fd);
+
+        r = fork_agent(&agent_pid,
+                       &pipe_fd[1], 1,
+                       POLKIT_AGENT_BINARY_PATH,
+                       POLKIT_AGENT_BINARY_PATH, "--notify-fd", notify_fd, NULL);
+
+        /* Close the writing side, because that's the one for the agent */
+        close_nointr_nofail(pipe_fd[1]);
+
+        if (r < 0)
+                log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
+        else
+                /* Wait until the agent closes the fd */
+                fd_wait_for_event(pipe_fd[0], POLLHUP, (usec_t) -1);
+
+        close_nointr_nofail(pipe_fd[0]);
+
+        return r;
+}
+
+void polkit_agent_close(void) {
+
+        if (agent_pid <= 0)
+                return;
+
+        /* Inform agent that we are done */
+        kill(agent_pid, SIGTERM);
+        kill(agent_pid, SIGCONT);
+        wait_for_terminate(agent_pid, NULL);
+        agent_pid = 0;
+}
diff --git a/src/shared/spawn-polkit-agent.h b/src/shared/spawn-polkit-agent.h
new file mode 100644
index 0000000..b91d20f
--- /dev/null
+++ b/src/shared/spawn-polkit-agent.h
@@ -0,0 +1,28 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foospawnpolkitagenthfoo
+#define foospawnpolkitagenthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int polkit_agent_open(void);
+void polkit_agent_close(void);
+
+#endif
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
new file mode 100644
index 0000000..ae00ae1
--- /dev/null
+++ b/src/shared/specifier.c
@@ -0,0 +1,108 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "macro.h"
+#include "util.h"
+#include "specifier.h"
+
+/*
+ * Generic infrastructure for replacing %x style specifiers in
+ * strings. Will call a callback for each replacement.
+ *
+ */
+
+char *specifier_printf(const char *text, const Specifier table[], void *userdata) {
+        char *r, *t;
+        const char *f;
+        bool percent = false;
+        size_t l;
+
+        assert(text);
+        assert(table);
+
+        l = strlen(text);
+        if (!(r = new(char, l+1)))
+                return NULL;
+
+        t = r;
+
+        for (f = text; *f; f++, l--) {
+
+                if (percent) {
+                        if (*f == '%')
+                                *(t++) = '%';
+                        else {
+                                const Specifier *i;
+
+                                for (i = table; i->specifier; i++)
+                                        if (i->specifier == *f)
+                                                break;
+
+                                if (i->lookup) {
+                                        char *n, *w;
+                                        size_t k, j;
+
+                                        if (!(w = i->lookup(i->specifier, i->data, userdata))) {
+                                                free(r);
+                                                return NULL;
+                                        }
+
+                                        j = t - r;
+                                        k = strlen(w);
+
+                                        if (!(n = new(char, j + k + l + 1))) {
+                                                free(r);
+                                                free(w);
+                                                return NULL;
+                                        }
+
+                                        memcpy(n, r, j);
+                                        memcpy(n + j, w, k);
+
+                                        free(r);
+                                        free(w);
+
+                                        r = n;
+                                        t = n + j + k;
+                                } else {
+                                        *(t++) = '%';
+                                        *(t++) = *f;
+                                }
+                        }
+
+                        percent = false;
+                } else if (*f == '%')
+                        percent = true;
+                else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+        return r;
+}
+
+/* Generic handler for simple string replacements */
+
+char* specifier_string(char specifier, void *data, void *userdata) {
+        return strdup(strempty(data));
+}
diff --git a/src/shared/specifier.h b/src/shared/specifier.h
new file mode 100644
index 0000000..57d1fcb
--- /dev/null
+++ b/src/shared/specifier.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foospecifierhfoo
+#define foospecifierhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata);
+
+typedef struct Specifier {
+        const char specifier;
+        const SpecifierCallback lookup;
+        void *data;
+} Specifier;
+
+char *specifier_printf(const char *text, const Specifier table[], void *userdata);
+
+char* specifier_string(char specifier, void *data, void *userdata);
+
+#endif
diff --git a/src/shared/umount.c b/src/shared/umount.c
new file mode 100644
index 0000000..24c0947
--- /dev/null
+++ b/src/shared/umount.c
@@ -0,0 +1,644 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 ProFUSION embedded systems
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/swap.h>
+#include <unistd.h>
+#include <linux/loop.h>
+#include <linux/dm-ioctl.h>
+#include <libudev.h>
+
+#include "list.h"
+#include "mount-setup.h"
+#include "umount.h"
+#include "util.h"
+
+typedef struct MountPoint {
+        char *path;
+        dev_t devnum;
+        bool skip_ro;
+        LIST_FIELDS (struct MountPoint, mount_point);
+} MountPoint;
+
+static void mount_point_free(MountPoint **head, MountPoint *m) {
+        assert(head);
+        assert(m);
+
+        LIST_REMOVE(MountPoint, mount_point, *head, m);
+
+        free(m->path);
+        free(m);
+}
+
+static void mount_points_list_free(MountPoint **head) {
+        assert(head);
+
+        while (*head)
+                mount_point_free(head, *head);
+}
+
+static int mount_points_list_get(MountPoint **head) {
+        FILE *proc_self_mountinfo;
+        char *path, *p;
+        unsigned int i;
+        int r;
+
+        assert(head);
+
+        if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
+                return -errno;
+
+        for (i = 1;; i++) {
+                int k;
+                MountPoint *m;
+                char *root;
+                bool skip_ro;
+
+                path = p = NULL;
+
+                if ((k = fscanf(proc_self_mountinfo,
+                                "%*s "       /* (1) mount id */
+                                "%*s "       /* (2) parent id */
+                                "%*s "       /* (3) major:minor */
+                                "%ms "       /* (4) root */
+                                "%ms "       /* (5) mount point */
+                                "%*s"        /* (6) mount options */
+                                "%*[^-]"     /* (7) optional fields */
+                                "- "         /* (8) separator */
+                                "%*s "       /* (9) file system type */
+                                "%*s"        /* (10) mount source */
+                                "%*s"        /* (11) mount options 2 */
+                                "%*[^\n]",   /* some rubbish at the end */
+                                &root,
+                                &path)) != 2) {
+                        if (k == EOF)
+                                break;
+
+                        log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
+
+                        free(path);
+                        continue;
+                }
+
+                /* If we encounter a bind mount, don't try to remount
+                 * the source dir too early */
+                skip_ro = !streq(root, "/");
+                free(root);
+
+                p = cunescape(path);
+                free(path);
+
+                if (!p) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (mount_point_is_api(p) || mount_point_ignore(p)) {
+                        free(p);
+                        continue;
+                }
+
+                if (!(m = new0(MountPoint, 1))) {
+                        free(p);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                m->path = p;
+                m->skip_ro = skip_ro;
+                LIST_PREPEND(MountPoint, mount_point, *head, m);
+        }
+
+        r = 0;
+
+finish:
+        fclose(proc_self_mountinfo);
+
+        return r;
+}
+
+static int swap_list_get(MountPoint **head) {
+        FILE *proc_swaps;
+        unsigned int i;
+        int r;
+
+        assert(head);
+
+        if (!(proc_swaps = fopen("/proc/swaps", "re")))
+                return (errno == ENOENT) ? 0 : -errno;
+
+        (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
+
+        for (i = 2;; i++) {
+                MountPoint *swap;
+                char *dev = NULL, *d;
+                int k;
+
+                if ((k = fscanf(proc_swaps,
+                                "%ms " /* device/file */
+                                "%*s " /* type of swap */
+                                "%*s " /* swap size */
+                                "%*s " /* used */
+                                "%*s\n", /* priority */
+                                &dev)) != 1) {
+
+                        if (k == EOF)
+                                break;
+
+                        log_warning("Failed to parse /proc/swaps:%u.", i);
+
+                        free(dev);
+                        continue;
+                }
+
+                if (endswith(dev, "(deleted)")) {
+                        free(dev);
+                        continue;
+                }
+
+                d = cunescape(dev);
+                free(dev);
+
+                if (!d) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(swap = new0(MountPoint, 1))) {
+                        free(d);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                swap->path = d;
+                LIST_PREPEND(MountPoint, mount_point, *head, swap);
+        }
+
+        r = 0;
+
+finish:
+        fclose(proc_swaps);
+
+        return r;
+}
+
+static int loopback_list_get(MountPoint **head) {
+        int r;
+        struct udev *udev;
+        struct udev_enumerate *e = NULL;
+        struct udev_list_entry *item = NULL, *first = NULL;
+
+        assert(head);
+
+        if (!(udev = udev_new())) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!(e = udev_enumerate_new(udev))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
+            udev_enumerate_add_match_sysname(e, "loop*") < 0) {
+                r = -EIO;
+                goto finish;
+        }
+
+        if (udev_enumerate_scan_devices(e) < 0) {
+                r = -EIO;
+                goto finish;
+        }
+
+        first = udev_enumerate_get_list_entry(e);
+        udev_list_entry_foreach(item, first) {
+                MountPoint *lb;
+                struct udev_device *d;
+                char *loop;
+                const char *dn;
+
+                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(dn = udev_device_get_devnode(d))) {
+                        udev_device_unref(d);
+                        continue;
+                }
+
+                loop = strdup(dn);
+                udev_device_unref(d);
+
+                if (!loop) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(lb = new0(MountPoint, 1))) {
+                        free(loop);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                lb->path = loop;
+                LIST_PREPEND(MountPoint, mount_point, *head, lb);
+        }
+
+        r = 0;
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        if (udev)
+                udev_unref(udev);
+
+        return r;
+}
+
+static int dm_list_get(MountPoint **head) {
+        int r;
+        struct udev *udev;
+        struct udev_enumerate *e = NULL;
+        struct udev_list_entry *item = NULL, *first = NULL;
+
+        assert(head);
+
+        if (!(udev = udev_new())) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!(e = udev_enumerate_new(udev))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
+            udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
+                r = -EIO;
+                goto finish;
+        }
+
+        if (udev_enumerate_scan_devices(e) < 0) {
+                r = -EIO;
+                goto finish;
+        }
+
+        first = udev_enumerate_get_list_entry(e);
+
+        udev_list_entry_foreach(item, first) {
+                MountPoint *m;
+                struct udev_device *d;
+                dev_t devnum;
+                char *node;
+                const char *dn;
+
+                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                devnum = udev_device_get_devnum(d);
+                dn = udev_device_get_devnode(d);
+
+                if (major(devnum) == 0 || !dn) {
+                        udev_device_unref(d);
+                        continue;
+                }
+
+                node = strdup(dn);
+                udev_device_unref(d);
+
+                if (!node) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(m = new(MountPoint, 1))) {
+                        free(node);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                m->path = node;
+                m->devnum = devnum;
+                LIST_PREPEND(MountPoint, mount_point, *head, m);
+        }
+
+        r = 0;
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        if (udev)
+                udev_unref(udev);
+
+        return r;
+}
+
+static int delete_loopback(const char *device) {
+        int fd, r;
+
+        if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
+                return errno == ENOENT ? 0 : -errno;
+
+        r = ioctl(fd, LOOP_CLR_FD, 0);
+        close_nointr_nofail(fd);
+
+        if (r >= 0)
+                return 1;
+
+        /* ENXIO: not bound, so no error */
+        if (errno == ENXIO)
+                return 0;
+
+        return -errno;
+}
+
+static int delete_dm(dev_t devnum) {
+        int fd, r;
+        struct dm_ioctl dm;
+
+        assert(major(devnum) != 0);
+
+        if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
+                return -errno;
+
+        zero(dm);
+        dm.version[0] = DM_VERSION_MAJOR;
+        dm.version[1] = DM_VERSION_MINOR;
+        dm.version[2] = DM_VERSION_PATCHLEVEL;
+
+        dm.data_size = sizeof(dm);
+        dm.dev = devnum;
+
+        r = ioctl(fd, DM_DEV_REMOVE, &dm);
+        close_nointr_nofail(fd);
+
+        return r >= 0 ? 0 : -errno;
+}
+
+static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
+        MountPoint *m, *n;
+        int n_failed = 0;
+
+        assert(head);
+
+        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+                if (path_equal(m->path, "/")
+#ifndef HAVE_SPLIT_USR
+                    || path_equal(m->path, "/usr")
+#endif
+                ) {
+                        n_failed++;
+                        continue;
+                }
+
+                /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
+                if (umount2(m->path, MNT_FORCE) == 0) {
+                        log_info("Unmounted %s.", m->path);
+                        if (changed)
+                                *changed = true;
+
+                        mount_point_free(head, m);
+                } else if (log_error) {
+                        log_warning("Could not unmount %s: %m", m->path);
+                        n_failed++;
+                }
+        }
+
+        return n_failed;
+}
+
+static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
+        MountPoint *m, *n;
+        int n_failed = 0;
+
+        assert(head);
+
+        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+
+                if (m->skip_ro) {
+                        n_failed++;
+                        continue;
+                }
+
+                /* Trying to remount read-only */
+                if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) {
+                        if (changed)
+                                *changed = true;
+
+                        mount_point_free(head, m);
+                } else {
+                        log_warning("Could not remount as read-only %s: %m", m->path);
+                        n_failed++;
+                }
+        }
+
+        return n_failed;
+}
+
+static int swap_points_list_off(MountPoint **head, bool *changed) {
+        MountPoint *m, *n;
+        int n_failed = 0;
+
+        assert(head);
+
+        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+                if (swapoff(m->path) == 0) {
+                        if (changed)
+                                *changed = true;
+
+                        mount_point_free(head, m);
+                } else {
+                        log_warning("Could not deactivate swap %s: %m", m->path);
+                        n_failed++;
+                }
+        }
+
+        return n_failed;
+}
+
+static int loopback_points_list_detach(MountPoint **head, bool *changed) {
+        MountPoint *m, *n;
+        int n_failed = 0, k;
+        struct stat root_st;
+
+        assert(head);
+
+        k = lstat("/", &root_st);
+
+        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+                int r;
+                struct stat loopback_st;
+
+                if (k >= 0 &&
+                    major(root_st.st_dev) != 0 &&
+                    lstat(m->path, &loopback_st) >= 0 &&
+                    root_st.st_dev == loopback_st.st_rdev) {
+                        n_failed ++;
+                        continue;
+                }
+
+                if ((r = delete_loopback(m->path)) >= 0) {
+
+                        if (r > 0 && changed)
+                                *changed = true;
+
+                        mount_point_free(head, m);
+                } else {
+                        log_warning("Could not delete loopback %s: %m", m->path);
+                        n_failed++;
+                }
+        }
+
+        return n_failed;
+}
+
+static int dm_points_list_detach(MountPoint **head, bool *changed) {
+        MountPoint *m, *n;
+        int n_failed = 0, k;
+        struct stat root_st;
+
+        assert(head);
+
+        k = lstat("/", &root_st);
+
+        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+                int r;
+
+                if (k >= 0 &&
+                    major(root_st.st_dev) != 0 &&
+                    root_st.st_dev == m->devnum) {
+                        n_failed ++;
+                        continue;
+                }
+
+                if ((r = delete_dm(m->devnum)) >= 0) {
+
+                        if (r > 0 && changed)
+                                *changed = true;
+
+                        mount_point_free(head, m);
+                } else {
+                        log_warning("Could not delete dm %s: %m", m->path);
+                        n_failed++;
+                }
+        }
+
+        return n_failed;
+}
+
+int umount_all(bool *changed) {
+        int r;
+        bool umount_changed;
+
+        LIST_HEAD(MountPoint, mp_list_head);
+
+        LIST_HEAD_INIT(MountPoint, mp_list_head);
+
+        r = mount_points_list_get(&mp_list_head);
+        if (r < 0)
+                goto end;
+
+        /* retry umount, until nothing can be umounted anymore */
+        do {
+                umount_changed = false;
+
+                mount_points_list_umount(&mp_list_head, &umount_changed, false);
+                if (umount_changed)
+                        *changed = true;
+
+        } while (umount_changed);
+
+        /* umount one more time with logging enabled */
+        r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
+        if (r <= 0)
+                goto end;
+
+        r = mount_points_list_remount_read_only(&mp_list_head, changed);
+
+  end:
+        mount_points_list_free(&mp_list_head);
+
+        return r;
+}
+
+int swapoff_all(bool *changed) {
+        int r;
+        LIST_HEAD(MountPoint, swap_list_head);
+
+        LIST_HEAD_INIT(MountPoint, swap_list_head);
+
+        r = swap_list_get(&swap_list_head);
+        if (r < 0)
+                goto end;
+
+        r = swap_points_list_off(&swap_list_head, changed);
+
+  end:
+        mount_points_list_free(&swap_list_head);
+
+        return r;
+}
+
+int loopback_detach_all(bool *changed) {
+        int r;
+        LIST_HEAD(MountPoint, loopback_list_head);
+
+        LIST_HEAD_INIT(MountPoint, loopback_list_head);
+
+        r = loopback_list_get(&loopback_list_head);
+        if (r < 0)
+                goto end;
+
+        r = loopback_points_list_detach(&loopback_list_head, changed);
+
+  end:
+        mount_points_list_free(&loopback_list_head);
+
+        return r;
+}
+
+int dm_detach_all(bool *changed) {
+        int r;
+        LIST_HEAD(MountPoint, dm_list_head);
+
+        LIST_HEAD_INIT(MountPoint, dm_list_head);
+
+        r = dm_list_get(&dm_list_head);
+        if (r < 0)
+                goto end;
+
+        r = dm_points_list_detach(&dm_list_head, changed);
+
+  end:
+        mount_points_list_free(&dm_list_head);
+
+        return r;
+}
diff --git a/src/shared/umount.h b/src/shared/umount.h
new file mode 100644
index 0000000..2e2f9c1
--- /dev/null
+++ b/src/shared/umount.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooumounthfoo
+#define fooumounthfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 ProFUSION embedded systems
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int umount_all(bool *changed);
+
+int swapoff_all(bool *changed);
+
+int loopback_detach_all(bool *changed);
+
+int dm_detach_all(bool *changed);
+
+#endif
diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c
new file mode 100644
index 0000000..566cdc5
--- /dev/null
+++ b/src/shared/unit-name.c
@@ -0,0 +1,448 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "unit-name.h"
+
+#define VALID_CHARS                             \
+        "0123456789"                            \
+        "abcdefghijklmnopqrstuvwxyz"            \
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
+        ":-_.\\"
+
+bool unit_name_is_valid_no_type(const char *n, bool template_ok) {
+        const char *e, *i, *at;
+
+        /* Valid formats:
+         *
+         *         string at instance.suffix
+         *         string.suffix
+         */
+
+        assert(n);
+
+        if (strlen(n) >= UNIT_NAME_MAX)
+                return false;
+
+        e = strrchr(n, '.');
+        if (!e || e == n)
+                return false;
+
+        for (i = n, at = NULL; i < e; i++) {
+
+                if (*i == '@' && !at)
+                        at = i;
+
+                if (!strchr("@" VALID_CHARS, *i))
+                        return false;
+        }
+
+        if (at) {
+                if (at == n)
+                        return false;
+
+                if (!template_ok && at+1 == e)
+                        return false;
+        }
+
+        return true;
+}
+
+bool unit_instance_is_valid(const char *i) {
+        assert(i);
+
+        /* The max length depends on the length of the string, so we
+         * don't really check this here. */
+
+        if (i[0] == 0)
+                return false;
+
+        /* We allow additional @ in the instance string, we do not
+         * allow them in the prefix! */
+
+        for (; *i; i++)
+                if (!strchr("@" VALID_CHARS, *i))
+                        return false;
+
+        return true;
+}
+
+bool unit_prefix_is_valid(const char *p) {
+
+        /* We don't allow additional @ in the instance string */
+
+        if (p[0] == 0)
+                return false;
+
+        for (; *p; p++)
+                if (!strchr(VALID_CHARS, *p))
+                        return false;
+
+        return true;
+}
+
+int unit_name_to_instance(const char *n, char **instance) {
+        const char *p, *d;
+        char *i;
+
+        assert(n);
+        assert(instance);
+
+        /* Everything past the first @ and before the last . is the instance */
+        if (!(p = strchr(n, '@'))) {
+                *instance = NULL;
+                return 0;
+        }
+
+        assert_se(d = strrchr(n, '.'));
+        assert(p < d);
+
+        if (!(i = strndup(p+1, d-p-1)))
+                return -ENOMEM;
+
+        *instance = i;
+        return 0;
+}
+
+char *unit_name_to_prefix_and_instance(const char *n) {
+        const char *d;
+
+        assert(n);
+
+        assert_se(d = strrchr(n, '.'));
+
+        return strndup(n, d - n);
+}
+
+char *unit_name_to_prefix(const char *n) {
+        const char *p;
+
+        if ((p = strchr(n, '@')))
+                return strndup(n, p - n);
+
+        return unit_name_to_prefix_and_instance(n);
+}
+
+char *unit_name_change_suffix(const char *n, const char *suffix) {
+        char *e, *r;
+        size_t a, b;
+
+        assert(n);
+        assert(unit_name_is_valid_no_type(n, true));
+        assert(suffix);
+
+        assert_se(e = strrchr(n, '.'));
+        a = e - n;
+        b = strlen(suffix);
+
+        if (!(r = new(char, a + b + 1)))
+                return NULL;
+
+        memcpy(r, n, a);
+        memcpy(r+a, suffix, b+1);
+
+        return r;
+}
+
+char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
+        assert(prefix);
+        assert(unit_prefix_is_valid(prefix));
+        assert(!instance || unit_instance_is_valid(instance));
+        assert(suffix);
+
+        if (!instance)
+                return strappend(prefix, suffix);
+
+        return join(prefix, "@", instance, suffix, NULL);
+}
+
+static char* do_escape(const char *f, char *t) {
+        assert(f);
+        assert(t);
+
+        for (; *f; f++) {
+                if (*f == '/')
+                        *(t++) = '-';
+                else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
+                        *(t++) = '\\';
+                        *(t++) = 'x';
+                        *(t++) = hexchar(*f >> 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        return t;
+}
+
+char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
+        char *r, *t;
+        size_t a, b, c;
+
+        assert(prefix);
+        assert(suffix);
+
+        /* Takes a arbitrary string for prefix and instance plus a
+         * suffix and makes a nice string suitable as unit name of it,
+         * escaping all weird chars on the way.
+         *
+         * / becomes ., and all chars not allowed in a unit name get
+         * escaped as \xFF, including \ and ., of course. This
+         * escaping is hence reversible.
+         *
+         * This is primarily useful to make nice unit names from
+         * strings, but is actually useful for any kind of string.
+         */
+
+        a = strlen(prefix);
+        c = strlen(suffix);
+
+        if (instance) {
+                b = strlen(instance);
+
+                if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
+                        return NULL;
+
+                t = do_escape(prefix, r);
+                *(t++) = '@';
+                t = do_escape(instance, t);
+        } else {
+
+                if (!(r = new(char, a*4 + c + 1)))
+                        return NULL;
+
+                t = do_escape(prefix, r);
+        }
+
+        strcpy(t, suffix);
+        return r;
+}
+
+char *unit_name_escape(const char *f) {
+        char *r, *t;
+
+        if (!(r = new(char, strlen(f)*4+1)))
+                return NULL;
+
+        t = do_escape(f, r);
+        *t = 0;
+
+        return r;
+
+}
+
+char *unit_name_unescape(const char *f) {
+        char *r, *t;
+
+        assert(f);
+
+        if (!(r = strdup(f)))
+                return NULL;
+
+        for (t = r; *f; f++) {
+                if (*f == '-')
+                        *(t++) = '/';
+                else if (*f == '\\') {
+                        int a, b;
+
+                        if (f[1] != 'x' ||
+                            (a = unhexchar(f[2])) < 0 ||
+                            (b = unhexchar(f[3])) < 0) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '\\';
+                        } else {
+                                *(t++) = (char) ((a << 4) | b);
+                                f += 3;
+                        }
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+bool unit_name_is_template(const char *n) {
+        const char *p;
+
+        assert(n);
+
+        if (!(p = strchr(n, '@')))
+                return false;
+
+        return p[1] == '.';
+}
+
+char *unit_name_replace_instance(const char *f, const char *i) {
+        const char *p, *e;
+        char *r, *k;
+        size_t a;
+
+        assert(f);
+
+        p = strchr(f, '@');
+        assert_se(e = strrchr(f, '.'));
+
+        a = p - f;
+
+        if (p) {
+                size_t b;
+
+                b = strlen(i);
+
+                if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
+                        return NULL;
+
+                k = mempcpy(r, f, a + 1);
+                k = mempcpy(k, i, b);
+        } else {
+
+                if (!(r = new(char, a + strlen(e) + 1)))
+                        return NULL;
+
+                k = mempcpy(r, f, a);
+        }
+
+        strcpy(k, e);
+        return r;
+}
+
+char *unit_name_template(const char *f) {
+        const char *p, *e;
+        char *r;
+        size_t a;
+
+        if (!(p = strchr(f, '@')))
+                return strdup(f);
+
+        assert_se(e = strrchr(f, '.'));
+        a = p - f + 1;
+
+        if (!(r = new(char, a + strlen(e) + 1)))
+                return NULL;
+
+        strcpy(mempcpy(r, f, a), e);
+        return r;
+
+}
+
+char *unit_name_from_path(const char *path, const char *suffix) {
+        char *p, *r;
+
+        assert(path);
+        assert(suffix);
+
+        if (!(p = strdup(path)))
+                return NULL;
+
+        path_kill_slashes(p);
+
+        path = p[0] == '/' ? p + 1 : p;
+
+        if (path[0] == 0) {
+                free(p);
+                return strappend("-", suffix);
+        }
+
+        r = unit_name_build_escape(path, NULL, suffix);
+        free(p);
+
+        return r;
+}
+
+char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
+        char *p, *r;
+
+        assert(path);
+        assert(suffix);
+
+        if (!(p = strdup(path)))
+                return NULL;
+
+        path_kill_slashes(p);
+
+        path = p[0] == '/' ? p + 1 : p;
+
+        if (path[0] == 0) {
+                free(p);
+                return unit_name_build_escape(prefix, "-", suffix);
+        }
+
+        r = unit_name_build_escape(prefix, path, suffix);
+        free(p);
+
+        return r;
+}
+
+char *unit_name_to_path(const char *name) {
+        char *w, *e;
+
+        assert(name);
+
+        if (!(w = unit_name_to_prefix(name)))
+                return NULL;
+
+        e = unit_name_unescape(w);
+        free(w);
+
+        if (!e)
+                return NULL;
+
+        if (e[0] != '/') {
+                w = strappend("/", e);
+                free(e);
+
+                if (!w)
+                        return NULL;
+
+                e = w;
+        }
+
+        return e;
+}
+
+char *unit_name_path_unescape(const char *f) {
+        char *e;
+
+        assert(f);
+
+        if (!(e = unit_name_unescape(f)))
+                return NULL;
+
+        if (e[0] != '/') {
+                char *w;
+
+                w = strappend("/", e);
+                free(e);
+
+                if (!w)
+                        return NULL;
+
+                e = w;
+        }
+
+        return e;
+}
diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h
new file mode 100644
index 0000000..4dfb9fa
--- /dev/null
+++ b/src/shared/unit-name.h
@@ -0,0 +1,57 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foounitnamehfoo
+#define foounitnamehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#define UNIT_NAME_MAX 256
+
+int unit_name_to_instance(const char *n, char **instance);
+char* unit_name_to_prefix(const char *n);
+char* unit_name_to_prefix_and_instance(const char *n);
+
+bool unit_name_is_valid_no_type(const char *n, bool template_ok);
+bool unit_prefix_is_valid(const char *p);
+bool unit_instance_is_valid(const char *i);
+
+char *unit_name_change_suffix(const char *n, const char *suffix);
+
+char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
+char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix);
+
+char *unit_name_escape(const char *f);
+char *unit_name_unescape(const char *f);
+
+char *unit_name_path_unescape(const char *f);
+
+bool unit_name_is_template(const char *n);
+
+char *unit_name_replace_instance(const char *f, const char *i);
+
+char *unit_name_template(const char *f);
+
+char *unit_name_from_path(const char *path, const char *suffix);
+char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix);
+char *unit_name_to_path(const char *name);
+
+#endif
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
new file mode 100644
index 0000000..6bba325
--- /dev/null
+++ b/src/shared/utmp-wtmp.c
@@ -0,0 +1,430 @@
+/*-*- 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 Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <utmpx.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/poll.h>
+
+#include "macro.h"
+#include "utmp-wtmp.h"
+
+int utmp_get_runlevel(int *runlevel, int *previous) {
+        struct utmpx lookup, *found;
+        int r;
+        const char *e;
+
+        assert(runlevel);
+
+        /* If these values are set in the environment this takes
+         * precedence. Presumably, sysvinit does this to work around a
+         * race condition that would otherwise exist where we'd always
+         * go to disk and hence might read runlevel data that might be
+         * very new and does not apply to the current script being
+         * executed. */
+
+        if ((e = getenv("RUNLEVEL")) && e[0] > 0) {
+                *runlevel = e[0];
+
+                if (previous) {
+                        /* $PREVLEVEL seems to be an Upstart thing */
+
+                        if ((e = getenv("PREVLEVEL")) && e[0] > 0)
+                                *previous = e[0];
+                        else
+                                *previous = 0;
+                }
+
+                return 0;
+        }
+
+        if (utmpxname(_PATH_UTMPX) < 0)
+                return -errno;
+
+        setutxent();
+
+        zero(lookup);
+        lookup.ut_type = RUN_LVL;
+
+        if (!(found = getutxid(&lookup)))
+                r = -errno;
+        else {
+                int a, b;
+
+                a = found->ut_pid & 0xFF;
+                b = (found->ut_pid >> 8) & 0xFF;
+
+                if (a < 0 || b < 0)
+                        r = -EIO;
+                else {
+                        *runlevel = a;
+
+                        if (previous)
+                                *previous = b;
+                        r = 0;
+                }
+        }
+
+        endutxent();
+
+        return r;
+}
+
+static void init_timestamp(struct utmpx *store, usec_t t) {
+        assert(store);
+
+        zero(*store);
+
+        if (t <= 0)
+                t = now(CLOCK_REALTIME);
+
+        store->ut_tv.tv_sec = t / USEC_PER_SEC;
+        store->ut_tv.tv_usec = t % USEC_PER_SEC;
+}
+
+static void init_entry(struct utmpx *store, usec_t t) {
+        struct utsname uts;
+
+        assert(store);
+
+        init_timestamp(store, t);
+
+        zero(uts);
+
+        if (uname(&uts) >= 0)
+                strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
+
+        strncpy(store->ut_line, "~", sizeof(store->ut_line));  /* or ~~ ? */
+        strncpy(store->ut_id, "~~", sizeof(store->ut_id));
+}
+
+static int write_entry_utmp(const struct utmpx *store) {
+        int r;
+
+        assert(store);
+
+        /* utmp is similar to wtmp, but there is only one entry for
+         * each entry type resp. user; i.e. basically a key/value
+         * table. */
+
+        if (utmpxname(_PATH_UTMPX) < 0)
+                return -errno;
+
+        setutxent();
+
+        if (!pututxline(store))
+                r = -errno;
+        else
+                r = 0;
+
+        endutxent();
+
+        return r;
+}
+
+static int write_entry_wtmp(const struct utmpx *store) {
+        assert(store);
+
+        /* wtmp is a simple append-only file where each entry is
+        simply appended to * the end; i.e. basically a log. */
+
+        errno = 0;
+        updwtmpx(_PATH_WTMPX, store);
+        return -errno;
+}
+
+static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) {
+        int r, s;
+
+        r = write_entry_utmp(store_utmp);
+        s = write_entry_wtmp(store_wtmp);
+
+        if (r >= 0)
+                r = s;
+
+        /* If utmp/wtmp have been disabled, that's a good thing, hence
+         * ignore the errors */
+        if (r == -ENOENT)
+                r = 0;
+
+        return r;
+}
+
+static int write_entry_both(const struct utmpx *store) {
+        return write_utmp_wtmp(store, store);
+}
+
+int utmp_put_shutdown(void) {
+        struct utmpx store;
+
+        init_entry(&store, 0);
+
+        store.ut_type = RUN_LVL;
+        strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
+
+        return write_entry_both(&store);
+}
+
+int utmp_put_reboot(usec_t t) {
+        struct utmpx store;
+
+        init_entry(&store, t);
+
+        store.ut_type = BOOT_TIME;
+        strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
+
+        return write_entry_both(&store);
+}
+
+static const char *sanitize_id(const char *id) {
+        size_t l;
+
+        assert(id);
+        l = strlen(id);
+
+        if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
+                return id;
+
+        return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
+}
+
+int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) {
+        struct utmpx store;
+
+        assert(id);
+
+        init_timestamp(&store, 0);
+
+        store.ut_type = INIT_PROCESS;
+        store.ut_pid = pid;
+        store.ut_session = sid;
+
+        strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
+
+        if (line)
+                strncpy(store.ut_line, file_name_from_path(line), sizeof(store.ut_line));
+
+        return write_entry_both(&store);
+}
+
+int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
+        struct utmpx lookup, store, store_wtmp, *found;
+
+        assert(id);
+
+        setutxent();
+
+        zero(lookup);
+        lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
+        strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
+
+        if (!(found = getutxid(&lookup)))
+                return 0;
+
+        if (found->ut_pid != pid)
+                return 0;
+
+        memcpy(&store, found, sizeof(store));
+        store.ut_type = DEAD_PROCESS;
+        store.ut_exit.e_termination = code;
+        store.ut_exit.e_exit = status;
+
+        zero(store.ut_user);
+        zero(store.ut_host);
+        zero(store.ut_tv);
+
+        memcpy(&store_wtmp, &store, sizeof(store_wtmp));
+        /* wtmp wants the current time */
+        init_timestamp(&store_wtmp, 0);
+
+        return write_utmp_wtmp(&store, &store_wtmp);
+}
+
+
+int utmp_put_runlevel(int runlevel, int previous) {
+        struct utmpx store;
+        int r;
+
+        assert(runlevel > 0);
+
+        if (previous <= 0) {
+                /* Find the old runlevel automatically */
+
+                if ((r = utmp_get_runlevel(&previous, NULL)) < 0) {
+                        if (r != -ESRCH)
+                                return r;
+
+                        previous = 0;
+                }
+        }
+
+        if (previous == runlevel)
+                return 0;
+
+        init_entry(&store, 0);
+
+        store.ut_type = RUN_LVL;
+        store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
+        strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
+
+        return write_entry_both(&store);
+}
+
+#define TIMEOUT_MSEC 50
+
+static int write_to_terminal(const char *tty, const char *message) {
+        int fd, r;
+        const char *p;
+        size_t left;
+        usec_t end;
+
+        assert(tty);
+        assert(message);
+
+        if ((fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC)) < 0)
+                return -errno;
+
+        if (!isatty(fd)) {
+                r = -errno;
+                goto finish;
+        }
+
+        p = message;
+        left = strlen(message);
+
+        end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC;
+
+        while (left > 0) {
+                ssize_t n;
+                struct pollfd pollfd;
+                usec_t t;
+                int k;
+
+                t = now(CLOCK_MONOTONIC);
+
+                if (t >= end) {
+                        r = -ETIME;
+                        goto finish;
+                }
+
+                zero(pollfd);
+                pollfd.fd = fd;
+                pollfd.events = POLLOUT;
+
+                if ((k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC)) < 0)
+                        return -errno;
+
+                if (k <= 0) {
+                        r = -ETIME;
+                        goto finish;
+                }
+
+                if ((n = write(fd, p, left)) < 0) {
+
+                        if (errno == EAGAIN)
+                                continue;
+
+                        r = -errno;
+                        goto finish;
+                }
+
+                assert((size_t) n <= left);
+
+                p += n;
+                left -= n;
+        }
+
+        r = 0;
+
+finish:
+        close_nointr_nofail(fd);
+
+        return r;
+}
+
+int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
+        struct utmpx *u;
+        char date[FORMAT_TIMESTAMP_MAX];
+        char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
+        int r;
+
+        if (!(hn = gethostname_malloc()) ||
+            !(un = getlogname_malloc())) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        getttyname_harder(STDIN_FILENO, &tty);
+
+        if (asprintf(&text,
+                     "\a\r\n"
+                     "Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
+                     "%s\r\n\r\n",
+                     un, hn,
+                     tty ? " on " : "", strempty(tty),
+                     format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
+                     message) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        setutxent();
+
+        r = 0;
+
+        while ((u = getutxent())) {
+                int q;
+                const char *path;
+                char *buf = NULL;
+
+                if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
+                        continue;
+
+                if (path_startswith(u->ut_line, "/dev/"))
+                        path = u->ut_line;
+                else {
+                        if (asprintf(&buf, "/dev/%s", u->ut_line) < 0) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        path = buf;
+                }
+
+                if (!match_tty || match_tty(path))
+                        if ((q = write_to_terminal(path, text)) < 0)
+                                r = q;
+
+                free(buf);
+        }
+
+finish:
+        free(hn);
+        free(un);
+        free(tty);
+        free(text);
+
+        return r;
+}
diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h
new file mode 100644
index 0000000..ab95061
--- /dev/null
+++ b/src/shared/utmp-wtmp.h
@@ -0,0 +1,38 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooutmpwtmphfoo
+#define fooutmpwtmphfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+int utmp_get_runlevel(int *runlevel, int *previous);
+
+int utmp_put_shutdown(void);
+int utmp_put_reboot(usec_t timestamp);
+int utmp_put_runlevel(int runlevel, int previous);
+
+int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
+int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line);
+
+int utmp_wall(const char *message, bool (*match_tty)(const char *tty));
+
+#endif
diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c
new file mode 100644
index 0000000..13265e7
--- /dev/null
+++ b/src/shared/watchdog.c
@@ -0,0 +1,169 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/watchdog.h>
+
+#include "watchdog.h"
+#include "log.h"
+
+static int watchdog_fd = -1;
+static usec_t watchdog_timeout = (usec_t) -1;
+
+static int update_timeout(void) {
+        int r;
+
+        if (watchdog_fd < 0)
+                return 0;
+
+        if (watchdog_timeout == (usec_t) -1)
+                return 0;
+        else if (watchdog_timeout == 0) {
+                int flags;
+
+                flags = WDIOS_DISABLECARD;
+                r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
+                if (r < 0) {
+                        log_warning("Failed to disable hardware watchdog: %m");
+                        return -errno;
+                }
+        } else {
+                int sec, flags;
+                char buf[FORMAT_TIMESPAN_MAX];
+
+                sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
+                r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
+                if (r < 0) {
+                        log_warning("Failed to set timeout to %is: %m", sec);
+                        return -errno;
+                }
+
+                watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
+                log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout));
+
+                flags = WDIOS_ENABLECARD;
+                r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
+                if (r < 0) {
+                        log_warning("Failed to enable hardware watchdog: %m");
+                        return -errno;
+                }
+
+                r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
+                if (r < 0) {
+                        log_warning("Failed to ping hardware watchdog: %m");
+                        return -errno;
+                }
+        }
+
+        return 0;
+}
+
+static int open_watchdog(void) {
+        struct watchdog_info ident;
+
+        if (watchdog_fd >= 0)
+                return 0;
+
+        watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
+        if (watchdog_fd < 0)
+                return -errno;
+
+        if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0)
+                log_info("Hardware watchdog '%s', version %x",
+                         ident.identity,
+                         ident.firmware_version);
+
+        return update_timeout();
+}
+
+int watchdog_set_timeout(usec_t *usec) {
+        int r;
+
+        watchdog_timeout = *usec;
+
+        /* If we didn't open the watchdog yet and didn't get any
+         * explicit timeout value set, don't do anything */
+        if (watchdog_fd < 0 && watchdog_timeout == (usec_t) -1)
+                return 0;
+
+        if (watchdog_fd < 0)
+                r = open_watchdog();
+        else
+                r = update_timeout();
+
+        *usec = watchdog_timeout;
+
+        return r;
+}
+
+int watchdog_ping(void) {
+        int r;
+
+        if (watchdog_fd < 0) {
+                r = open_watchdog();
+                if (r < 0)
+                        return r;
+        }
+
+        r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
+        if (r < 0) {
+                log_warning("Failed to ping hardware watchdog: %m");
+                return -errno;
+        }
+
+        return 0;
+}
+
+void watchdog_close(bool disarm) {
+        int r;
+
+        if (watchdog_fd < 0)
+                return;
+
+        if (disarm) {
+                int flags;
+
+                /* Explicitly disarm it */
+                flags = WDIOS_DISABLECARD;
+                r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
+                if (r < 0)
+                        log_warning("Failed to disable hardware watchdog: %m");
+
+                /* To be sure, use magic close logic, too */
+                for (;;) {
+                        static const char v = 'V';
+
+                        if (write(watchdog_fd, &v, 1) > 0)
+                                break;
+
+                        if (errno != EINTR) {
+                                log_error("Failed to disarm watchdog timer: %m");
+                                break;
+                        }
+                }
+        }
+
+        close_nointr_nofail(watchdog_fd);
+        watchdog_fd = -1;
+}
diff --git a/src/shared/watchdog.h b/src/shared/watchdog.h
new file mode 100644
index 0000000..2e00cb9
--- /dev/null
+++ b/src/shared/watchdog.h
@@ -0,0 +1,31 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foowatchdoghfoo
+#define foowatchdoghfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+int watchdog_set_timeout(usec_t *usec);
+int watchdog_ping(void);
+void watchdog_close(bool disarm);
+
+#endif
diff --git a/src/spawn-ask-password-agent.c b/src/spawn-ask-password-agent.c
deleted file mode 100644
index c1a9c58..0000000
--- a/src/spawn-ask-password-agent.c
+++ /dev/null
@@ -1,67 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <signal.h>
-#include <fcntl.h>
-
-#include "log.h"
-#include "util.h"
-#include "spawn-ask-password-agent.h"
-
-static pid_t agent_pid = 0;
-
-int ask_password_agent_open(void) {
-        int r;
-
-        if (agent_pid > 0)
-                return 0;
-
-        /* We check STDIN here, not STDOUT, since this is about input,
-         * not output */
-        if (!isatty(STDIN_FILENO))
-                return 0;
-
-        r = fork_agent(&agent_pid,
-                       NULL, 0,
-                       SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
-                       SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
-        if (r < 0)
-                log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
-
-        return r;
-}
-
-void ask_password_agent_close(void) {
-
-        if (agent_pid <= 0)
-                return;
-
-        /* Inform agent that we are done */
-        kill(agent_pid, SIGTERM);
-        kill(agent_pid, SIGCONT);
-        wait_for_terminate(agent_pid, NULL);
-        agent_pid = 0;
-}
diff --git a/src/spawn-ask-password-agent.h b/src/spawn-ask-password-agent.h
deleted file mode 100644
index fa5e7b0..0000000
--- a/src/spawn-ask-password-agent.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foospawnaskpasswordagenthfoo
-#define foospawnaskpasswordagenthfoo
-
-/***
-  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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int ask_password_agent_open(void);
-void ask_password_agent_close(void);
-
-#endif
diff --git a/src/spawn-polkit-agent.c b/src/spawn-polkit-agent.c
deleted file mode 100644
index fd72588..0000000
--- a/src/spawn-polkit-agent.c
+++ /dev/null
@@ -1,86 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/poll.h>
-
-#include "log.h"
-#include "util.h"
-#include "spawn-polkit-agent.h"
-
-static pid_t agent_pid = 0;
-
-int polkit_agent_open(void) {
-        int r;
-        int pipe_fd[2];
-        char notify_fd[10 + 1];
-
-        if (agent_pid > 0)
-                return 0;
-
-        /* We check STDIN here, not STDOUT, since this is about input,
-         * not output */
-        if (!isatty(STDIN_FILENO))
-                return 0;
-
-        if (pipe2(pipe_fd, 0) < 0)
-                return -errno;
-
-        snprintf(notify_fd, sizeof(notify_fd), "%i", pipe_fd[1]);
-        char_array_0(notify_fd);
-
-        r = fork_agent(&agent_pid,
-                       &pipe_fd[1], 1,
-                       POLKIT_AGENT_BINARY_PATH,
-                       POLKIT_AGENT_BINARY_PATH, "--notify-fd", notify_fd, NULL);
-
-        /* Close the writing side, because that's the one for the agent */
-        close_nointr_nofail(pipe_fd[1]);
-
-        if (r < 0)
-                log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
-        else
-                /* Wait until the agent closes the fd */
-                fd_wait_for_event(pipe_fd[0], POLLHUP, (usec_t) -1);
-
-        close_nointr_nofail(pipe_fd[0]);
-
-        return r;
-}
-
-void polkit_agent_close(void) {
-
-        if (agent_pid <= 0)
-                return;
-
-        /* Inform agent that we are done */
-        kill(agent_pid, SIGTERM);
-        kill(agent_pid, SIGCONT);
-        wait_for_terminate(agent_pid, NULL);
-        agent_pid = 0;
-}
diff --git a/src/spawn-polkit-agent.h b/src/spawn-polkit-agent.h
deleted file mode 100644
index b91d20f..0000000
--- a/src/spawn-polkit-agent.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foospawnpolkitagenthfoo
-#define foospawnpolkitagenthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int polkit_agent_open(void);
-void polkit_agent_close(void);
-
-#endif
diff --git a/src/specifier.c b/src/specifier.c
deleted file mode 100644
index ae00ae1..0000000
--- a/src/specifier.c
+++ /dev/null
@@ -1,108 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-
-#include "macro.h"
-#include "util.h"
-#include "specifier.h"
-
-/*
- * Generic infrastructure for replacing %x style specifiers in
- * strings. Will call a callback for each replacement.
- *
- */
-
-char *specifier_printf(const char *text, const Specifier table[], void *userdata) {
-        char *r, *t;
-        const char *f;
-        bool percent = false;
-        size_t l;
-
-        assert(text);
-        assert(table);
-
-        l = strlen(text);
-        if (!(r = new(char, l+1)))
-                return NULL;
-
-        t = r;
-
-        for (f = text; *f; f++, l--) {
-
-                if (percent) {
-                        if (*f == '%')
-                                *(t++) = '%';
-                        else {
-                                const Specifier *i;
-
-                                for (i = table; i->specifier; i++)
-                                        if (i->specifier == *f)
-                                                break;
-
-                                if (i->lookup) {
-                                        char *n, *w;
-                                        size_t k, j;
-
-                                        if (!(w = i->lookup(i->specifier, i->data, userdata))) {
-                                                free(r);
-                                                return NULL;
-                                        }
-
-                                        j = t - r;
-                                        k = strlen(w);
-
-                                        if (!(n = new(char, j + k + l + 1))) {
-                                                free(r);
-                                                free(w);
-                                                return NULL;
-                                        }
-
-                                        memcpy(n, r, j);
-                                        memcpy(n + j, w, k);
-
-                                        free(r);
-                                        free(w);
-
-                                        r = n;
-                                        t = n + j + k;
-                                } else {
-                                        *(t++) = '%';
-                                        *(t++) = *f;
-                                }
-                        }
-
-                        percent = false;
-                } else if (*f == '%')
-                        percent = true;
-                else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-        return r;
-}
-
-/* Generic handler for simple string replacements */
-
-char* specifier_string(char specifier, void *data, void *userdata) {
-        return strdup(strempty(data));
-}
diff --git a/src/specifier.h b/src/specifier.h
deleted file mode 100644
index 57d1fcb..0000000
--- a/src/specifier.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foospecifierhfoo
-#define foospecifierhfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata);
-
-typedef struct Specifier {
-        const char specifier;
-        const SpecifierCallback lookup;
-        void *data;
-} Specifier;
-
-char *specifier_printf(const char *text, const Specifier table[], void *userdata);
-
-char* specifier_string(char specifier, void *data, void *userdata);
-
-#endif
diff --git a/src/umount.c b/src/umount.c
deleted file mode 100644
index 24c0947..0000000
--- a/src/umount.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 ProFUSION embedded systems
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/swap.h>
-#include <unistd.h>
-#include <linux/loop.h>
-#include <linux/dm-ioctl.h>
-#include <libudev.h>
-
-#include "list.h"
-#include "mount-setup.h"
-#include "umount.h"
-#include "util.h"
-
-typedef struct MountPoint {
-        char *path;
-        dev_t devnum;
-        bool skip_ro;
-        LIST_FIELDS (struct MountPoint, mount_point);
-} MountPoint;
-
-static void mount_point_free(MountPoint **head, MountPoint *m) {
-        assert(head);
-        assert(m);
-
-        LIST_REMOVE(MountPoint, mount_point, *head, m);
-
-        free(m->path);
-        free(m);
-}
-
-static void mount_points_list_free(MountPoint **head) {
-        assert(head);
-
-        while (*head)
-                mount_point_free(head, *head);
-}
-
-static int mount_points_list_get(MountPoint **head) {
-        FILE *proc_self_mountinfo;
-        char *path, *p;
-        unsigned int i;
-        int r;
-
-        assert(head);
-
-        if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
-                return -errno;
-
-        for (i = 1;; i++) {
-                int k;
-                MountPoint *m;
-                char *root;
-                bool skip_ro;
-
-                path = p = NULL;
-
-                if ((k = fscanf(proc_self_mountinfo,
-                                "%*s "       /* (1) mount id */
-                                "%*s "       /* (2) parent id */
-                                "%*s "       /* (3) major:minor */
-                                "%ms "       /* (4) root */
-                                "%ms "       /* (5) mount point */
-                                "%*s"        /* (6) mount options */
-                                "%*[^-]"     /* (7) optional fields */
-                                "- "         /* (8) separator */
-                                "%*s "       /* (9) file system type */
-                                "%*s"        /* (10) mount source */
-                                "%*s"        /* (11) mount options 2 */
-                                "%*[^\n]",   /* some rubbish at the end */
-                                &root,
-                                &path)) != 2) {
-                        if (k == EOF)
-                                break;
-
-                        log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
-
-                        free(path);
-                        continue;
-                }
-
-                /* If we encounter a bind mount, don't try to remount
-                 * the source dir too early */
-                skip_ro = !streq(root, "/");
-                free(root);
-
-                p = cunescape(path);
-                free(path);
-
-                if (!p) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (mount_point_is_api(p) || mount_point_ignore(p)) {
-                        free(p);
-                        continue;
-                }
-
-                if (!(m = new0(MountPoint, 1))) {
-                        free(p);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                m->path = p;
-                m->skip_ro = skip_ro;
-                LIST_PREPEND(MountPoint, mount_point, *head, m);
-        }
-
-        r = 0;
-
-finish:
-        fclose(proc_self_mountinfo);
-
-        return r;
-}
-
-static int swap_list_get(MountPoint **head) {
-        FILE *proc_swaps;
-        unsigned int i;
-        int r;
-
-        assert(head);
-
-        if (!(proc_swaps = fopen("/proc/swaps", "re")))
-                return (errno == ENOENT) ? 0 : -errno;
-
-        (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
-
-        for (i = 2;; i++) {
-                MountPoint *swap;
-                char *dev = NULL, *d;
-                int k;
-
-                if ((k = fscanf(proc_swaps,
-                                "%ms " /* device/file */
-                                "%*s " /* type of swap */
-                                "%*s " /* swap size */
-                                "%*s " /* used */
-                                "%*s\n", /* priority */
-                                &dev)) != 1) {
-
-                        if (k == EOF)
-                                break;
-
-                        log_warning("Failed to parse /proc/swaps:%u.", i);
-
-                        free(dev);
-                        continue;
-                }
-
-                if (endswith(dev, "(deleted)")) {
-                        free(dev);
-                        continue;
-                }
-
-                d = cunescape(dev);
-                free(dev);
-
-                if (!d) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(swap = new0(MountPoint, 1))) {
-                        free(d);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                swap->path = d;
-                LIST_PREPEND(MountPoint, mount_point, *head, swap);
-        }
-
-        r = 0;
-
-finish:
-        fclose(proc_swaps);
-
-        return r;
-}
-
-static int loopback_list_get(MountPoint **head) {
-        int r;
-        struct udev *udev;
-        struct udev_enumerate *e = NULL;
-        struct udev_list_entry *item = NULL, *first = NULL;
-
-        assert(head);
-
-        if (!(udev = udev_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!(e = udev_enumerate_new(udev))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
-            udev_enumerate_add_match_sysname(e, "loop*") < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first) {
-                MountPoint *lb;
-                struct udev_device *d;
-                char *loop;
-                const char *dn;
-
-                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(dn = udev_device_get_devnode(d))) {
-                        udev_device_unref(d);
-                        continue;
-                }
-
-                loop = strdup(dn);
-                udev_device_unref(d);
-
-                if (!loop) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(lb = new0(MountPoint, 1))) {
-                        free(loop);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                lb->path = loop;
-                LIST_PREPEND(MountPoint, mount_point, *head, lb);
-        }
-
-        r = 0;
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        if (udev)
-                udev_unref(udev);
-
-        return r;
-}
-
-static int dm_list_get(MountPoint **head) {
-        int r;
-        struct udev *udev;
-        struct udev_enumerate *e = NULL;
-        struct udev_list_entry *item = NULL, *first = NULL;
-
-        assert(head);
-
-        if (!(udev = udev_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!(e = udev_enumerate_new(udev))) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
-            udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        first = udev_enumerate_get_list_entry(e);
-
-        udev_list_entry_foreach(item, first) {
-                MountPoint *m;
-                struct udev_device *d;
-                dev_t devnum;
-                char *node;
-                const char *dn;
-
-                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                devnum = udev_device_get_devnum(d);
-                dn = udev_device_get_devnode(d);
-
-                if (major(devnum) == 0 || !dn) {
-                        udev_device_unref(d);
-                        continue;
-                }
-
-                node = strdup(dn);
-                udev_device_unref(d);
-
-                if (!node) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!(m = new(MountPoint, 1))) {
-                        free(node);
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                m->path = node;
-                m->devnum = devnum;
-                LIST_PREPEND(MountPoint, mount_point, *head, m);
-        }
-
-        r = 0;
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        if (udev)
-                udev_unref(udev);
-
-        return r;
-}
-
-static int delete_loopback(const char *device) {
-        int fd, r;
-
-        if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
-                return errno == ENOENT ? 0 : -errno;
-
-        r = ioctl(fd, LOOP_CLR_FD, 0);
-        close_nointr_nofail(fd);
-
-        if (r >= 0)
-                return 1;
-
-        /* ENXIO: not bound, so no error */
-        if (errno == ENXIO)
-                return 0;
-
-        return -errno;
-}
-
-static int delete_dm(dev_t devnum) {
-        int fd, r;
-        struct dm_ioctl dm;
-
-        assert(major(devnum) != 0);
-
-        if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
-                return -errno;
-
-        zero(dm);
-        dm.version[0] = DM_VERSION_MAJOR;
-        dm.version[1] = DM_VERSION_MINOR;
-        dm.version[2] = DM_VERSION_PATCHLEVEL;
-
-        dm.data_size = sizeof(dm);
-        dm.dev = devnum;
-
-        r = ioctl(fd, DM_DEV_REMOVE, &dm);
-        close_nointr_nofail(fd);
-
-        return r >= 0 ? 0 : -errno;
-}
-
-static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
-        MountPoint *m, *n;
-        int n_failed = 0;
-
-        assert(head);
-
-        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-                if (path_equal(m->path, "/")
-#ifndef HAVE_SPLIT_USR
-                    || path_equal(m->path, "/usr")
-#endif
-                ) {
-                        n_failed++;
-                        continue;
-                }
-
-                /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
-                if (umount2(m->path, MNT_FORCE) == 0) {
-                        log_info("Unmounted %s.", m->path);
-                        if (changed)
-                                *changed = true;
-
-                        mount_point_free(head, m);
-                } else if (log_error) {
-                        log_warning("Could not unmount %s: %m", m->path);
-                        n_failed++;
-                }
-        }
-
-        return n_failed;
-}
-
-static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
-        MountPoint *m, *n;
-        int n_failed = 0;
-
-        assert(head);
-
-        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-
-                if (m->skip_ro) {
-                        n_failed++;
-                        continue;
-                }
-
-                /* Trying to remount read-only */
-                if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) {
-                        if (changed)
-                                *changed = true;
-
-                        mount_point_free(head, m);
-                } else {
-                        log_warning("Could not remount as read-only %s: %m", m->path);
-                        n_failed++;
-                }
-        }
-
-        return n_failed;
-}
-
-static int swap_points_list_off(MountPoint **head, bool *changed) {
-        MountPoint *m, *n;
-        int n_failed = 0;
-
-        assert(head);
-
-        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-                if (swapoff(m->path) == 0) {
-                        if (changed)
-                                *changed = true;
-
-                        mount_point_free(head, m);
-                } else {
-                        log_warning("Could not deactivate swap %s: %m", m->path);
-                        n_failed++;
-                }
-        }
-
-        return n_failed;
-}
-
-static int loopback_points_list_detach(MountPoint **head, bool *changed) {
-        MountPoint *m, *n;
-        int n_failed = 0, k;
-        struct stat root_st;
-
-        assert(head);
-
-        k = lstat("/", &root_st);
-
-        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-                int r;
-                struct stat loopback_st;
-
-                if (k >= 0 &&
-                    major(root_st.st_dev) != 0 &&
-                    lstat(m->path, &loopback_st) >= 0 &&
-                    root_st.st_dev == loopback_st.st_rdev) {
-                        n_failed ++;
-                        continue;
-                }
-
-                if ((r = delete_loopback(m->path)) >= 0) {
-
-                        if (r > 0 && changed)
-                                *changed = true;
-
-                        mount_point_free(head, m);
-                } else {
-                        log_warning("Could not delete loopback %s: %m", m->path);
-                        n_failed++;
-                }
-        }
-
-        return n_failed;
-}
-
-static int dm_points_list_detach(MountPoint **head, bool *changed) {
-        MountPoint *m, *n;
-        int n_failed = 0, k;
-        struct stat root_st;
-
-        assert(head);
-
-        k = lstat("/", &root_st);
-
-        LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-                int r;
-
-                if (k >= 0 &&
-                    major(root_st.st_dev) != 0 &&
-                    root_st.st_dev == m->devnum) {
-                        n_failed ++;
-                        continue;
-                }
-
-                if ((r = delete_dm(m->devnum)) >= 0) {
-
-                        if (r > 0 && changed)
-                                *changed = true;
-
-                        mount_point_free(head, m);
-                } else {
-                        log_warning("Could not delete dm %s: %m", m->path);
-                        n_failed++;
-                }
-        }
-
-        return n_failed;
-}
-
-int umount_all(bool *changed) {
-        int r;
-        bool umount_changed;
-
-        LIST_HEAD(MountPoint, mp_list_head);
-
-        LIST_HEAD_INIT(MountPoint, mp_list_head);
-
-        r = mount_points_list_get(&mp_list_head);
-        if (r < 0)
-                goto end;
-
-        /* retry umount, until nothing can be umounted anymore */
-        do {
-                umount_changed = false;
-
-                mount_points_list_umount(&mp_list_head, &umount_changed, false);
-                if (umount_changed)
-                        *changed = true;
-
-        } while (umount_changed);
-
-        /* umount one more time with logging enabled */
-        r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
-        if (r <= 0)
-                goto end;
-
-        r = mount_points_list_remount_read_only(&mp_list_head, changed);
-
-  end:
-        mount_points_list_free(&mp_list_head);
-
-        return r;
-}
-
-int swapoff_all(bool *changed) {
-        int r;
-        LIST_HEAD(MountPoint, swap_list_head);
-
-        LIST_HEAD_INIT(MountPoint, swap_list_head);
-
-        r = swap_list_get(&swap_list_head);
-        if (r < 0)
-                goto end;
-
-        r = swap_points_list_off(&swap_list_head, changed);
-
-  end:
-        mount_points_list_free(&swap_list_head);
-
-        return r;
-}
-
-int loopback_detach_all(bool *changed) {
-        int r;
-        LIST_HEAD(MountPoint, loopback_list_head);
-
-        LIST_HEAD_INIT(MountPoint, loopback_list_head);
-
-        r = loopback_list_get(&loopback_list_head);
-        if (r < 0)
-                goto end;
-
-        r = loopback_points_list_detach(&loopback_list_head, changed);
-
-  end:
-        mount_points_list_free(&loopback_list_head);
-
-        return r;
-}
-
-int dm_detach_all(bool *changed) {
-        int r;
-        LIST_HEAD(MountPoint, dm_list_head);
-
-        LIST_HEAD_INIT(MountPoint, dm_list_head);
-
-        r = dm_list_get(&dm_list_head);
-        if (r < 0)
-                goto end;
-
-        r = dm_points_list_detach(&dm_list_head, changed);
-
-  end:
-        mount_points_list_free(&dm_list_head);
-
-        return r;
-}
diff --git a/src/umount.h b/src/umount.h
deleted file mode 100644
index 2e2f9c1..0000000
--- a/src/umount.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooumounthfoo
-#define fooumounthfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 ProFUSION embedded systems
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int umount_all(bool *changed);
-
-int swapoff_all(bool *changed);
-
-int loopback_detach_all(bool *changed);
-
-int dm_detach_all(bool *changed);
-
-#endif
diff --git a/src/unit-name.c b/src/unit-name.c
deleted file mode 100644
index 566cdc5..0000000
--- a/src/unit-name.c
+++ /dev/null
@@ -1,448 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-
-#include "util.h"
-#include "unit-name.h"
-
-#define VALID_CHARS                             \
-        "0123456789"                            \
-        "abcdefghijklmnopqrstuvwxyz"            \
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
-        ":-_.\\"
-
-bool unit_name_is_valid_no_type(const char *n, bool template_ok) {
-        const char *e, *i, *at;
-
-        /* Valid formats:
-         *
-         *         string at instance.suffix
-         *         string.suffix
-         */
-
-        assert(n);
-
-        if (strlen(n) >= UNIT_NAME_MAX)
-                return false;
-
-        e = strrchr(n, '.');
-        if (!e || e == n)
-                return false;
-
-        for (i = n, at = NULL; i < e; i++) {
-
-                if (*i == '@' && !at)
-                        at = i;
-
-                if (!strchr("@" VALID_CHARS, *i))
-                        return false;
-        }
-
-        if (at) {
-                if (at == n)
-                        return false;
-
-                if (!template_ok && at+1 == e)
-                        return false;
-        }
-
-        return true;
-}
-
-bool unit_instance_is_valid(const char *i) {
-        assert(i);
-
-        /* The max length depends on the length of the string, so we
-         * don't really check this here. */
-
-        if (i[0] == 0)
-                return false;
-
-        /* We allow additional @ in the instance string, we do not
-         * allow them in the prefix! */
-
-        for (; *i; i++)
-                if (!strchr("@" VALID_CHARS, *i))
-                        return false;
-
-        return true;
-}
-
-bool unit_prefix_is_valid(const char *p) {
-
-        /* We don't allow additional @ in the instance string */
-
-        if (p[0] == 0)
-                return false;
-
-        for (; *p; p++)
-                if (!strchr(VALID_CHARS, *p))
-                        return false;
-
-        return true;
-}
-
-int unit_name_to_instance(const char *n, char **instance) {
-        const char *p, *d;
-        char *i;
-
-        assert(n);
-        assert(instance);
-
-        /* Everything past the first @ and before the last . is the instance */
-        if (!(p = strchr(n, '@'))) {
-                *instance = NULL;
-                return 0;
-        }
-
-        assert_se(d = strrchr(n, '.'));
-        assert(p < d);
-
-        if (!(i = strndup(p+1, d-p-1)))
-                return -ENOMEM;
-
-        *instance = i;
-        return 0;
-}
-
-char *unit_name_to_prefix_and_instance(const char *n) {
-        const char *d;
-
-        assert(n);
-
-        assert_se(d = strrchr(n, '.'));
-
-        return strndup(n, d - n);
-}
-
-char *unit_name_to_prefix(const char *n) {
-        const char *p;
-
-        if ((p = strchr(n, '@')))
-                return strndup(n, p - n);
-
-        return unit_name_to_prefix_and_instance(n);
-}
-
-char *unit_name_change_suffix(const char *n, const char *suffix) {
-        char *e, *r;
-        size_t a, b;
-
-        assert(n);
-        assert(unit_name_is_valid_no_type(n, true));
-        assert(suffix);
-
-        assert_se(e = strrchr(n, '.'));
-        a = e - n;
-        b = strlen(suffix);
-
-        if (!(r = new(char, a + b + 1)))
-                return NULL;
-
-        memcpy(r, n, a);
-        memcpy(r+a, suffix, b+1);
-
-        return r;
-}
-
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
-        assert(prefix);
-        assert(unit_prefix_is_valid(prefix));
-        assert(!instance || unit_instance_is_valid(instance));
-        assert(suffix);
-
-        if (!instance)
-                return strappend(prefix, suffix);
-
-        return join(prefix, "@", instance, suffix, NULL);
-}
-
-static char* do_escape(const char *f, char *t) {
-        assert(f);
-        assert(t);
-
-        for (; *f; f++) {
-                if (*f == '/')
-                        *(t++) = '-';
-                else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        return t;
-}
-
-char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
-        char *r, *t;
-        size_t a, b, c;
-
-        assert(prefix);
-        assert(suffix);
-
-        /* Takes a arbitrary string for prefix and instance plus a
-         * suffix and makes a nice string suitable as unit name of it,
-         * escaping all weird chars on the way.
-         *
-         * / becomes ., and all chars not allowed in a unit name get
-         * escaped as \xFF, including \ and ., of course. This
-         * escaping is hence reversible.
-         *
-         * This is primarily useful to make nice unit names from
-         * strings, but is actually useful for any kind of string.
-         */
-
-        a = strlen(prefix);
-        c = strlen(suffix);
-
-        if (instance) {
-                b = strlen(instance);
-
-                if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
-                        return NULL;
-
-                t = do_escape(prefix, r);
-                *(t++) = '@';
-                t = do_escape(instance, t);
-        } else {
-
-                if (!(r = new(char, a*4 + c + 1)))
-                        return NULL;
-
-                t = do_escape(prefix, r);
-        }
-
-        strcpy(t, suffix);
-        return r;
-}
-
-char *unit_name_escape(const char *f) {
-        char *r, *t;
-
-        if (!(r = new(char, strlen(f)*4+1)))
-                return NULL;
-
-        t = do_escape(f, r);
-        *t = 0;
-
-        return r;
-
-}
-
-char *unit_name_unescape(const char *f) {
-        char *r, *t;
-
-        assert(f);
-
-        if (!(r = strdup(f)))
-                return NULL;
-
-        for (t = r; *f; f++) {
-                if (*f == '-')
-                        *(t++) = '/';
-                else if (*f == '\\') {
-                        int a, b;
-
-                        if (f[1] != 'x' ||
-                            (a = unhexchar(f[2])) < 0 ||
-                            (b = unhexchar(f[3])) < 0) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                        } else {
-                                *(t++) = (char) ((a << 4) | b);
-                                f += 3;
-                        }
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-bool unit_name_is_template(const char *n) {
-        const char *p;
-
-        assert(n);
-
-        if (!(p = strchr(n, '@')))
-                return false;
-
-        return p[1] == '.';
-}
-
-char *unit_name_replace_instance(const char *f, const char *i) {
-        const char *p, *e;
-        char *r, *k;
-        size_t a;
-
-        assert(f);
-
-        p = strchr(f, '@');
-        assert_se(e = strrchr(f, '.'));
-
-        a = p - f;
-
-        if (p) {
-                size_t b;
-
-                b = strlen(i);
-
-                if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
-                        return NULL;
-
-                k = mempcpy(r, f, a + 1);
-                k = mempcpy(k, i, b);
-        } else {
-
-                if (!(r = new(char, a + strlen(e) + 1)))
-                        return NULL;
-
-                k = mempcpy(r, f, a);
-        }
-
-        strcpy(k, e);
-        return r;
-}
-
-char *unit_name_template(const char *f) {
-        const char *p, *e;
-        char *r;
-        size_t a;
-
-        if (!(p = strchr(f, '@')))
-                return strdup(f);
-
-        assert_se(e = strrchr(f, '.'));
-        a = p - f + 1;
-
-        if (!(r = new(char, a + strlen(e) + 1)))
-                return NULL;
-
-        strcpy(mempcpy(r, f, a), e);
-        return r;
-
-}
-
-char *unit_name_from_path(const char *path, const char *suffix) {
-        char *p, *r;
-
-        assert(path);
-        assert(suffix);
-
-        if (!(p = strdup(path)))
-                return NULL;
-
-        path_kill_slashes(p);
-
-        path = p[0] == '/' ? p + 1 : p;
-
-        if (path[0] == 0) {
-                free(p);
-                return strappend("-", suffix);
-        }
-
-        r = unit_name_build_escape(path, NULL, suffix);
-        free(p);
-
-        return r;
-}
-
-char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
-        char *p, *r;
-
-        assert(path);
-        assert(suffix);
-
-        if (!(p = strdup(path)))
-                return NULL;
-
-        path_kill_slashes(p);
-
-        path = p[0] == '/' ? p + 1 : p;
-
-        if (path[0] == 0) {
-                free(p);
-                return unit_name_build_escape(prefix, "-", suffix);
-        }
-
-        r = unit_name_build_escape(prefix, path, suffix);
-        free(p);
-
-        return r;
-}
-
-char *unit_name_to_path(const char *name) {
-        char *w, *e;
-
-        assert(name);
-
-        if (!(w = unit_name_to_prefix(name)))
-                return NULL;
-
-        e = unit_name_unescape(w);
-        free(w);
-
-        if (!e)
-                return NULL;
-
-        if (e[0] != '/') {
-                w = strappend("/", e);
-                free(e);
-
-                if (!w)
-                        return NULL;
-
-                e = w;
-        }
-
-        return e;
-}
-
-char *unit_name_path_unescape(const char *f) {
-        char *e;
-
-        assert(f);
-
-        if (!(e = unit_name_unescape(f)))
-                return NULL;
-
-        if (e[0] != '/') {
-                char *w;
-
-                w = strappend("/", e);
-                free(e);
-
-                if (!w)
-                        return NULL;
-
-                e = w;
-        }
-
-        return e;
-}
diff --git a/src/unit-name.h b/src/unit-name.h
deleted file mode 100644
index 4dfb9fa..0000000
--- a/src/unit-name.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foounitnamehfoo
-#define foounitnamehfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#define UNIT_NAME_MAX 256
-
-int unit_name_to_instance(const char *n, char **instance);
-char* unit_name_to_prefix(const char *n);
-char* unit_name_to_prefix_and_instance(const char *n);
-
-bool unit_name_is_valid_no_type(const char *n, bool template_ok);
-bool unit_prefix_is_valid(const char *p);
-bool unit_instance_is_valid(const char *i);
-
-char *unit_name_change_suffix(const char *n, const char *suffix);
-
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
-char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix);
-
-char *unit_name_escape(const char *f);
-char *unit_name_unescape(const char *f);
-
-char *unit_name_path_unescape(const char *f);
-
-bool unit_name_is_template(const char *n);
-
-char *unit_name_replace_instance(const char *f, const char *i);
-
-char *unit_name_template(const char *f);
-
-char *unit_name_from_path(const char *path, const char *suffix);
-char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix);
-char *unit_name_to_path(const char *name);
-
-#endif
diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c
deleted file mode 100644
index 6bba325..0000000
--- a/src/utmp-wtmp.c
+++ /dev/null
@@ -1,430 +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 Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <utmpx.h>
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <sys/utsname.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/poll.h>
-
-#include "macro.h"
-#include "utmp-wtmp.h"
-
-int utmp_get_runlevel(int *runlevel, int *previous) {
-        struct utmpx lookup, *found;
-        int r;
-        const char *e;
-
-        assert(runlevel);
-
-        /* If these values are set in the environment this takes
-         * precedence. Presumably, sysvinit does this to work around a
-         * race condition that would otherwise exist where we'd always
-         * go to disk and hence might read runlevel data that might be
-         * very new and does not apply to the current script being
-         * executed. */
-
-        if ((e = getenv("RUNLEVEL")) && e[0] > 0) {
-                *runlevel = e[0];
-
-                if (previous) {
-                        /* $PREVLEVEL seems to be an Upstart thing */
-
-                        if ((e = getenv("PREVLEVEL")) && e[0] > 0)
-                                *previous = e[0];
-                        else
-                                *previous = 0;
-                }
-
-                return 0;
-        }
-
-        if (utmpxname(_PATH_UTMPX) < 0)
-                return -errno;
-
-        setutxent();
-
-        zero(lookup);
-        lookup.ut_type = RUN_LVL;
-
-        if (!(found = getutxid(&lookup)))
-                r = -errno;
-        else {
-                int a, b;
-
-                a = found->ut_pid & 0xFF;
-                b = (found->ut_pid >> 8) & 0xFF;
-
-                if (a < 0 || b < 0)
-                        r = -EIO;
-                else {
-                        *runlevel = a;
-
-                        if (previous)
-                                *previous = b;
-                        r = 0;
-                }
-        }
-
-        endutxent();
-
-        return r;
-}
-
-static void init_timestamp(struct utmpx *store, usec_t t) {
-        assert(store);
-
-        zero(*store);
-
-        if (t <= 0)
-                t = now(CLOCK_REALTIME);
-
-        store->ut_tv.tv_sec = t / USEC_PER_SEC;
-        store->ut_tv.tv_usec = t % USEC_PER_SEC;
-}
-
-static void init_entry(struct utmpx *store, usec_t t) {
-        struct utsname uts;
-
-        assert(store);
-
-        init_timestamp(store, t);
-
-        zero(uts);
-
-        if (uname(&uts) >= 0)
-                strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
-
-        strncpy(store->ut_line, "~", sizeof(store->ut_line));  /* or ~~ ? */
-        strncpy(store->ut_id, "~~", sizeof(store->ut_id));
-}
-
-static int write_entry_utmp(const struct utmpx *store) {
-        int r;
-
-        assert(store);
-
-        /* utmp is similar to wtmp, but there is only one entry for
-         * each entry type resp. user; i.e. basically a key/value
-         * table. */
-
-        if (utmpxname(_PATH_UTMPX) < 0)
-                return -errno;
-
-        setutxent();
-
-        if (!pututxline(store))
-                r = -errno;
-        else
-                r = 0;
-
-        endutxent();
-
-        return r;
-}
-
-static int write_entry_wtmp(const struct utmpx *store) {
-        assert(store);
-
-        /* wtmp is a simple append-only file where each entry is
-        simply appended to * the end; i.e. basically a log. */
-
-        errno = 0;
-        updwtmpx(_PATH_WTMPX, store);
-        return -errno;
-}
-
-static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) {
-        int r, s;
-
-        r = write_entry_utmp(store_utmp);
-        s = write_entry_wtmp(store_wtmp);
-
-        if (r >= 0)
-                r = s;
-
-        /* If utmp/wtmp have been disabled, that's a good thing, hence
-         * ignore the errors */
-        if (r == -ENOENT)
-                r = 0;
-
-        return r;
-}
-
-static int write_entry_both(const struct utmpx *store) {
-        return write_utmp_wtmp(store, store);
-}
-
-int utmp_put_shutdown(void) {
-        struct utmpx store;
-
-        init_entry(&store, 0);
-
-        store.ut_type = RUN_LVL;
-        strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
-
-int utmp_put_reboot(usec_t t) {
-        struct utmpx store;
-
-        init_entry(&store, t);
-
-        store.ut_type = BOOT_TIME;
-        strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
-
-static const char *sanitize_id(const char *id) {
-        size_t l;
-
-        assert(id);
-        l = strlen(id);
-
-        if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
-                return id;
-
-        return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
-}
-
-int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) {
-        struct utmpx store;
-
-        assert(id);
-
-        init_timestamp(&store, 0);
-
-        store.ut_type = INIT_PROCESS;
-        store.ut_pid = pid;
-        store.ut_session = sid;
-
-        strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
-
-        if (line)
-                strncpy(store.ut_line, file_name_from_path(line), sizeof(store.ut_line));
-
-        return write_entry_both(&store);
-}
-
-int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
-        struct utmpx lookup, store, store_wtmp, *found;
-
-        assert(id);
-
-        setutxent();
-
-        zero(lookup);
-        lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
-        strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
-
-        if (!(found = getutxid(&lookup)))
-                return 0;
-
-        if (found->ut_pid != pid)
-                return 0;
-
-        memcpy(&store, found, sizeof(store));
-        store.ut_type = DEAD_PROCESS;
-        store.ut_exit.e_termination = code;
-        store.ut_exit.e_exit = status;
-
-        zero(store.ut_user);
-        zero(store.ut_host);
-        zero(store.ut_tv);
-
-        memcpy(&store_wtmp, &store, sizeof(store_wtmp));
-        /* wtmp wants the current time */
-        init_timestamp(&store_wtmp, 0);
-
-        return write_utmp_wtmp(&store, &store_wtmp);
-}
-
-
-int utmp_put_runlevel(int runlevel, int previous) {
-        struct utmpx store;
-        int r;
-
-        assert(runlevel > 0);
-
-        if (previous <= 0) {
-                /* Find the old runlevel automatically */
-
-                if ((r = utmp_get_runlevel(&previous, NULL)) < 0) {
-                        if (r != -ESRCH)
-                                return r;
-
-                        previous = 0;
-                }
-        }
-
-        if (previous == runlevel)
-                return 0;
-
-        init_entry(&store, 0);
-
-        store.ut_type = RUN_LVL;
-        store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
-        strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
-
-#define TIMEOUT_MSEC 50
-
-static int write_to_terminal(const char *tty, const char *message) {
-        int fd, r;
-        const char *p;
-        size_t left;
-        usec_t end;
-
-        assert(tty);
-        assert(message);
-
-        if ((fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC)) < 0)
-                return -errno;
-
-        if (!isatty(fd)) {
-                r = -errno;
-                goto finish;
-        }
-
-        p = message;
-        left = strlen(message);
-
-        end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC;
-
-        while (left > 0) {
-                ssize_t n;
-                struct pollfd pollfd;
-                usec_t t;
-                int k;
-
-                t = now(CLOCK_MONOTONIC);
-
-                if (t >= end) {
-                        r = -ETIME;
-                        goto finish;
-                }
-
-                zero(pollfd);
-                pollfd.fd = fd;
-                pollfd.events = POLLOUT;
-
-                if ((k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC)) < 0)
-                        return -errno;
-
-                if (k <= 0) {
-                        r = -ETIME;
-                        goto finish;
-                }
-
-                if ((n = write(fd, p, left)) < 0) {
-
-                        if (errno == EAGAIN)
-                                continue;
-
-                        r = -errno;
-                        goto finish;
-                }
-
-                assert((size_t) n <= left);
-
-                p += n;
-                left -= n;
-        }
-
-        r = 0;
-
-finish:
-        close_nointr_nofail(fd);
-
-        return r;
-}
-
-int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
-        struct utmpx *u;
-        char date[FORMAT_TIMESTAMP_MAX];
-        char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
-        int r;
-
-        if (!(hn = gethostname_malloc()) ||
-            !(un = getlogname_malloc())) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        getttyname_harder(STDIN_FILENO, &tty);
-
-        if (asprintf(&text,
-                     "\a\r\n"
-                     "Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
-                     "%s\r\n\r\n",
-                     un, hn,
-                     tty ? " on " : "", strempty(tty),
-                     format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
-                     message) < 0) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        setutxent();
-
-        r = 0;
-
-        while ((u = getutxent())) {
-                int q;
-                const char *path;
-                char *buf = NULL;
-
-                if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
-                        continue;
-
-                if (path_startswith(u->ut_line, "/dev/"))
-                        path = u->ut_line;
-                else {
-                        if (asprintf(&buf, "/dev/%s", u->ut_line) < 0) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        path = buf;
-                }
-
-                if (!match_tty || match_tty(path))
-                        if ((q = write_to_terminal(path, text)) < 0)
-                                r = q;
-
-                free(buf);
-        }
-
-finish:
-        free(hn);
-        free(un);
-        free(tty);
-        free(text);
-
-        return r;
-}
diff --git a/src/utmp-wtmp.h b/src/utmp-wtmp.h
deleted file mode 100644
index ab95061..0000000
--- a/src/utmp-wtmp.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooutmpwtmphfoo
-#define fooutmpwtmphfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-
-int utmp_get_runlevel(int *runlevel, int *previous);
-
-int utmp_put_shutdown(void);
-int utmp_put_reboot(usec_t timestamp);
-int utmp_put_runlevel(int runlevel, int previous);
-
-int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
-int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line);
-
-int utmp_wall(const char *message, bool (*match_tty)(const char *tty));
-
-#endif
diff --git a/src/watchdog.c b/src/watchdog.c
deleted file mode 100644
index 13265e7..0000000
--- a/src/watchdog.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/watchdog.h>
-
-#include "watchdog.h"
-#include "log.h"
-
-static int watchdog_fd = -1;
-static usec_t watchdog_timeout = (usec_t) -1;
-
-static int update_timeout(void) {
-        int r;
-
-        if (watchdog_fd < 0)
-                return 0;
-
-        if (watchdog_timeout == (usec_t) -1)
-                return 0;
-        else if (watchdog_timeout == 0) {
-                int flags;
-
-                flags = WDIOS_DISABLECARD;
-                r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
-                if (r < 0) {
-                        log_warning("Failed to disable hardware watchdog: %m");
-                        return -errno;
-                }
-        } else {
-                int sec, flags;
-                char buf[FORMAT_TIMESPAN_MAX];
-
-                sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
-                r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
-                if (r < 0) {
-                        log_warning("Failed to set timeout to %is: %m", sec);
-                        return -errno;
-                }
-
-                watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
-                log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout));
-
-                flags = WDIOS_ENABLECARD;
-                r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
-                if (r < 0) {
-                        log_warning("Failed to enable hardware watchdog: %m");
-                        return -errno;
-                }
-
-                r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
-                if (r < 0) {
-                        log_warning("Failed to ping hardware watchdog: %m");
-                        return -errno;
-                }
-        }
-
-        return 0;
-}
-
-static int open_watchdog(void) {
-        struct watchdog_info ident;
-
-        if (watchdog_fd >= 0)
-                return 0;
-
-        watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
-        if (watchdog_fd < 0)
-                return -errno;
-
-        if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0)
-                log_info("Hardware watchdog '%s', version %x",
-                         ident.identity,
-                         ident.firmware_version);
-
-        return update_timeout();
-}
-
-int watchdog_set_timeout(usec_t *usec) {
-        int r;
-
-        watchdog_timeout = *usec;
-
-        /* If we didn't open the watchdog yet and didn't get any
-         * explicit timeout value set, don't do anything */
-        if (watchdog_fd < 0 && watchdog_timeout == (usec_t) -1)
-                return 0;
-
-        if (watchdog_fd < 0)
-                r = open_watchdog();
-        else
-                r = update_timeout();
-
-        *usec = watchdog_timeout;
-
-        return r;
-}
-
-int watchdog_ping(void) {
-        int r;
-
-        if (watchdog_fd < 0) {
-                r = open_watchdog();
-                if (r < 0)
-                        return r;
-        }
-
-        r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
-        if (r < 0) {
-                log_warning("Failed to ping hardware watchdog: %m");
-                return -errno;
-        }
-
-        return 0;
-}
-
-void watchdog_close(bool disarm) {
-        int r;
-
-        if (watchdog_fd < 0)
-                return;
-
-        if (disarm) {
-                int flags;
-
-                /* Explicitly disarm it */
-                flags = WDIOS_DISABLECARD;
-                r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
-                if (r < 0)
-                        log_warning("Failed to disable hardware watchdog: %m");
-
-                /* To be sure, use magic close logic, too */
-                for (;;) {
-                        static const char v = 'V';
-
-                        if (write(watchdog_fd, &v, 1) > 0)
-                                break;
-
-                        if (errno != EINTR) {
-                                log_error("Failed to disarm watchdog timer: %m");
-                                break;
-                        }
-                }
-        }
-
-        close_nointr_nofail(watchdog_fd);
-        watchdog_fd = -1;
-}
diff --git a/src/watchdog.h b/src/watchdog.h
deleted file mode 100644
index 2e00cb9..0000000
--- a/src/watchdog.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foowatchdoghfoo
-#define foowatchdoghfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-
-int watchdog_set_timeout(usec_t *usec);
-int watchdog_ping(void);
-void watchdog_close(bool disarm);
-
-#endif



More information about the systemd-commits mailing list