[systemd-commits] 4 commits - configure.ac fixme .gitignore Makefile.am man/systemd.unit.xml src/dbus.c src/dbus-manager.c src/dbus-unit.c src/dbus-unit.h src/load-fragment.c src/manager.c src/manager.h src/missing.h src/system.conf src/unit.c src/unit.h src/update-utmp.c src/util.c src/utmp-wtmp.c units/basic.target units/fedora units/gentoo units/shutdown.target units/sysinit.target.m4 units/umount.target

Lennart Poettering lennart at kemper.freedesktop.org
Tue Aug 10 16:44:45 PDT 2010


 .gitignore                   |    1 
 Makefile.am                  |   33 +++
 configure.ac                 |   36 +++
 fixme                        |   12 +
 man/systemd.unit.xml         |   24 +-
 src/dbus-manager.c           |    7 
 src/dbus-unit.c              |   30 ++-
 src/dbus-unit.h              |    9 
 src/dbus.c                   |    2 
 src/load-fragment.c          |    3 
 src/manager.c                |   82 ++------
 src/manager.h                |   12 -
 src/missing.h                |    8 
 src/system.conf              |    1 
 src/unit.c                   |   32 +--
 src/unit.h                   |    9 
 src/update-utmp.c            |  410 +++++++++++++++++++++++++++++++++++++++++++
 src/util.c                   |   53 ++---
 src/utmp-wtmp.c              |    6 
 units/basic.target           |    2 
 units/fedora/killall.service |    2 
 units/gentoo/killall.service |    2 
 units/shutdown.target        |    2 
 units/sysinit.target.m4      |    2 
 units/umount.target          |    2 
 25 files changed, 644 insertions(+), 138 deletions(-)

New commits:
commit 4927fcae48de061393b3ce9c12d49f80d73fbf1d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 11 01:43:23 2010 +0200

    audit,utmp: implement audit logic and rip utmp stuff out of the main daemon and into a helper binary

diff --git a/.gitignore b/.gitignore
index 6ff8519..b143ad1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-update-utmp
 test-env-replace
 systemd-cgls
 systemd.pc
diff --git a/Makefile.am b/Makefile.am
index b6041b5..cb23184 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -68,7 +68,8 @@ endif
 rootlibexec_PROGRAMS = \
 	systemd-logger \
 	systemd-cgroups-agent \
-	systemd-initctl
+	systemd-initctl \
+	systemd-update-utmp
 
 noinst_PROGRAMS = \
 	test-engine \
@@ -243,6 +244,13 @@ libsystemd_basic_la_SOURCES = \
         src/log.c \
         src/ratelimit.c
 
+libsystemd_basic_la_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(SELINUX_CFLAGS)
+
+libsystemd_basic_la_LIBADD = \
+	$(SELINUX_LIBS)
+
 libsystemd_core_la_SOURCES = \
 	src/unit.c \
         src/job.c \
@@ -282,7 +290,6 @@ libsystemd_core_la_SOURCES = \
 	src/loopback-setup.c \
 	src/kmod-setup.c \
 	src/modprobe-setup.c \
-	src/utmp-wtmp.c \
 	src/specifier.c \
 	src/unit-name.c \
 	src/fdset.c \
@@ -293,7 +300,10 @@ libsystemd_core_la_SOURCES = \
 libsystemd_core_la_CFLAGS = \
 	$(AM_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	$(UDEV_CFLAGS)
+	$(UDEV_CFLAGS) \
+	$(LIBWRAP_CFLAGS) \
+	$(PAM_CFLAGS) \
+	$(AUDIT_CFLAGS)
 
 libsystemd_core_la_LIBADD = \
 	libsystemd-basic.la \
@@ -301,7 +311,7 @@ libsystemd_core_la_LIBADD = \
 	$(UDEV_LIBS) \
 	$(LIBWRAP_LIBS) \
 	$(PAM_LIBS) \
-	$(SELINUX_LIBS)
+	$(AUDIT_LIBS)
 
 # This is needed because automake is buggy in how it generates the
 # rules for C programs, but not Vala programs.  We therefore can't
@@ -480,6 +490,21 @@ systemd_initctl_LDADD = \
 	libsystemd-basic.la \
 	$(DBUS_LIBS)
 
+systemd_update_utmp_SOURCES = \
+	src/update-utmp.c \
+	src/dbus-common.c \
+	src/utmp-wtmp.c
+
+systemd_update_utmp_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	$(AUDIT_CFLAGS)
+
+systemd_update_utmp_LDADD = \
+	libsystemd-basic.la \
+	$(DBUS_LIBS) \
+	$(AUDIT_LIBS)
+
 systemd_cgroups_agent_SOURCES = \
 	src/cgroups-agent.c \
 	src/dbus-common.c
diff --git a/configure.ac b/configure.ac
index f5dba3a..72218e4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -186,6 +186,42 @@ fi
 AC_SUBST(PAM_LIBS)
 AM_CONDITIONAL([HAVE_PAM], [test "x$have_pam" != xno])
 
+AC_ARG_ENABLE([audit],
+        AS_HELP_STRING([--disable-audit],[Disable optional AUDIT support]),
+                [case "${enableval}" in
+                        yes) have_audit=yes ;;
+                        no) have_audit=no ;;
+                        *) AC_MSG_ERROR(bad value ${enableval} for --disable-audit) ;;
+                esac],
+                [have_audit=auto])
+
+if test "x${have_audit}" != xno ; then
+        AC_CHECK_HEADERS(
+                [libaudit.h],
+                [have_audit=yes],
+                [if test "x$have_audit" = xyes ; then
+                        AC_MSG_ERROR([*** AUDIT headers not found.])
+                fi])
+
+        AC_CHECK_LIB(
+                [audit],
+                [audit_open],
+                [have_audit=yes],
+                [if test "x$have_audit" = xyes ; then
+                        AC_MSG_ERROR([*** libaudit not found.])
+                fi])
+
+        if test "x$have_audit" = xyes ; then
+                AUDIT_LIBS="-laudit"
+                AC_DEFINE(HAVE_AUDIT, 1, [AUDIT available])
+        else
+                have_audit=no
+        fi
+else
+        AUDIT_LIBS=
+fi
+AC_SUBST(AUDIT_LIBS)
+
 have_gtk=no
 AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools]))
 if test "x$enable_gtk" != "xno"; then
diff --git a/fixme b/fixme
index 3614c11..be771ab 100644
--- a/fixme
+++ b/fixme
@@ -79,9 +79,9 @@
 
 * don't show file not found msgs for irrelevant units
 
-* audit
+* j->installed issue
 
-* env vars must be replaced by ""
+* plymouth boot.log
 
 External:
 
diff --git a/src/manager.c b/src/manager.c
index ddb253a..25eb4e7 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -37,6 +37,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <dirent.h>
+#include <libaudit.h>
 
 #include "manager.h"
 #include "hashmap.h"
@@ -202,6 +203,10 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
         m->pin_cgroupfs_fd = -1;
 
+#ifdef HAVE_AUDIT
+        m->audit_fd = -1;
+#endif
+
         m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
         m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
 
@@ -245,6 +250,9 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         if ((r = bus_init(m)) < 0)
                 goto fail;
 
+        if ((m->audit_fd = audit_open()) < 0)
+                log_error("Failed to connect to audit log: %m");
+
         *_m = m;
         return 0;
 
@@ -429,6 +437,11 @@ void manager_free(Manager *m) {
         if (m->notify_watch.fd >= 0)
                 close_nointr_nofail(m->notify_watch.fd);
 
+#ifdef HAVE_AUDIT
+        if (m->audit_fd >= 0)
+                audit_close(m->audit_fd);
+#endif
+
         free(m->notify_socket);
 
         lookup_paths_free(&m->lookup_paths);
@@ -567,10 +580,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
                 m->n_deserializing --;
         }
 
-        /* Now that the initial devices are available, let's see if we
-         * can write the utmp file */
-        manager_write_utmp_reboot(m);
-
         return r;
 }
 
@@ -2234,70 +2243,25 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
         return 0;
 }
 
-static bool manager_utmp_good(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if ((r = mount_path_is_mounted(m, _PATH_UTMPX)) <= 0) {
-
-                if (r < 0)
-                        log_warning("Failed to determine whether " _PATH_UTMPX " is mounted: %s", strerror(-r));
-
-                return false;
-        }
-
-        return true;
-}
-
-void manager_write_utmp_reboot(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if (m->utmp_reboot_written)
-                return;
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
 
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
+#ifdef HAVE_AUDIT
+        char *p;
 
-        if (!manager_utmp_good(m))
+        if (m->audit_fd < 0)
                 return;
 
-        if ((r = utmp_put_reboot(m->startup_timestamp.realtime)) < 0) {
-
-                if (r != -ENOENT && r != -EROFS)
-                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-
+        if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) {
+                log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
                 return;
         }
 
-        m->utmp_reboot_written = true;
-}
-
-void manager_write_utmp_runlevel(Manager *m, Unit *u) {
-        int runlevel, r;
-
-        assert(m);
-        assert(u);
-
-        if (u->meta.type != UNIT_TARGET)
-                return;
+        if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0)
+                log_error("Failed to send audit message: %m");
 
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
-        if (!manager_utmp_good(m))
-                return;
+        free(p);
+#endif
 
-        if ((runlevel = target_get_runlevel(TARGET(u))) <= 0)
-                return;
-
-        if ((r = utmp_put_runlevel(0, runlevel, 0)) < 0) {
-
-                if (r != -ENOENT && r != -EROFS)
-                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-        }
 }
 
 void manager_dispatch_bus_name_owner_changed(
diff --git a/src/manager.h b/src/manager.h
index a762dbc..c1f787f 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -185,6 +185,11 @@ struct Manager {
          * file system */
         int pin_cgroupfs_fd;
 
+        /* Audit fd */
+#ifdef HAVE_AUDIT
+        int audit_fd;
+#endif
+
         /* Flags */
         ManagerRunningAs running_as;
         ManagerExitCode exit_code:4;
@@ -193,8 +198,6 @@ struct Manager {
         bool dispatching_run_queue:1;
         bool dispatching_dbus_queue:1;
 
-        bool utmp_reboot_written:1;
-
         int n_deserializing;
 
         bool show_status;
@@ -234,9 +237,6 @@ unsigned manager_dispatch_dbus_queue(Manager *m);
 
 int manager_loop(Manager *m);
 
-void manager_write_utmp_reboot(Manager *m);
-void manager_write_utmp_runlevel(Manager *m, Unit *t);
-
 void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
 void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid);
 
@@ -251,6 +251,8 @@ bool manager_is_booting_or_shutting_down(Manager *m);
 
 void manager_reset_maintenance(Manager *m);
 
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
+
 const char *manager_running_as_to_string(ManagerRunningAs i);
 ManagerRunningAs manager_running_as_from_string(const char *s);
 
diff --git a/src/missing.h b/src/missing.h
index 5914b01..d6114cc 100644
--- a/src/missing.h
+++ b/src/missing.h
@@ -63,4 +63,12 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
 
 /* static void nss_disable_nscd(void) _weakref_(__nss_disable_nscd); */
 
+#ifndef AUDIT_SERVICE_START
+#define AUDIT_SERVICE_START     1130    /* Service (daemon) start */
+#endif
+
+#ifndef AUDIT_SERVICE_STOP
+#define AUDIT_SERVICE_STOP      1131    /* Service (daemon) stop */
+#endif
+
 #endif
diff --git a/src/unit.c b/src/unit.c
index 9ccf7a4..3c4bdec 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -41,6 +41,7 @@
 #include "dbus-unit.h"
 #include "special.h"
 #include "cgroup-util.h"
+#include "missing.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
@@ -1094,12 +1095,11 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
 
         /* Some names are special */
         if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
-                if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) {
+                if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
                         /* The bus just might have become available,
                          * hence try to connect to it, if we aren't
                          * yet connected. */
                         bus_init(u->meta.manager);
-                }
 
                 if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
                         /* The syslog daemon just might have become
@@ -1107,17 +1107,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
                          * we aren't yet connected. */
                         log_open();
 
-                if (u->meta.type == UNIT_MOUNT)
-                        /* Another directory became available, let's
-                         * check if that is enough to write our utmp
-                         * entry. */
-                        manager_write_utmp_reboot(u->meta.manager);
-
-                if (u->meta.type == UNIT_TARGET)
-                        /* A target got activated, maybe this is a runlevel? */
-                        manager_write_utmp_runlevel(u->meta.manager, u);
+                if (u->meta.type == UNIT_SERVICE &&
+                    !UNIT_IS_ACTIVE_OR_RELOADING(os))
+                        /* Write audit record if we have just finished starting up */
+                        manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_START, 1);
 
-        } else if (!UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
+        } else {
 
                 if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
                         /* The syslog daemon might just have
@@ -1127,6 +1122,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
 
                 /* We don't care about D-Bus here, since we'll get an
                  * asynchronous notification for it anyway. */
+
+                if (u->meta.type == UNIT_SERVICE &&
+                    UNIT_IS_INACTIVE_OR_MAINTENANCE(ns) &&
+                    !UNIT_IS_INACTIVE_OR_MAINTENANCE(os))
+
+                        /* Write audit record if we have just finished shutting down */
+                        manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
         }
 
         /* Maybe we finished startup and are now ready for being
diff --git a/src/update-utmp.c b/src/update-utmp.c
new file mode 100644
index 0000000..e64a819
--- /dev/null
+++ b/src/update-utmp.c
@@ -0,0 +1,410 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libaudit.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "special.h"
+#include "utmp-wtmp.h"
+#include "dbus-common.h"
+
+typedef struct Context {
+        DBusConnection *bus;
+#ifdef HAVE_AUDIT
+        int audit_fd;
+#endif
+} Context;
+
+static usec_t get_startup_time(Context *c) {
+        const char
+                *interface = "org.freedesktop.systemd1.Manager",
+                *property = "StartupTimestamp";
+
+        DBusError error;
+        usec_t t = 0;
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusMessageIter iter, sub;
+
+        dbus_error_init(&error);
+
+        assert(c);
+
+        if (!(m = dbus_message_new_method_call(
+                              "org.freedesktop.systemd1",
+                              "/org/freedesktop/systemd1",
+                              "org.freedesktop.DBus.Properties",
+                              "Get"))) {
+                log_error("Could not allocate message.");
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &interface,
+                                      DBUS_TYPE_STRING, &property,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                goto finish;
+        }
+
+        if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) {
+                log_error("Failed to send command: %s", error.message);
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
+                log_error("Failed to parse reply.");
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT64)  {
+                log_error("Failed to parse reply.");
+                goto finish;
+        }
+
+        dbus_message_iter_get_basic(&sub, &t);
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return t;
+}
+
+static int get_current_runlevel(Context *c) {
+        static const struct {
+                const int runlevel;
+                const char *special;
+        } table[] = {
+                /* The first target of this list that is active or has
+                 * a job scheduled wins */
+                { '0', SPECIAL_POWEROFF_TARGET },
+                { '6', SPECIAL_REBOOT_TARGET },
+                { '5', SPECIAL_RUNLEVEL5_TARGET },
+                { '4', SPECIAL_RUNLEVEL4_TARGET },
+                { '3', SPECIAL_RUNLEVEL3_TARGET },
+                { '2', SPECIAL_RUNLEVEL2_TARGET },
+                { '1', SPECIAL_RESCUE_TARGET },
+        };
+        const char
+                *interface = "org.freedesktop.systemd1.Unit",
+                *property = "ActiveState";
+
+        DBusMessage *m = NULL, *reply = NULL;
+        int r = 0;
+        unsigned i;
+        DBusError error;
+
+        assert(c);
+
+        dbus_error_init(&error);
+
+        for (i = 0; i < ELEMENTSOF(table); i++) {
+                const char *path = NULL, *state;
+                DBusMessageIter iter, sub;
+
+                if (!(m = dbus_message_new_method_call(
+                                      "org.freedesktop.systemd1",
+                                      "/org/freedesktop/systemd1",
+                                      "org.freedesktop.systemd1.Manager",
+                                      "GetUnit"))) {
+                        log_error("Could not allocate message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &table[i].special,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) {
+                        dbus_error_free(&error);
+                        continue;
+                }
+
+                if (!dbus_message_get_args(reply, &error,
+                                           DBUS_TYPE_OBJECT_PATH, &path,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse reply: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                if (!(m = dbus_message_new_method_call(
+                                      "org.freedesktop.systemd1",
+                                      path,
+                                      "org.freedesktop.DBus.Properties",
+                                      "Get"))) {
+                        log_error("Could not allocate message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &interface,
+                                              DBUS_TYPE_STRING, &property,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                dbus_message_unref(reply);
+                if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) {
+                        log_error("Failed to send command: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (!dbus_message_iter_init(reply, &iter) ||
+                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&iter, &sub);
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_get_basic(&sub, &state);
+
+                if (streq(state, "active") || streq(state, "reloading"))
+                        r = table[i].runlevel;
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+
+                if (r)
+                        break;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int on_reboot(Context *c) {
+        int r = 0, q;
+        usec_t t;
+
+        assert(c);
+
+        /* We finished start-up, so let's write the utmp
+         * record and send the audit msg */
+
+#ifdef HAVE_AUDIT
+        if (c->audit_fd >= 0)
+                if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", NULL, NULL, NULL, 1) < 0) {
+                        log_error("Failed to send audit message: %m");
+                        r = -errno;
+                }
+#endif
+
+        /* If this call fails it will return 0, which
+         * utmp_put_reboot() will then fix to the current time */
+        t = get_startup_time(c);
+
+        if ((q = utmp_put_reboot(t)) < 0) {
+                log_error("Failed to write utmp record: %s", strerror(-q));
+                r = q;
+        }
+
+        return r;
+}
+
+static int on_shutdown(Context *c) {
+        int r = 0, q;
+
+        assert(c);
+
+        /* We started shut-down, so let's write the utmp
+         * record and send the audit msg */
+
+#ifdef HAVE_AUDIT
+        if (c->audit_fd >= 0)
+                if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", NULL, NULL, NULL, 1) < 0) {
+                        log_error("Failed to send audit message: %m");
+                        r = -errno;
+                }
+#endif
+
+        if ((q = utmp_put_shutdown(0)) < 0) {
+                log_error("Failed to write utmp record: %s", strerror(-q));
+                r = q;
+        }
+
+        return r;
+}
+
+static int on_runlevel(Context *c) {
+        int r = 0, q, previous, runlevel;
+
+        assert(c);
+
+        /* We finished changing runlevel, so let's write the
+         * utmp record and send the audit msg */
+
+        /* First, get last runlevel */
+        if ((q = utmp_get_runlevel(&previous, NULL)) < 0) {
+
+                if (q != -ESRCH && q != -ENOENT) {
+                        log_error("Failed to get current runlevel: %s", strerror(-q));
+                        return q;
+                }
+
+                /* Hmm, we didn't find any runlevel, that means we
+                 * have been rebooted */
+                r = on_reboot(c);
+                previous = 0;
+        }
+
+        /* Second get new runlevel */
+        if ((runlevel = get_current_runlevel(c)) < 0)
+                return runlevel;
+
+        if (previous == runlevel)
+                return 0;
+
+#ifdef HAVE_AUDIT
+        if (c->audit_fd >= 0) {
+                char *s = NULL;
+
+                if (asprintf(&s, "old-level=%c new-level=%c", previous, runlevel) < 0)
+                        return -ENOMEM;
+
+                if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0) {
+                        log_error("Failed to send audit message: %m");
+                        r = -errno;
+                }
+
+                free(s);
+        }
+#endif
+
+        if ((q = utmp_put_runlevel(0, runlevel, previous)) < 0) {
+                log_error("Failed to write utmp record: %s", strerror(-q));
+                r = q;
+        }
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+        DBusError error;
+        Context c;
+
+        dbus_error_init(&error);
+
+        zero(c);
+#ifdef HAVE_AUDIT
+        c.audit_fd = -1;
+#endif
+
+        /* if (getppid() != 1) { */
+        /*         log_error("This program should be invoked by init only."); */
+        /*         return 1; */
+        /* } */
+
+        if (argc != 2) {
+                log_error("This program requires one argument.");
+                return 1;
+        }
+
+        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        log_parse_environment();
+
+#ifdef HAVE_AUDIT
+        if ((c.audit_fd = audit_open()) < 0)
+                log_error("Failed to connect to audit log: %m");
+#endif
+
+        if (bus_connect(DBUS_BUS_SYSTEM, &c.bus, NULL, &error) < 0) {
+                log_error("Failed to get D-Bus connection: %s", error.message);
+                r = -EIO;
+                goto finish;
+        }
+
+        log_info("systemd-update-utmp running as pid %lu", (unsigned long) getpid());
+
+        if (streq(argv[1], "reboot"))
+                r = on_reboot(&c);
+        else if (streq(argv[1], "shutdown"))
+                r = on_shutdown(&c);
+        else if (streq(argv[1], "runlevel"))
+                r = on_runlevel(&c);
+        else {
+                log_error("Unknown command %s", argv[1]);
+                r = -EINVAL;
+        }
+
+        log_info("systemd-update-utmp stopped as pid %lu", (unsigned long) getpid());
+finish:
+
+#ifdef HAVE_AUDIT
+        if (c.audit_fd >= 0)
+                audit_close(c.audit_fd);
+#endif
+
+        if (c.bus) {
+               dbus_connection_close(c.bus);
+               dbus_connection_unref(c.bus);
+        }
+
+        dbus_error_free(&error);
+        dbus_shutdown();
+
+        return r < 0 ? 1 : 0;
+}
diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c
index 45da79c..46dfba3 100644
--- a/src/utmp-wtmp.c
+++ b/src/utmp-wtmp.c
@@ -202,11 +202,11 @@ int utmp_put_runlevel(usec_t t, int runlevel, int previous) {
 
                         previous = 0;
                 }
-
-                if (previous == runlevel)
-                        return 0;
         }
 
+        if (previous == runlevel)
+                return 0;
+
         init_entry(&store, t);
 
         store.ut_type = RUN_LVL;
commit b95cf3629e8d78a0d28e71b0f5559fa9a8c038b5
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Aug 10 21:05:19 2010 +0200

    util: when replacing env vars replace unset envvars by nothing
    
    This makes it easier to support /etc/sysconfig/xxxx with command line
    env vars in style of $OPTIONS which might or might not be set.

diff --git a/fixme b/fixme
index 397f5c3..3614c11 100644
--- a/fixme
+++ b/fixme
@@ -79,8 +79,6 @@
 
 * don't show file not found msgs for irrelevant units
 
-* hide plymouth in multi-user mode
-
 * audit
 
 * env vars must be replaced by ""
diff --git a/src/util.c b/src/util.c
index 7281b70..a2def28 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3085,18 +3085,18 @@ char *replace_env(const char *format, char **env) {
 
                 case VARIABLE:
                         if (*e == '}') {
-                                char *t;
+                                const char *t;
 
-                                if ((t = strv_env_get_with_length(env, word+2, e-word-2))) {
-                                        if (!(k = strappend(r, t)))
-                                                goto fail;
+                                if (!(t = strv_env_get_with_length(env, word+2, e-word-2)))
+                                        t = "";
 
-                                        free(r);
-                                        r = k;
+                                if (!(k = strappend(r, t)))
+                                        goto fail;
 
-                                        word = e+1;
-                                }
+                                free(r);
+                                r = k;
 
+                                word = e+1;
                                 state = WORD;
                         }
                         break;
@@ -3126,36 +3126,39 @@ char **replace_env_argv(char **argv, char **env) {
         STRV_FOREACH(i, argv) {
 
                 /* If $FOO appears as single word, replace it by the split up variable */
-                if ((*i)[0] == '$') {
-                        char *e = strv_env_get(env, *i+1);
+                if ((*i)[0] == '$' && (*i)[1] != '{') {
+                        char *e;
+                        char **w, **m;
+                        unsigned q;
 
-                        if (e) {
-                                char **w, **m;
-                                unsigned q;
+                        if ((e = strv_env_get(env, *i+1))) {
 
                                 if (!(m = strv_split_quoted(e))) {
                                         r[k] = NULL;
                                         strv_free(r);
                                         return NULL;
                                 }
+                        } else
+                                m = NULL;
 
-                                q = strv_length(m);
-                                l = l + q - 1;
+                        q = strv_length(m);
+                        l = l + q - 1;
 
-                                if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
-                                        r[k] = NULL;
-                                        strv_free(r);
-                                        strv_free(m);
-                                        return NULL;
-                                }
+                        if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
+                                r[k] = NULL;
+                                strv_free(r);
+                                strv_free(m);
+                                return NULL;
+                        }
 
-                                r = w;
+                        r = w;
+                        if (m) {
                                 memcpy(r + k, m, q * sizeof(char*));
                                 free(m);
-
-                                k += q;
-                                continue;
                         }
+
+                        k += q;
+                        continue;
                 }
 
                 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
commit 3454f9e519260c1b9908dda23870a6c6cdd79f22
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Aug 10 20:59:01 2010 +0200

    conf: add commented default SysVConsole= value

diff --git a/src/system.conf b/src/system.conf
index 20218d1..11885e0 100644
--- a/src/system.conf
+++ b/src/system.conf
@@ -15,5 +15,6 @@
 #DumpCore=yes
 #CrashShell=no
 #ShowStatus=yes
+#SysVConsole=yes
 #CrashChVT=1
 #CPUAffinity=1 2
commit b5e9dba8d60b8fb80b6302b6ea2cd665b3ab370c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Aug 10 20:57:21 2010 +0200

    unit: rename OnlyByDependency= to RefuseManualStart= and introduce RefuseManualStop=
    
    Some unit shall never be start on user request (e.g. shutdown.target)
    others never be stopped on user request (e.g. auditd.servce), hence
    offer options for both.

diff --git a/fixme b/fixme
index 45dfb62..397f5c3 100644
--- a/fixme
+++ b/fixme
@@ -81,6 +81,10 @@
 
 * hide plymouth in multi-user mode
 
+* audit
+
+* env vars must be replaced by ""
+
 External:
 
 * sysv functions should color when stdout is tty, not stdin
@@ -105,6 +109,14 @@ https://bugs.freedesktop.org/show_bug.cgi?id=29194 -- ConsoleKit
 https://bugs.freedesktop.org/show_bug.cgi?id=29205 -- udisks
 http://article.gmane.org/gmane.linux.bluez.kernel/6479 -- bluez
 http://www.spinics.net/lists/linux-nfs/msg14371.html -- rpcbind
+https://bugzilla.redhat.com/show_bug.cgi?id=617328 -- ntp
+https://bugzilla.redhat.com/show_bug.cgi?id=617320 -- at
+https://bugzilla.redhat.com/show_bug.cgi?id=617326 -- fprintd
+https://bugzilla.redhat.com/show_bug.cgi?id=617333 -- yum
+https://bugzilla.redhat.com/show_bug.cgi?id=617317 -- acpid
+https://bugzilla.redhat.com/show_bug.cgi?id=617327 -- gpm
+https://bugzilla.redhat.com/show_bug.cgi?id=617330 -- pcsc-lite
+https://bugzilla.redhat.com/show_bug.cgi?id=617321 -- audit
 
 Regularly:
 
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index e5d5968..bb11682 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -461,20 +461,26 @@
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>OnlyByDependency=</varname></term>
+                                <term><varname>RefuseManualStart=</varname></term>
+                                <term><varname>RefuseManualStop=</varname></term>
 
                                 <listitem><para>Takes a boolean
                                 argument. If <option>true</option>
                                 this unit can only be activated
-                                indirectly. In this case explicit
-                                start-up requested by the user is
-                                denied, however if it is started as a
+                                (resp. deactivated) indirectly. In
+                                this case explicit start-up
+                                (resp. termination) requested by the
+                                user is denied, however if it is
+                                started (resp. stopped) as a
                                 dependency of another unit, start-up
-                                will succeed. This is mostly a safety
-                                feature to ensure that the user does
-                                not accidentally activate units that are
-                                not intended to be activated
-                                explicitly. This option defaults to
+                                (resp. termination) will succeed. This
+                                is mostly a safety feature to ensure
+                                that the user does not accidentally
+                                activate units that are not intended
+                                to be activated explicitly, and not
+                                accidentally deactivate units that are
+                                not intended to be deactivated.
+                                These options default to
                                 <option>false</option>.</para></listitem>
                         </varlistentry>
 
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 549f175..6d0ecc3 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -801,8 +801,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                                 job_type = JOB_RELOAD;
                 }
 
-                if (job_type == JOB_START && u->meta.only_by_dependency) {
-                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Unit may be activated by dependency only.");
+                if ((job_type == JOB_START && u->meta.refuse_manual_start) ||
+                    (job_type == JOB_STOP && u->meta.refuse_manual_stop) ||
+                    ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
+                     (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) {
+                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
                         return bus_send_error_reply(m, connection, message, &error, -EPERM);
                 }
 
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index c9ccac1..2d59242 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -147,7 +147,28 @@ int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *proper
         assert(u);
 
         b = unit_can_start(u) &&
-                !u->meta.only_by_dependency;
+                !u->meta.refuse_manual_start;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(u);
+
+        /* On the lower levels we assume that every unit we can start
+         * we can also stop */
+
+        b = unit_can_start(u) &&
+                !u->meta.refuse_manual_stop;
 
         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
                 return -ENOMEM;
@@ -334,8 +355,11 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
                 Job *j;
                 int r;
 
-                if (job_type == JOB_START && u->meta.only_by_dependency) {
-                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Unit may be activated by dependency only.");
+                if ((job_type == JOB_START && u->meta.refuse_manual_start) ||
+                    (job_type == JOB_STOP && u->meta.refuse_manual_stop) ||
+                    ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
+                     (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) {
+                        dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
                         return bus_send_error_reply(m, connection, message, &error, -EPERM);
                 }
 
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
index 0744377..05892b8 100644
--- a/src/dbus-unit.h
+++ b/src/dbus-unit.h
@@ -85,10 +85,12 @@
         "  <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n"   \
         "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n"    \
         "  <property name=\"RecursiveStop\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"StopWhenUneeded\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"OnlyByDependency\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>\n" \
@@ -123,11 +125,13 @@
         { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp",  bus_property_append_uint64,     "t",    &u->meta.active_exit_timestamp.realtime    }, \
         { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_uint64,    "t",    &u->meta.inactive_enter_timestamp.realtime }, \
         { "org.freedesktop.systemd1.Unit", "CanStart",             bus_unit_append_can_start,      "b",    u                                 }, \
+        { "org.freedesktop.systemd1.Unit", "CanStop",              bus_unit_append_can_stop,       "b",    u                                 }, \
         { "org.freedesktop.systemd1.Unit", "CanReload",            bus_unit_append_can_reload,     "b",    u                                 }, \
         { "org.freedesktop.systemd1.Unit", "Job",                  bus_unit_append_job,            "(uo)", u                                 }, \
         { "org.freedesktop.systemd1.Unit", "RecursiveStop",        bus_property_append_bool,       "b",    &u->meta.recursive_stop           }, \
         { "org.freedesktop.systemd1.Unit", "StopWhenUneeded",      bus_property_append_bool,       "b",    &u->meta.stop_when_unneeded       }, \
-        { "org.freedesktop.systemd1.Unit", "OnlyByDependency",     bus_property_append_bool,       "b",    &u->meta.only_by_dependency       }, \
+        { "org.freedesktop.systemd1.Unit", "RefuseManualStart",    bus_property_append_bool,       "b",    &u->meta.refuse_manual_start      }, \
+        { "org.freedesktop.systemd1.Unit", "RefuseManualStop",     bus_property_append_bool,       "b",    &u->meta.refuse_manual_stop       }, \
         { "org.freedesktop.systemd1.Unit", "DefaultDependencies",  bus_property_append_bool,       "b",    &u->meta.default_dependencies     }, \
         { "org.freedesktop.systemd1.Unit", "DefaultControlGroup",  bus_unit_append_default_cgroup, "s",    u                                 }, \
         { "org.freedesktop.systemd1.Unit", "ControlGroups",        bus_unit_append_cgroups,        "as",   u                                 }, \
@@ -142,6 +146,7 @@ int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *prope
 int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data);
diff --git a/src/dbus.c b/src/dbus.c
index 0ab55b8..cb580e1 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -385,7 +385,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
 
                         r = manager_load_unit(m, name, NULL, &error, &u);
 
-                        if (r >= 0 && u->meta.only_by_dependency)
+                        if (r >= 0 && u->meta.refuse_manual_start)
                                 r = -EPERM;
 
                         if (r >= 0)
diff --git a/src/load-fragment.c b/src/load-fragment.c
index f2f2d72..1a87a96 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1566,7 +1566,8 @@ static int load_from_path(Unit *u, const char *path) {
                 { "OnFailure",              config_parse_deps,            UINT_TO_PTR(UNIT_ON_FAILURE),                    "Unit"    },
                 { "RecursiveStop",          config_parse_bool,            &u->meta.recursive_stop,                         "Unit"    },
                 { "StopWhenUnneeded",       config_parse_bool,            &u->meta.stop_when_unneeded,                     "Unit"    },
-                { "OnlyByDependency",       config_parse_bool,            &u->meta.only_by_dependency,                     "Unit"    },
+                { "RefuseManualStart",      config_parse_bool,            &u->meta.refuse_manual_start,                    "Unit"    },
+                { "RefuseManualStop",       config_parse_bool,            &u->meta.refuse_manual_stop,                     "Unit"    },
                 { "DefaultDependencies",    config_parse_bool,            &u->meta.default_dependencies,                   "Unit"    },
                 { "IgnoreDependencyFailure",config_parse_bool,            &u->meta.ignore_dependency_failure,              "Unit"    },
                 { "JobTimeoutSec",          config_parse_usec,            &u->meta.job_timeout,                            "Unit"    },
diff --git a/src/unit.c b/src/unit.c
index d205ca4..9ccf7a4 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -646,12 +646,14 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                 fprintf(f,
                         "%s\tRecursive Stop: %s\n"
                         "%s\tStopWhenUnneeded: %s\n"
-                        "%s\tOnlyByDependency: %s\n"
+                        "%s\tRefuseManualStart: %s\n"
+                        "%s\tRefuseManualStop: %s\n"
                         "%s\tDefaultDependencies: %s\n"
                         "%s\tIgnoreDependencyFailure: %s\n",
                         prefix, yes_no(u->meta.recursive_stop),
                         prefix, yes_no(u->meta.stop_when_unneeded),
-                        prefix, yes_no(u->meta.only_by_dependency),
+                        prefix, yes_no(u->meta.refuse_manual_start),
+                        prefix, yes_no(u->meta.refuse_manual_stop),
                         prefix, yes_no(u->meta.default_dependencies),
                         prefix, yes_no(u->meta.ignore_dependency_failure));
 
diff --git a/src/unit.h b/src/unit.h
index f657aea..1c97e15 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -186,15 +186,18 @@ struct Meta {
         /* Garbage collect us we nobody wants or requires us anymore */
         bool stop_when_unneeded;
 
-        /* Refuse manual starting, allow starting only indirectly via dependency. */
-        bool only_by_dependency;
-
         /* Create default depedencies */
         bool default_dependencies;
 
         /* Bring up this unit even if a dependency fails to start */
         bool ignore_dependency_failure;
 
+        /* Refuse manual starting, allow starting only indirectly via dependency. */
+        bool refuse_manual_start;
+
+        /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */
+        bool refuse_manual_stop;
+
         /* When deserializing, temporarily store the job type for this
          * unit here, if there was a job scheduled */
         int deserialized_job; /* This is actually of type JobType */
diff --git a/units/basic.target b/units/basic.target
index aa94b94..ecd72ef 100644
--- a/units/basic.target
+++ b/units/basic.target
@@ -11,4 +11,4 @@
 Description=Basic System
 Requires=sysinit.target local-fs.target swap.target sockets.target
 After=sysinit.target local-fs.target swap.target sockets.target
-OnlyByDependency=yes
+RefuseManualStart=yes
diff --git a/units/fedora/killall.service b/units/fedora/killall.service
index 73a0569..3b27375 100644
--- a/units/fedora/killall.service
+++ b/units/fedora/killall.service
@@ -9,7 +9,7 @@
 Description=Kill All Processes
 DefaultDependencies=no
 After=shutdown.target
-OnlyByDependency=yes
+RefuseManualStart=yes
 
 [Service]
 Type=finish
diff --git a/units/gentoo/killall.service b/units/gentoo/killall.service
index 0d2f923..3f107e3 100644
--- a/units/gentoo/killall.service
+++ b/units/gentoo/killall.service
@@ -9,7 +9,7 @@
 Description=Kill All Processes
 DefaultDependencies=no
 After=shutdown.target
-OnlyByDependency=yes
+RefuseManualStart=yes
 
 [Service]
 Type=finish
diff --git a/units/shutdown.target b/units/shutdown.target
index 586ca4a..6d1fb6f 100644
--- a/units/shutdown.target
+++ b/units/shutdown.target
@@ -9,5 +9,5 @@
 
 [Unit]
 Description=Shutdown
-OnlyByDependency=yes
+RefuseManualStart=yes
 IgnoreDependencyFailure=yes
diff --git a/units/sysinit.target.m4 b/units/sysinit.target.m4
index 8ca37ff..029bb3c 100644
--- a/units/sysinit.target.m4
+++ b/units/sysinit.target.m4
@@ -11,7 +11,7 @@
 Description=System Initialization
 Conflicts=emergency.service emergency.target
 After=emergency.service emergency.target
-OnlyByDependency=yes
+RefuseManualStart=yes
 m4_dnl
 m4_ifdef(`TARGET_FEDORA',
 m4_dnl Hook in Fedora's /etc/rc.d/rc.sysinit
diff --git a/units/umount.target b/units/umount.target
index 6a00c31..c25696e 100644
--- a/units/umount.target
+++ b/units/umount.target
@@ -9,5 +9,5 @@
 
 [Unit]
 Description=Unmount All Filesystems
-OnlyByDependency=yes
+RefuseManualStart=yes
 IgnoreDependencyFailure=yes


More information about the systemd-commits mailing list