chiark / gitweb /
systemctl: fold systemd-install into systemctl
authorLennart Poettering <lennart@poettering.net>
Fri, 23 Jul 2010 22:53:33 +0000 (00:53 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 23 Jul 2010 22:53:33 +0000 (00:53 +0200)
Makefile.am
man/daemon.xml
man/systemctl.xml
man/systemd-install.xml [deleted file]
man/systemd.unit.xml
man/systemd.xml
src/install.c [deleted file]
src/systemctl.c

index 0c3262e02ee5bd491f72b952a8a6d5cd6a067690..bebfd2f7370a9ef35be9218c02a1da9a04605edd 100644 (file)
@@ -58,7 +58,6 @@ rootbin_PROGRAMS = \
        systemd-notify
 
 bin_PROGRAMS = \
-       systemd-install \
        systemd-cgls
 
 if HAVE_GTK
@@ -325,7 +324,6 @@ MANPAGES = \
        man/systemd.1 \
        man/systemctl.1 \
        man/systemadm.1 \
-       man/systemd-install.1 \
        man/systemd-cgls.1 \
        man/systemd-notify.1 \
        man/sd_notify.3 \
@@ -494,6 +492,8 @@ systemctl_SOURCES = \
        src/systemctl.c \
        src/utmp-wtmp.c \
        src/dbus-common.c \
+       src/path-lookup.c \
+       src/sd-daemon.c \
        src/cgroup-show.c \
        src/cgroup-util.c
 
@@ -512,20 +512,6 @@ systemd_notify_SOURCES = \
 systemd_notify_LDADD = \
        libsystemd-basic.la
 
-systemd_install_SOURCES = \
-       src/install.c \
-       src/path-lookup.c \
-       src/dbus-common.c \
-       src/sd-daemon.c
-
-systemd_install_LDADD = \
-       libsystemd-basic.la \
-       $(DBUS_LIBS)
-
-systemd_install_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(DBUS_CFLAGS)
-
 systemd_cgls_SOURCES = \
        src/cgls.c \
        src/cgroup-show.c \
index fb22e6c6165d88f4d950542fba0e7a37baf0d25a..30d39d7be11eeaa177cfc17d95f74783969eee2e 100644 (file)
                         the hardware of the respective kind is plugged
                         in or otherwise becomes available. In a
                         new-style init system it is possible to bind
-                        activation to hardware plug/unplug events. In systemd,
-                        kernel devices appearing in the sysfs/udev
-                        device tree can be exposed as units if they
-                        are tagged with the string
+                        activation to hardware plug/unplug events. In
+                        systemd, kernel devices appearing in the
+                        sysfs/udev device tree can be exposed as units
+                        if they are tagged with the string
                         "<literal>systemd</literal>". Like any other
                         kind of unit they may then pull in other units
                         when activated (i.e. Plugged in) and thus
                         <filename>bluetoothd.service</filename> via
                         controlling a
                         <filename>bluetooth.target.wants/</filename>
-                        symlink uniformly with a tool like
-                        <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                        symlink uniformly with a command like
+                        <command>enable</command> of
+                        <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                         instead of manipulating the udev
                         ruleset.</para>
                 </refsect2>
                         install their systemd unit files in the
                         directory returned by <command>pkg-config
                         systemd
-                        --variable=systemdsystemunitdir</command>
-                        (for system services),
-                        resp. <command>pkg-config systemd
+                        --variable=systemdsystemunitdir</command> (for
+                        system services), resp. <command>pkg-config
+                        systemd
                         --variable=systemdsessionunitdir</command>
                         (for session services). This will make the
                         services available in the system on explicit
                         installation (e.g. <command>rpm -i</command>
                         by the administrator) symlinks should be
                         created in the systemd configuration
-                        directories via the
-                        <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                        directories via the <command>enable</command>
+                        command of the
+                        <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                         tool, to activate them automatically on
                         boot.</para>
 
@@ -823,20 +825,32 @@ endif</programlisting>
                         package managers:</para>
 
                         <programlisting>%post
-/usr/bin/systemd-install --realize enable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+if [ $1 -eq 1 ]; then
+        # Enable (but don't start) the units by default
+        /bin/systemctl enable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+fi
 
 %preun
-if [ "$1" -eq 0 ]; then
-        /usr/bin/systemd-install --realize disable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+if [ $1 -eq 0 ]; then
+        # Disable and stop the units
+        /bin/systemctl disable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+        /bin/systemctl stop foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+fi
+
+%postun
+if [ $1 -ge 1 ] ; then
+        # On upgrade, reload init system configuration if we changed unit files
+        /bin/systemctl daemon-reload >/dev/null 2>&amp;1 || :
+        # On upgrade, restart the daemon
+        /bin/systemctl try-restart foobar.service >/dev/null 2>&amp;1 || :
 fi</programlisting>
 
                         <para>Depending on whether your service should
                         or should not be started/stopped/restarted
                         during package installation, deinstallation or
-                        upgrade, a different argument to
-                        <option>--realize=</option> may be
+                        upgrade, a different set of commands may be
                         specified. See
-                        <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                        <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                         for details.</para>
 
                 </refsect2>
@@ -909,7 +923,6 @@ fi</programlisting>
                 <title>See Also</title>
                 <para>
                         <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
index 678bf0b2eeaffaa1b082392e614159867a1c744f..6e4b203d8877ba80f545c4b01c2edbb29f83d1d4 100644 (file)
@@ -21,7 +21,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 -->
 
-<refentry id="systemd-install">
+<refentry id="systemctl">
 
         <refentryinfo>
                 <title>systemctl</title>
@@ -96,8 +96,9 @@
 
                                 <listitem><para>When showing
                                 unit/job/manager information, limit
-                                display to certain property names. If
-                                not specified all set properties are
+                                display to certain properties as
+                                specified as argument. If not
+                                specified all set properties are
                                 shown. The argument should be a
                                 property name, such as
                                 <literal>MainPID</literal>. If
                                 <term><option>--fail</option></term>
 
                                 <listitem><para>If the requested
-                                operation conflicts with an existing
-                                unfinished operation, fail the
-                                command. If this is not specified the
-                                requested operation will replace the
-                                pending job if
-                                necessary.</para></listitem>
+                                operation conflicts with a pending
+                                unfinished job, fail the command. If
+                                this is not specified the requested
+                                operation will replace the pending job,
+                                if necessary.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--quiet</option></term>
+                                <term><option>-q</option></term>
+
+                                <listitem><para>Suppress output to
+                                STDOUT in
+                                <command>snapshot</command>,
+                                <command>check</command>,
+                                <command>enable</command> and
+                                <command>disable</command>.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--no-block</option></term>
+
+                               <listitem><para>Do not synchronously wait for
+                               the requested operation to finish. If this is
+                               not specified the job will be verified,
+                               enqueued and <command>systemctl</command> will
+                               wait until it is completed. By passing this
+                               argument it is only verified and
+                               enqueued.</para></listitem> </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--system</option></term>
+
+                                <listitem><para>Talk to the systemd
+                                system manager. (Default)</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--session</option></term>
+
+                                <listitem><para>Talk to the systemd
+                                session manager of the calling user.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><option>--system</option></term>
+                                <term><option>--no-wall</option></term>
 
-                                <listitem><para>Talk to the systemd
-                                system manager. (Default)</para></listitem>
+                                <listitem><para>Don't send wall
+                                message before
+                                halt, power-off, reboot.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><option>--session</option></term>
+                                <term><option>--global</option></term>
 
-                                <listitem><para>Talk to the systemd
-                                session manager of the calling user.</para></listitem>
+                                <listitem><para>When used with
+                                <command>enable</command> and
+                                <command>disable</command>, operate on the
+                                global session configuĊ•ation
+                                directory, thus enabling or disabling
+                                a unit file globally for all future
+                                sessions of all users.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><option>--no-block</option></term>
+                                <term><option>--no-reload</option></term>
 
-                               <listitem><para>Do not synchronously wait for
-                               the requested operation to finish. If this is
-                               not specified the job will be verified,
-                               enqueued and <command>systemctl</command> will
-                               wait until it is completed. By passing this
-                               argument it is only verified and
-                               enqueued.</para></listitem> </varlistentry>
+                                <listitem><para>When used with
+                                <command>enable</command> and
+                                <command>disable</command>, do not
+                                implicitly reload daemon configuration
+                                after executing the
+                                changes.</para></listitem>
+                        </varlistentry>
 
                         <varlistentry>
-                                <term><option>--quiet</option></term>
-                                <term><option>-q</option></term>
+                                <term><option>--force</option></term>
 
-                                <listitem><para>Suppress output to
-                                STDOUT for <command>snapshot</command>
-                                and
-                                <command>check</command>.</para></listitem>
+                                <listitem><para>When used with
+                                <command>enable</command>, override any
+                                existing conflicting
+                                symlinks.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
-                                <term><option>--no-wall</option></term>
+                                <term><option>--defaults</option></term>
 
-                                <listitem><para>Don't send wall
-                                message before
-                                halt, power-off, reboot.</para></listitem>
+                                <listitem><para>When used with
+                                <command>disable</command>, ensures
+                                that only the symlinks created by
+                                <command>enable</command> are removed,
+                                not all symlinks pointing to the unit
+                                file that shall be
+                                disabled.</para></listitem>
                         </varlistentry>
                 </variablelist>
 
                         <varlistentry>
                                 <term><command>start [NAME...]</command></term>
 
-                                <listitem><para>Start one or more
-                                units specified on the command
+                                <listitem><para>Start (activate) one
+                                or more units specified on the command
                                 line.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>stop [NAME...]</command></term>
 
-                                <listitem><para>Stop one or more units
-                                specified on the command
+                                <listitem><para>Stop (deactivate) one
+                                or more units specified on the command
                                 line.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>reload [NAME...]</command></term>
 
-                                <listitem><para>Asks all services
-                                whose units are listed on the command
-                                line to reload their
+                                <listitem><para>Asks all units listed
+                                on the command line to reload their
                                 configuration. Note that this will
-                                reload the daemon configuration
-                                itself, not the unit configuration
-                                file of systemd. If you want systemd
-                                to reload the configuration file of a
-                                unit use the
+                                reload the service-specific
+                                configuration, not the unit
+                                configuration file of systemd. If you
+                                want systemd to reload the
+                                configuration file of a unit use the
                                 <command>daemon-reload</command>
                                 command. In other words: for the
                                 example case of Apache, this will
                                 <filename>httpd.conf</filename> in the
                                 web server, not the
                                 <filename>apache.service</filename>
-                                systemd unit file. </para> <para>This
-                                command should not be confused with
-                                the <command>daemon-reload</command>
-                                or <command>load</command>
+                                systemd unit file. </para>
+
+                                <para>This command should not be
+                                confused with the
+                                <command>daemon-reload</command> or
+                                <command>load</command>
                                 commands.</para></listitem>
 
                         </varlistentry>
                                 <term><command>reload-or-try-restart [NAME...]</command></term>
 
                                 <listitem><para>Reload one or more
-                                units if they support it. If not
-                                restart them
-                                instead.</para></listitem>
+                                units if they support it. If not,
+                                restart them instead. Note that for
+                                compatibility with SysV and Red Hat
+                                init scripts
+                                <command>force-reload</command> and
+                                <command>condrestart</command> may be
+                                used as equivalent commands to
+                                <command>reload-or-try-restart</command>.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>isolate [NAME]</command></term>
                                 others.</para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><command>check [NAME...]</command></term>
+                                <term><command>is-active [NAME...]</command></term>
 
                                 <listitem><para>Check whether any of
                                 the specified units is active
-                                (i.e. running). Returns 0 if at least
-                                one is active, non-zero
+                                (i.e. running). Returns an exit code
+                                0 if at least one is active, non-zero
                                 otherwise. Unless
                                 <option>--quiet</option> is specified
                                 this will also print the current unit
                         <varlistentry>
                                 <term><command>status [NAME...]</command></term>
 
-                                <listitem><para>Show short status
-                                information about one or more
-                                units. This shows terse runtime
-                                information about
-                                units.</para></listitem>
+                                <listitem><para>Show terse runtime
+                                status information about one or more
+                                units. This function is intended to
+                                generate human-readable output. If you
+                                are looking for computer-parsable
+                                output, use <command>show</command>
+                                instead.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>show [NAME...|JOB...]</command></term>
 
-                                <listitem><para>Show properties of
-                                one or more units, jobs or the manager
+                                <listitem><para>Show properties of one
+                                or more units, jobs or the manager
                                 itself. If no argument is specified
                                 properties of the manager will be
                                 shown. If a unit name is specified
-                                properties of the unit is shown,
-                                and if a job id is specified
-                                properties of the job is
-                                shown.</para></listitem>
+                                properties of the unit is shown, and
+                                if a job id is specified properties of
+                                the job is shown. By default, empty
+                                properties are suppressed. Use
+                                <option>--all</option> to show those
+                                too. To select specific properties to
+                                show use
+                                <option>--property=</option>. This
+                                command is intended to be used
+                                whenever computer-parsable output is
+                                required. Use
+                                <command>status</command> if you are
+                                looking for formatted human-readable
+                                output.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
                                 command.</para></listitem>
                         </varlistentry>
 
+                        <varlistentry>
+                                <term><command>enable [NAME...]</command></term>
+
+                                <listitem><para>Enable one or more
+                                unit files, as specified on the
+                                command line. This will create a
+                                number of symlinks as encoded in the
+                                <literal>[Install]</literal> sections
+                                of the unit files. After the symlinks
+                                have been created the systemd
+                                configuration is reloaded (in a way
+                                that is equivalent to
+                                <command>daemon-reload</command>) to
+                                ensure the changes are taken into
+                                account immediately. Note that this
+                                does not have the effect that any of
+                                the units enabled are also started at
+                                the same time. If this is desired a
+                                seperate <command>start</command>
+                                command must be invoked for the
+                                unit.</para>
+
+                                <para>This command will
+                                print the actions executed. This
+                                output may be suppressed by passing
+                                <option>--quiet</option>.</para>
+
+                                <para>Note that this operation creates
+                                only the suggested symlinks for the
+                                units. While this command is the
+                                recommended way to manipulate the unit
+                                configuration directory, the
+                                administrator is free to make
+                                additional changes manually, by
+                                placing or removing symlinks in the
+                                directory. This is particular useful
+                                to create configurations that deviate
+                                from the suggested default
+                                installation. In this case the
+                                administrator must make sure to invoke
+                                <command>daemon-reload</command>
+                                manually as necessary, to ensure his
+                                changes are taken into account.</para>
+
+                                <para>Enabling units should not be
+                                confused with starting (activating)
+                                units, as done by the
+                                <command>start</command>
+                                command. Enabling and starting units
+                                is orthogonal: units may be enabled
+                                without being started and started
+                                without being enabled. Enabling simply
+                                hooks the unit into various suggested
+                                places (for example, so that the unit
+                                is automatically started on boot or
+                                when a particular kind of hardware is
+                                plugged in). Starting actually spawns
+                                the daemon process (in case of service
+                                units), or binds the socket (in case
+                                of socket units), and so
+                                on.</para>
+
+                                <para>Depending on whether
+                                <option>--system</option>,
+                                <option>--session</option> or
+                                <option>--global</option> is specified
+                                this enables the unit for the system,
+                                for sessions of the calling user only
+                                or for all future session of all
+                                users. Note that in the latter case no
+                                systemd daemon configuration is
+                                reloaded.</para>
+                                </listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><command>disable [NAME...]</command></term>
+
+                                <listitem><para>Disables one or more
+                                units. This removes all symlinks to
+                                the specified unit files from the unit
+                                configuration directory, and hence
+                                undoes the changes made by
+                                <command>enable</command>. Note
+                                however that this by default removes
+                                all symlinks to the unit files
+                                (i.e. including manual additions), not
+                                just those actually created by
+                                <command>enable</command>. If only the
+                                symlinks that are suggested by default
+                                shall be removed, pass
+                                <option>--defaults</option>. This
+                                implicitly reloads the systemd daemon
+                                configuration after completing the
+                                disabling of the units. Note that this
+                                command does not implicitly stop the
+                                units that is being disabled. If this
+                                is desired an additional
+                                <command>stop</command>command should
+                                be executed afterwards.</para>
+
+                                <para>This command will print the
+                                actions executed. This output may be
+                                suppressed by passing
+                                <option>--quiet</option>.</para>
+                                </listitem>
+
+                                <para>This command honours
+                                <option>--system</option>,
+                                <option>--session</option>,
+                                <option>--global</option> in a similar
+                                way as
+                                <command>enable</command>.</para>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><command>is-enabled [NAME...]</command></term>
+
+                                <listitem><para>Checks whether any of
+                                the specified unit files is enabled
+                                (as with
+                                <command>enable</command>). Returns an
+                                exit code of 0 if at least one is
+                                enabled, non-zero
+                                otherwise.</para></listitem>
+                        </varlistentry>
+
                         <varlistentry>
                                 <term><command>load [NAME...]</command></term>
 
                                 <listitem><para>Cancel one or more
                                 jobs specified on the command line by
                                 their numeric job
-                                IDs.</para></listitem>
-                        </varlistentry>
-                        <varlistentry>
-                                <term><command>clear-jobs</command></term>
-
-                                <listitem><para>Cancel all jobs that are in progress.</para></listitem>
+                                IDs. If not job id is specified cancels all jobs that are pending.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>monitor</command></term>
diff --git a/man/systemd-install.xml b/man/systemd-install.xml
deleted file mode 100644 (file)
index 228a916..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
--->
-
-<refentry id="systemd-install">
-
-        <refentryinfo>
-                <title>systemd-install</title>
-                <productname>systemd</productname>
-
-                <authorgroup>
-                        <author>
-                                <contrib>Developer</contrib>
-                                <firstname>Lennart</firstname>
-                                <surname>Poettering</surname>
-                                <email>lennart@poettering.net</email>
-                        </author>
-                </authorgroup>
-        </refentryinfo>
-
-        <refmeta>
-                <refentrytitle>systemd-install</refentrytitle>
-                <manvolnum>1</manvolnum>
-        </refmeta>
-
-        <refnamediv>
-                <refname>systemd-install</refname>
-                <refpurpose>Enable or disable a systemd unit
-                definition file</refpurpose>
-        </refnamediv>
-
-        <refsynopsisdiv>
-                <cmdsynopsis>
-                        <command>systemd-install <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain">enable</arg> <arg choice="opt" rep="repeat">NAME</arg></command>
-                </cmdsynopsis>
-                <cmdsynopsis>
-                        <command>systemd-install <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain">disable</arg> <arg choice="opt" rep="repeat">NAME</arg></command>
-                </cmdsynopsis>
-                <cmdsynopsis>
-                        <command>systemd-install <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain">realize</arg> <arg choice="opt" rep="repeat">NAME</arg></command>
-                </cmdsynopsis>
-                <cmdsynopsis>
-                        <command>systemd-install <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain">test</arg> <arg choice="opt" rep="repeat">NAME</arg></command>
-                </cmdsynopsis>
-        </refsynopsisdiv>
-
-        <refsect1>
-                <title>Description</title>
-
-                <para><command>systemd-install</command> enables or
-                disables systemd units, or checks whether they are
-                enabled, according to the installation suggestions
-                included in the unit files.</para>
-
-                <para>This command is useful to apply or undo the
-                installation instructions encoded in the <literal>[Install]</literal>
-                section of unit files. See
-                <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-                for more information.</para>
-
-                <para>Enabling units (as with <command>systemd-install
-                enable</command>) should not be confused with
-                activating units (as with <command>systemctl
-                start</command>). The former simply installs the unit
-                files in the configuration tree, but does not start
-                them. The latter equals starting them, but does not
-                necessarily require them to be enabled.</para>
-
-                <para>Note that while
-                <command>systemd-install</command> is the recommended
-                tool to create or remove symlinks in the systemd
-                configuration directory the administrator can also
-                create links there manually, which is particularly
-                useful to use configurations that deviate from the
-                installation suggestions included in the unit
-                files.</para>
-        </refsect1>
-
-        <refsect1>
-                <title>Options</title>
-
-                <para>The following options are understood:</para>
-
-                <variablelist>
-                        <varlistentry>
-                                <term><option>--help</option></term>
-
-                                <listitem><para>Prints a short help
-                                text and exits.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--force</option></term>
-
-                                <listitem><para>Enable/disable a
-                                service even if it conflicts
-                                with/contradicts another service. This
-                                might have the effect of disabling
-                                another service that was
-                                enabled.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--system</option></term>
-
-                                <listitem><para>Enable/disable a
-                                system service.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--session</option></term>
-
-                                <listitem><para>Enable/disable a
-                                session service for the calling
-                                user.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--global</option></term>
-
-                                <listitem><para>Enable/disable a
-                                session service for all
-                                users.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--realize[=MODE]</option></term>
-
-                                <listitem><para>After
-                                enabling/disabling stop/restart/stop
-                                the unit and reload manager
-                                configuration. Optionally, takes one
-                                of <option>no</option>,
-                                <option>reload</option>,
-                                <option>minimal</option>,
-                                <option>maybe</option> or
-                                <option>yes</option>. If
-                                <option>no</option> is passed the
-                                manager will not reload its
-                                configuration and no service will be
-                                started or stopped after
-                                enabling/disabling of the unit
-                                files. If <option>reload</option> is
-                                passed the daemon configuration is
-                                reloaded but the unit otherwise not
-                                started/stopped/restarted. If
-                                <option>minimal</option> is passed and
-                                a unit is being enabled it will also
-                                be restarted should it already be
-                                running. If a unit is being disabled
-                                it will be stopped should it be
-                                running. In either case the daemon
-                                configuration is
-                                reloaded. <option>maybe</option> is
-                                similar to this, but the unit will
-                                also be started if it is being enabled
-                                and any of the units listed in
-                                <varname>WantedBy=</varname> in the
-                                <literal>[Install]</literal> section
-                                of the unit file is already
-                                activated. Finally
-                                <option>yes</option> starts the unit
-                                unconditionally after enabling. This
-                                setting defaults to
-                                <option>no</option>. If
-                                <option>--realize</option> is
-                                specifieed but the mode value is
-                                omitted defaults to
-                                <option>minimal</option>. This option
-                                has no effect when
-                                <option>--global</option> or
-                                <command>test</command> is used, or
-                                when systemd is not running or the
-                                command is executed in a
-                                <citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-                                environment. This option is implied if
-                                the <command>realize</command> command
-                                is used.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--all</option></term>
-
-                                <listitem><para>If set makes sure that
-                                all symlinks on the specified unit are
-                                removed from the configuration
-                                directory and its subdirectories, not
-                                just those specified in the
-                                <literal>[Install]</literal>
-                                section.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><option>--verbose</option></term>
-                                <term><option>-v</option></term>
-
-                                <listitem><para>Show what is done as
-                                it is done.</para></listitem>
-                        </varlistentry>
-
-                </variablelist>
-
-                <para>The following commands are understood:</para>
-
-                <variablelist>
-                        <varlistentry>
-                                <term><command>enable</command></term>
-
-                                <listitem><para>Enable one or more
-                                units. This will create a number of
-                                symlinks as encoded in the
-                                <literal>[Install]</literal> section
-                                of a unit file.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><command>disable</command></term>
-
-                                <listitem><para>Disable or more
-                                units. This will remove a number of
-                                symlinks as encoded in the
-                                <literal>[Install]</literal> section
-                                of a unit file.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><command>realize</command></term>
-
-                                <listitem><para>Does not enable or
-                                disable any unit. Checks whether any
-                                of the units specified are enabled,
-                                and then starts/stops/restarts the
-                                units accordingly. This will check for
-                                the existence of a number of symlinks
-                                as encoded in the
-                                <literal>[Install]</literal> section
-                                of a unit file, and then executes the
-                                action normally specified by
-                                <option>--realize</option>. If
-                                <option>--realize</option> is not
-                                specified implies
-                                <option>minimal</option> mode. To
-                                override this mode specify
-                                <option>--realize=</option> in
-                                addition to
-                                <command>realize</command>.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><command>test</command></term>
-
-                                <listitem><para>Does not enable or
-                                disable any unit. Checks whether any
-                                of the units specified are
-                                enabled. This will check for the
-                                existence of a number of symlinks as
-                                encoded in the
-                                <literal>[Install]</literal> section
-                                of a unit file, and return with an
-                                exit code of 0 if a unit is enabled, 1
-                                otherwise.</para></listitem>
-                        </varlistentry>
-
-                </variablelist>
-
-        </refsect1>
-
-        <refsect1>
-                <title>Exit status</title>
-
-                <para>On success 0 is returned, a non-zero failure
-                code otherwise.</para>
-        </refsect1>
-
-        <refsect1>
-                <title>See Also</title>
-                <para>
-                        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-                </para>
-        </refsect1>
-
-</refentry>
index 7284524dbbae65b58567efd4da29cf0b1a0de5b0..585145ab375f333fe7384b6373ec2d43c25c4105 100644 (file)
                 <varname>Wanted=</varname> see below. The preferred
                 way to create symlinks in the
                 <filename>.wants/</filename> directory of a service is
-                with the
-                <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                with the <command>enable</command> command of the
+                <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 tool which reads information from the [Install]
                 section of unit files. (See below.)</para>
 
                 section is not interpreted by
                 <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 during runtime. It is used exclusively by the
-                <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                <command>enable</command> and
+                <command>disable</command> commands of the
+                <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 tool during installation of a unit:</para>
 
                 <variablelist>
                                 more than once, in which case all
                                 listed names are used. At installation
                                 time,
-                                <command>systemd-install</command>
+                                <command>systemctl enable</command>
                                 will create symlinks from these names
                                 to the unit file name. Note that this
                                 is different from the
                                 <varname>Alias=</varname> apply only
                                 if the unit has actually been
                                 installed with the
-                                <command>systemd-install</command>
-                                tool.  Also, if systemd searches for a
+                                <command>systemctl enable</command>
+                                command.  Also, if systemd searches for a
                                 unit, it will discover symlinked alias
                                 names as configured with
                                 <varname>Alias=</varname>, but not
                                 installed. If the user requests
                                 installation of a unit with this
                                 option configured,
-                                <command>systemd-install</command>
+                                <command>systemctl enable</command>
                                 will automatically install units
                                 listed in this option as
                                 well.</para></listitem>
                 <para>
                         <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
index c027b4f6600fb46d1011a3c29cd18ff12b625988..d2112b1bf02963d7d7f725f56e3fb56ff302816d 100644 (file)
                                 --variable=systemdsystemconfdir</command>
                                 returns the path of the system
                                 configuration directory. Packages
-                                should alter the content of these directories
-                                only with the
-                                <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                                should alter the content of these
+                                directories only with the
+                                <command>enable</command> and
+                                <command>disable</command> commands of
+                                the
+                                <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                                 tool.</para></listitem>
                         </varlistentry>
                 </variablelist>
                                 unit files in the directory returned
                                 by <command>pkg-config systemd
                                 --variable=systemdsessionunitdir</command>. Global
-                                configuration is done in the
-                                directory reported by
-                                <command>pkg-config systemd
+                                configuration is done in the directory
+                                reported by <command>pkg-config
+                                systemd
                                 --variable=systemdsessionconfdir</command>. The
-                                <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                                <command>enable</command> and
+                                <command>disable</command> commands of
+                                the
+                                <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                                 tool can handle both global (i.e. for
                                 all users) and private (for one user)
                                 enabling/disabling of
                 <para>
                         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemadm</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>systemd-install</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd-notify</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
diff --git a/src/install.c b/src/install.c
deleted file mode 100644 (file)
index 2d6316a..0000000
+++ /dev/null
@@ -1,1165 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/stat.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include "log.h"
-#include "path-lookup.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-#include "conf-parser.h"
-#include "dbus-common.h"
-#include "sd-daemon.h"
-
-static bool arg_force = false;
-static bool arg_all = false;
-static bool arg_verbose = false;
-
-static enum {
-        WHERE_SYSTEM,
-        WHERE_SESSION,
-        WHERE_GLOBAL,
-} arg_where = WHERE_SYSTEM;
-
-static enum {
-        ACTION_INVALID,
-        ACTION_ENABLE,
-        ACTION_DISABLE,
-        ACTION_REALIZE,
-        ACTION_TEST
-} arg_action = ACTION_INVALID;
-
-static enum {
-        REALIZE_NO,        /* Don't reload/start/stop or anything */
-        REALIZE_RELOAD,    /* Only reload daemon config, don't stop/start */
-        REALIZE_MINIMAL,   /* Only shutdown/restart if running. */
-        REALIZE_MAYBE,     /* Start if WantedBy= suggests */
-        REALIZE_YES        /* Start unconditionally */
-} arg_realize = REALIZE_NO;
-
-typedef struct {
-        char *name;
-        char *path;
-
-        char **aliases;
-        char **wanted_by;
-} InstallInfo;
-
-static Hashmap *will_install = NULL, *have_installed = NULL;
-static Set *remove_symlinks_to = NULL;
-
-static int help(void) {
-
-        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
-               "Install init system units.\n\n"
-               "  -h --help           Show this help\n"
-               "     --force          Override existing links\n"
-               "     --verbose        Show what is being done as it is done\n"
-               "     --system         Install into system\n"
-               "     --session        Install into session\n"
-               "     --global         Install into all sessions\n"
-               "     --all            When disabling, remove all symlinks, not\n"
-               "                      just those listed in the [Install] section\n"
-               "     --realize[=MODE] Start/stop/restart unit after installation\n"
-               "                      Takes 'no', 'minimal', 'maybe' or 'yes'\n\n"
-               "Commands:\n"
-               "  enable [NAME...]    Enable one or more units\n"
-               "  disable [NAME...]   Disable one or more units\n"
-               "  realize [NAME...]   Test whether any of the specified units are enabled\n"
-               "                      and the start/stop/restart units accordingly\n"
-               "  test [NAME...]      Test whether any of the specified units are enabled\n",
-               program_invocation_short_name);
-
-        return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
-        enum {
-                ARG_SESSION = 0x100,
-                ARG_SYSTEM,
-                ARG_GLOBAL,
-                ARG_FORCE,
-                ARG_REALIZE,
-                ARG_ALL
-        };
-
-        static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'         },
-                { "session",   no_argument,       NULL, ARG_SESSION },
-                { "system",    no_argument,       NULL, ARG_SYSTEM  },
-                { "global",    no_argument,       NULL, ARG_GLOBAL  },
-                { "force",     no_argument,       NULL, ARG_FORCE   },
-                { "realize",   optional_argument, NULL, ARG_REALIZE },
-                { "all",       no_argument,       NULL, ARG_ALL     },
-                { "verbose",   no_argument,       NULL, 'v'         },
-                { NULL,        0,                 NULL, 0           }
-        };
-
-        int c;
-        bool realize_switch = false;
-
-        assert(argc >= 1);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "hv", options, NULL)) >= 0) {
-
-                switch (c) {
-
-                case 'h':
-                        help();
-                        return 0;
-
-                case ARG_SESSION:
-                        arg_where = WHERE_SESSION;
-                        break;
-
-                case ARG_SYSTEM:
-                        arg_where = WHERE_SYSTEM;
-                        break;
-
-                case ARG_GLOBAL:
-                        arg_where = WHERE_GLOBAL;
-                        break;
-
-                case ARG_FORCE:
-                        arg_force = true;
-                        break;
-
-                case ARG_REALIZE:
-
-                        realize_switch = true;
-
-                        if (!optarg)
-                                arg_realize = REALIZE_MINIMAL;
-                        else if (streq(optarg, "no"))
-                                arg_realize = REALIZE_NO;
-                        else if (streq(optarg, "minimal"))
-                                arg_realize = REALIZE_MINIMAL;
-                        else if (streq(optarg, "maybe"))
-                                arg_realize = REALIZE_MAYBE;
-                        else if (streq(optarg, "yes"))
-                                arg_realize = REALIZE_YES;
-                        else if (streq(optarg, "reload"))
-                                arg_realize = REALIZE_RELOAD;
-                        else {
-                                log_error("Invalid --realize argument %s", optarg);
-                                return -EINVAL;
-                        }
-
-                        break;
-
-                case ARG_ALL:
-                        arg_all = true;
-                        break;
-
-                case 'v':
-                        arg_verbose = true;
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
-                }
-        }
-
-        if (optind >= argc) {
-                help();
-                return -EINVAL;
-        }
-
-        if (streq(argv[optind], "enable"))
-                arg_action = ACTION_ENABLE;
-        else if (streq(argv[optind], "disable"))
-                arg_action = ACTION_DISABLE;
-        else if (streq(argv[optind], "test"))
-                arg_action = ACTION_TEST;
-        else if (streq(argv[optind], "realize")) {
-                arg_action = ACTION_REALIZE;
-
-                if (!realize_switch)
-                        arg_realize = REALIZE_MINIMAL;
-        } else {
-                log_error("Unknown verb %s.", argv[optind]);
-                return -EINVAL;
-        }
-
-        optind++;
-
-        if (optind >= argc) {
-                log_error("Missing unit name.");
-                return -EINVAL;
-        }
-
-
-        return 1;
-}
-
-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;
-
-        while ((i = hashmap_steal_first(m)))
-                install_info_free(i);
-
-        hashmap_free(m);
-}
-
-static bool unit_name_valid(const char *name) {
-
-        /* This is a minimal version of unit_name_valid() from
-         * unit-name.c */
-
-        if (!*name)
-                return false;
-
-        if (ignore_file(name))
-                return false;
-
-        return true;
-}
-
-static int install_info_add(const char *name) {
-        InstallInfo *i;
-        int r;
-
-        if (!unit_name_valid(name))
-                return -EINVAL;
-
-        if (hashmap_get(have_installed, name) ||
-            hashmap_get(will_install, name))
-                return 0;
-
-        if (!(i = new0(InstallInfo, 1))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (!(i->name = strdup(name))) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if ((r = hashmap_put(will_install, i->name, i)) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        if (i)
-                install_info_free(i);
-
-        return r;
-}
-
-static int daemon_reload(DBusConnection *bus) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        int r;
-
-        assert(bus);
-
-        dbus_error_init(&error);
-
-        if (arg_verbose)
-                log_info("Reloading daemon configuration.");
-
-        if (!(m = dbus_message_new_method_call(
-                              "org.freedesktop.systemd1",
-                              "/org/freedesktop/systemd1",
-                              "org.freedesktop.systemd1.Manager",
-                              "Reload"))) {
-                log_error("Could not allocate message.");
-                return -ENOMEM;
-        }
-
-        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to reload configuration: %s", error.message);
-                r = -EIO;
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-static int install_info_run(DBusConnection *bus, InstallInfo *i, bool enabled) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        int r;
-        const char *mode = "replace";
-
-        assert(bus);
-        assert(i);
-
-        dbus_error_init(&error);
-
-        if (arg_action == ACTION_ENABLE ||
-            (arg_action == ACTION_REALIZE && enabled)) {
-
-                if (arg_realize == REALIZE_MAYBE) {
-                        char **k;
-                        bool yes_please = false;
-
-                        STRV_FOREACH(k, i->wanted_by) {
-                                DBusMessageIter sub, iter;
-
-                                const char *path, *state;
-                                const char *interface = "org.freedesktop.systemd1.Unit";
-                                const char *property = "ActiveState";
-
-                                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, k,
-                                                              DBUS_TYPE_INVALID)) {
-                                        log_error("Could not append arguments to message.");
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                        /* Hmm, this unit doesn't exist, let's try the next one */
-                                        dbus_message_unref(m);
-                                        m = NULL;
-                                        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(bus, m, -1, &error))) {
-                                        log_error("Failed to issue method call: %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);
-
-                                dbus_message_unref(m);
-                                dbus_message_unref(reply);
-                                m = reply = NULL;
-
-                                if (streq(state, "active") ||
-                                    startswith(state, "reloading") ||
-                                    startswith(state, "activating")) {
-                                        yes_please = true;
-                                        break;
-                                }
-                        }
-
-                        if (!yes_please) {
-                                r = 0;
-                                goto finish;
-                        }
-                }
-
-                if (arg_verbose)
-                        log_info("Restarting %s.", i->name);
-
-                if (!(m = dbus_message_new_method_call(
-                                      "org.freedesktop.systemd1",
-                                      "/org/freedesktop/systemd1",
-                                      "org.freedesktop.systemd1.Manager",
-                                      arg_realize == REALIZE_MINIMAL ? "TryRestartUnit" : "RestartUnit"))) {
-                        log_error("Could not allocate message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &i->name,
-                                              DBUS_TYPE_STRING, &mode,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-
-        } else if (arg_action == ACTION_DISABLE ||
-                   (arg_action == ACTION_REALIZE && !enabled)) {
-
-                if (arg_verbose)
-                        log_info("Stopping %s.", i->name);
-
-                if (!(m = dbus_message_new_method_call(
-                                      "org.freedesktop.systemd1",
-                                      "/org/freedesktop/systemd1",
-                                      "org.freedesktop.systemd1.Manager",
-                                      "StopUnit"))) {
-                        log_error("Could not allocate message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &i->name,
-                                              DBUS_TYPE_STRING, &mode,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-        } else
-                assert_not_reached("install_info_run() called but nothing to do?");
-
-        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to realize unit: %s", error.message);
-                r = -EIO;
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-static int config_parse_also(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char *n;
-                int r;
-
-                if (!(n = strndup(w, l)))
-                        return -ENOMEM;
-
-                r = install_info_add(n);
-                free(n);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int mark_symlink_for_removal(const char *p) {
-        char *n;
-        int r;
-
-        assert(p);
-        assert(path_is_absolute(p));
-
-        if (!remove_symlinks_to)
-                return 0;
-
-        if (!(n = canonicalize_file_name(p)))
-                if (!(n = strdup(p)))
-                        return -ENOMEM;
-
-        path_kill_slashes(n);
-
-        if ((r = set_put(remove_symlinks_to, n)) < 0) {
-                free(n);
-                return r;
-        }
-
-        return 0;
-}
-
-static int remove_marked_symlinks_fd(int fd, const char *config_path, const char *root, bool *deleted) {
-        int r = 0;
-        DIR *d;
-        struct dirent *de;
-
-        assert(fd >= 0);
-        assert(root);
-        assert(deleted);
-
-        if (!(d = fdopendir(fd)))
-                return -errno;
-
-        rewinddir(d);
-
-        while ((de = readdir(d))) {
-                bool is_dir = false, is_link = false;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                if (de->d_type == DT_LNK)
-                        is_link = true;
-                else if (de->d_type == DT_DIR)
-                        is_dir = true;
-                else if (de->d_type == DT_UNKNOWN) {
-                        struct stat st;
-
-                        if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
-                                log_error("Failed to stat %s/%s: %m", root, de->d_name);
-
-                                if (r == 0)
-                                        r = -errno;
-                                continue;
-                        }
-
-                        is_link = S_ISLNK(st.st_mode);
-                        is_dir = S_ISDIR(st.st_mode);
-                } else
-                        continue;
-
-                if (is_dir) {
-                        int nfd, q;
-                        char *p;
-
-                        if ((nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0) {
-                                log_error("Failed to open %s/%s: %m", root, de->d_name);
-
-                                if (r == 0)
-                                        r = -errno;
-                                continue;
-                        }
-
-                        if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
-                                log_error("Failed to allocate directory string.");
-                                close_nointr_nofail(nfd);
-                                r = -ENOMEM;
-                                break;
-                        }
-
-                        q = remove_marked_symlinks_fd(nfd, config_path, p, deleted);
-                        free(p);
-                        close_nointr_nofail(nfd);
-
-                        if (r == 0)
-                                q = r;
-
-                } else if (is_link) {
-                        char *p, *dest, *c;
-                        int q;
-
-                        if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
-                                log_error("Failed to allocate symlink string.");
-                                r = -ENOMEM;
-                                break;
-                        }
-
-                        if ((q = readlink_and_make_absolute(p, &dest)) < 0) {
-                                log_error("Cannot read symlink %s: %s", p, strerror(-q));
-                                free(p);
-
-                                if (r == 0)
-                                        r = q;
-                                continue;
-                        }
-
-                        if ((c = canonicalize_file_name(dest))) {
-                                /* This might fail if the destination
-                                 * is already removed */
-
-                                free(dest);
-                                dest = c;
-                        }
-
-                        path_kill_slashes(dest);
-                        if (set_get(remove_symlinks_to, dest)) {
-
-                                if (arg_verbose)
-                                        log_info("rm '%s'", p);
-
-                                if (unlink(p) < 0) {
-                                        log_error("Cannot unlink symlink %s: %m", p);
-
-                                        if (r == 0)
-                                                r = -errno;
-                                } else {
-                                        rmdir_parents(p, config_path);
-                                        path_kill_slashes(p);
-
-                                        if (!set_get(remove_symlinks_to, p)) {
-
-                                                if ((r = mark_symlink_for_removal(p)) < 0) {
-                                                        if (r == 0)
-                                                                r = q;
-                                                } else
-                                                        *deleted = true;
-                                        }
-                                }
-                        }
-
-                        free(p);
-                        free(dest);
-                }
-        }
-
-        return r;
-}
-
-static int remove_marked_symlinks(const char *config_path) {
-        int fd, r = 0;
-        bool deleted;
-
-        assert(config_path);
-
-        if (set_size(remove_symlinks_to) <= 0)
-                return 0;
-
-        if ((fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0)
-                return -errno;
-
-        do {
-                int q;
-                deleted = false;
-
-                if ((q = remove_marked_symlinks_fd(fd, config_path, config_path, &deleted)) < 0) {
-                        if (r == 0)
-                                r = q;
-                }
-        } while (deleted);
-
-        close_nointr_nofail(fd);
-
-        return r;
-}
-
-static int create_symlink(const char *old_path, const char *new_path) {
-        int r;
-
-        assert(old_path);
-        assert(new_path);
-
-        if (arg_action == ACTION_ENABLE) {
-                char *dest;
-
-                mkdir_parents(new_path, 0755);
-
-                if (symlink(old_path, new_path) >= 0)
-                        return 0;
-
-                if (errno != EEXIST) {
-                        log_error("Cannot link %s to %s: %m", old_path, new_path);
-                        return -errno;
-                }
-
-                if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
-
-                        if (errno == EINVAL) {
-                                log_error("Cannot link %s to %s, file exists already and is not a symlink.", old_path, new_path);
-                                return -EEXIST;
-                        }
-
-                        log_error("readlink() failed: %s", strerror(-r));
-                        return r;
-                }
-
-                if (streq(dest, old_path)) {
-                        free(dest);
-                        return 0;
-                }
-
-                if (!arg_force) {
-                        log_error("Cannot link %s to %s, symlink exists already and points to %s.", old_path, new_path, dest);
-                        free(dest);
-                        return -EEXIST;
-                }
-
-                free(dest);
-                unlink(new_path);
-
-                if (arg_verbose)
-                        log_info("ln -s '%s' '%s'", old_path, new_path);
-
-                if (symlink(old_path, new_path) >= 0)
-                        return 0;
-
-                log_error("Cannot link %s to %s: %m", old_path, new_path);
-                return -errno;
-
-        } else if (arg_action == ACTION_DISABLE) {
-                char *dest;
-
-                if ((r = mark_symlink_for_removal(old_path)) < 0)
-                        return r;
-
-                if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
-                        if (errno == ENOENT)
-                                return 0;
-
-                        if (errno == EINVAL) {
-                                log_warning("File %s not a symlink, ignoring.", old_path);
-                                return 0;
-                        }
-
-                        log_error("readlink() failed: %s", strerror(-r));
-                        return r;
-                }
-
-                if (!streq(dest, old_path)) {
-                        log_warning("File %s not a symlink to %s but points to %s, ignoring.", new_path, old_path, dest);
-                        free(dest);
-                        return 0;
-                }
-
-
-                free(dest);
-
-                if ((r = mark_symlink_for_removal(new_path)) < 0)
-                        return r;
-
-                if (arg_verbose)
-                        log_info("rm '%s'", new_path);
-
-                if (unlink(new_path) >= 0)
-                        return 0;
-
-                log_error("Cannot unlink %s: %m", new_path);
-                return -errno;
-
-        } else if (arg_action == ACTION_TEST || arg_action == ACTION_REALIZE) {
-                char *dest;
-
-                if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
-
-                        if (errno == ENOENT || errno == EINVAL)
-                                return 0;
-
-                        log_error("readlink() failed: %s", strerror(-r));
-                        return r;
-                }
-
-                if (streq(dest, old_path)) {
-                        free(dest);
-                        return 1;
-                }
-
-                return 0;
-        }
-
-        assert_not_reached("Unknown action.");
-}
-
-static int install_info_symlink_alias(InstallInfo *i, const char *config_path) {
-        char **s;
-        char *alias_path = NULL;
-        int r;
-
-        assert(i);
-
-        STRV_FOREACH(s, i->aliases) {
-
-                if (!unit_name_valid(*s)) {
-                        log_error("Invalid name %s.", *s);
-                        r = -EINVAL;
-                        goto finish;
-                }
-
-                free(alias_path);
-                if (!(alias_path = path_make_absolute(*s, config_path))) {
-                        log_error("Out of memory");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if ((r = create_symlink(i->path, alias_path)) != 0)
-                        goto finish;
-
-                if (arg_action == ACTION_DISABLE)
-                        rmdir_parents(alias_path, config_path);
-        }
-
-        r = 0;
-
-finish:
-        free(alias_path);
-
-        return r;
-}
-
-static int install_info_symlink_wants(InstallInfo *i, const char *config_path) {
-        char **s;
-        char *alias_path = NULL;
-        int r;
-
-        assert(i);
-
-        STRV_FOREACH(s, i->wanted_by) {
-                if (!unit_name_valid(*s)) {
-                        log_error("Invalid name %s.", *s);
-                        r = -EINVAL;
-                        goto finish;
-                }
-
-                free(alias_path);
-                alias_path = NULL;
-
-                if (asprintf(&alias_path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) {
-                        log_error("Out of memory");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if ((r = create_symlink(i->path, alias_path)) != 0)
-                        goto finish;
-
-                if (arg_action == ACTION_DISABLE)
-                        rmdir_parents(alias_path, config_path);
-        }
-
-        r = 0;
-
-finish:
-        free(alias_path);
-
-        return r;
-}
-
-static int install_info_apply(LookupPaths *paths, InstallInfo *i, const char *config_path) {
-
-        const ConfigItem items[] = {
-                { "Alias",    config_parse_strv, &i->aliases,   "Install" },
-                { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
-                { "Also",     config_parse_also, NULL,          "Install" },
-
-                { NULL, NULL, NULL, NULL }
-        };
-
-        char **p;
-        char *filename = NULL;
-        FILE *f = NULL;
-        int r;
-
-        assert(paths);
-        assert(i);
-
-        STRV_FOREACH(p, paths->unit_path) {
-                int fd;
-
-                if (!(filename = path_make_absolute(i->name, *p))) {
-                        log_error("Out of memory");
-                        return -ENOMEM;
-                }
-
-                /* Ensure that we don't follow symlinks */
-                if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
-                        if ((f = fdopen(fd, "re")))
-                                break;
-
-                if (errno == ELOOP) {
-                        log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
-                        free(filename);
-                        return -errno;
-                }
-
-                if (errno != ENOENT) {
-                        log_error("Failed to open %s: %m", filename);
-                        free(filename);
-                        return -errno;
-                }
-
-                free(filename);
-                filename = NULL;
-        }
-
-        if (!f) {
-                log_error("Couldn't find %s.", i->name);
-                return -ENOENT;
-        }
-
-        i->path = filename;
-
-        if ((r = config_parse(filename, f, NULL, items, true, i)) < 0) {
-                fclose(f);
-                return r;
-        }
-
-        fclose(f);
-
-        if ((r = install_info_symlink_alias(i, config_path)) != 0)
-                return r;
-
-        if ((r = install_info_symlink_wants(i, config_path)) != 0)
-                return r;
-
-        if ((r = mark_symlink_for_removal(filename)) < 0)
-                return r;
-
-        if ((r = remove_marked_symlinks(config_path)) < 0)
-                return r;
-
-        return 0;
-}
-
-static char *get_config_path(void) {
-
-        switch (arg_where) {
-
-        case WHERE_SYSTEM:
-                return strdup(SYSTEM_CONFIG_UNIT_PATH);
-
-        case WHERE_GLOBAL:
-                return strdup(SESSION_CONFIG_UNIT_PATH);
-
-        case WHERE_SESSION: {
-                char *p;
-
-                if (session_config_home(&p) < 0)
-                        return NULL;
-
-                return p;
-        }
-
-        default:
-                assert_not_reached("Unknown config path.");
-        }
-}
-
-static int do_realize(bool enabled) {
-        DBusConnection *bus = NULL;
-        DBusError error;
-        int r, q;
-        Iterator i;
-        InstallInfo *j;
-
-        dbus_error_init(&error);
-
-        if (arg_realize == REALIZE_NO)
-                return 0;
-
-        if (arg_where == WHERE_GLOBAL) {
-                log_warning("Warning: --realize has no effect with --global.");
-                return 0;
-        }
-
-        if (arg_action == ACTION_TEST) {
-                log_warning("Warning: --realize has no effect with test.");
-                return 0;
-        }
-
-        if (arg_where == WHERE_SYSTEM && sd_booted() <= 0) {
-                log_info("systemd is not running, --realize has no effect.");
-                return 0;
-        }
-
-        if (arg_where == WHERE_SYSTEM && running_in_chroot() > 0) {
-                log_info("Running in a chroot() environment, --realize has no effect.");
-                return 0;
-        }
-
-        if ((r = bus_connect(arg_where == WHERE_SESSION ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, NULL, &error)) < 0) {
-                log_error("Failed to get D-Bus connection: %s", error.message);
-                goto finish;
-        }
-
-        r = 0;
-
-        if (arg_action == ACTION_ENABLE || arg_action == ACTION_REALIZE)
-                if ((r = daemon_reload(bus)) < 0)
-                        goto finish;
-
-        if (arg_realize != REALIZE_RELOAD) {
-                HASHMAP_FOREACH(j, have_installed, i)
-                        if ((q = install_info_run(bus, j, enabled)) < 0)
-                                r = q;
-        }
-
-        if (arg_action == ACTION_DISABLE)
-                if ((q = daemon_reload(bus)) < 0)
-                        r = q;
-
-finish:
-        if (bus) {
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-        }
-
-        dbus_error_free(&error);
-
-        dbus_shutdown();
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        int r, retval = 1, j;
-        LookupPaths paths;
-        InstallInfo *i;
-        char *config_path = NULL;
-
-        zero(paths);
-
-        log_parse_environment();
-
-        if ((r = parse_argv(argc, argv)) < 0)
-                goto finish;
-        else if (r == 0) {
-                retval = 0;
-                goto finish;
-        }
-
-        if ((r = lookup_paths_init(&paths, arg_where == WHERE_SYSTEM ? MANAGER_SYSTEM : MANAGER_SESSION)) < 0) {
-                log_error("Failed to determine lookup paths: %s", strerror(-r));
-                goto finish;
-        }
-
-        if (!(config_path = get_config_path())) {
-                log_error("Failed to determine config path");
-                goto finish;
-        }
-
-        will_install = hashmap_new(string_hash_func, string_compare_func);
-        have_installed = hashmap_new(string_hash_func, string_compare_func);
-
-        if (!will_install || !have_installed) {
-                log_error("Failed to allocate unit sets.");
-                goto finish;
-        }
-
-        if (arg_all)
-                if (!(remove_symlinks_to = set_new(string_hash_func, string_compare_func))) {
-                        log_error("Failed to allocate symlink sets.");
-                        goto finish;
-                }
-
-        for (j = optind; j < argc; j++)
-                if ((r = install_info_add(argv[j])) < 0)
-                        goto finish;
-
-
-        while ((i = hashmap_first(will_install))) {
-                assert_se(hashmap_move_one(have_installed, will_install, i->name) == 0);
-
-                if ((r = install_info_apply(&paths, i, config_path)) != 0) {
-
-                        if (r < 0)
-                                goto finish;
-
-                        /* In test mode and found something */
-                        retval = 0;
-                        break;
-                }
-        }
-
-        if (do_realize(!retval) < 0)
-                goto finish;
-
-finish:
-        install_info_hashmap_free(will_install);
-        install_info_hashmap_free(have_installed);
-
-        set_free_free(remove_symlinks_to);
-
-        lookup_paths_free(&paths);
-
-        free(config_path);
-
-        return retval;
-}
index 667aeaeb9642cd4ee40891c745d96f522681b46c..1e3385f8604074ff59ea09939cc2be1d722da66e 100644 (file)
@@ -30,6 +30,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 
 #include <dbus/dbus.h>
 
 #include "cgroup-show.h"
 #include "cgroup-util.h"
 #include "list.h"
+#include "path-lookup.h"
+#include "conf-parser.h"
+#include "sd-daemon.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
 static bool arg_all = false;
 static bool arg_fail = false;
 static bool arg_session = false;
-static bool arg_no_block = false;
+static bool arg_global = false;
 static bool arg_immediate = false;
+static bool arg_no_block = false;
 static bool arg_no_wtmp = false;
 static bool arg_no_sync = false;
 static bool arg_no_wall = false;
+static bool arg_no_reload = false;
 static bool arg_dry = false;
 static bool arg_quiet = false;
-static char arg_full = false;
+static bool arg_full = false;
+static bool arg_force = false;
+static bool arg_defaults = false;
 static char **arg_wall = NULL;
 static enum action {
         ACTION_INVALID,
@@ -86,6 +94,8 @@ static enum dot {
 
 static bool private_bus = false;
 
+static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
+
 static const char *ansi_highlight(bool b) {
         static int t = -1;
 
@@ -687,6 +697,9 @@ static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
         assert(bus);
         assert(args);
 
+        if (n <= 1)
+                return daemon_reload(bus, args, n);
+
         for (i = 1; i < n; i++) {
                 unsigned id;
                 const char *path;
@@ -766,7 +779,7 @@ finish:
         return r;
 }
 
-static bool unit_need_daemon_reload(DBusConnection *bus, const char *unit) {
+static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
         DBusMessage *m, *reply;
         dbus_bool_t b = FALSE;
         DBusMessageIter iter, sub;
@@ -1007,7 +1020,7 @@ static int start_unit_one(
                 goto finish;
         }
 
-        if (unit_need_daemon_reload(bus, name))
+        if (need_daemon_reload(bus, name))
                 log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
                             arg_session ? "--session" : "--system");
 
@@ -2653,7 +2666,7 @@ finish:
         return r;
 }
 
-static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
+static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusError error;
         int r;
@@ -2669,11 +2682,12 @@ static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
                 assert(arg_action == ACTION_SYSTEMCTL);
 
                 method =
-                        streq(args[0], "clear-jobs")        ? "ClearJobs" :
-                        streq(args[0], "daemon-reload")     ? "Reload" :
+                        streq(args[0], "clear-jobs")        ||
+                        streq(args[0], "cancel")            ? "ClearJobs" :
                         streq(args[0], "daemon-reexec")     ? "Reexecute" :
                         streq(args[0], "reset-maintenance") ? "ResetMaintenance" :
-                                                              "Exit";
+                        streq(args[0], "daemon-exit")       ? "Exit" :
+                                                              "Reload";
         }
 
         if (!(m = dbus_message_new_method_call(
@@ -2723,7 +2737,7 @@ static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
         dbus_error_init(&error);
 
         if (n <= 1)
-                return clear_jobs(bus, args, n);
+                return daemon_reload(bus, args, n);
 
         for (i = 1; i < n; i++) {
 
@@ -2917,6 +2931,691 @@ finish:
         return r;
 }
 
+typedef struct {
+        char *name;
+        char *path;
+
+        char **aliases;
+        char **wanted_by;
+} InstallInfo;
+
+static Hashmap *will_install = NULL, *have_installed = NULL;
+static Set *remove_symlinks_to = NULL;
+
+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;
+
+        while ((i = hashmap_steal_first(m)))
+                install_info_free(i);
+
+        hashmap_free(m);
+}
+
+static bool unit_name_valid(const char *name) {
+
+        /* This is a minimal version of unit_name_valid() from
+         * unit-name.c */
+
+        if (!*name)
+                return false;
+
+        if (ignore_file(name))
+                return false;
+
+        return true;
+}
+
+static int install_info_add(const char *name) {
+        InstallInfo *i;
+        int r;
+
+        assert(will_install);
+
+        if (!unit_name_valid(name))
+                return -EINVAL;
+
+        if (hashmap_get(have_installed, name) ||
+            hashmap_get(will_install, name))
+                return 0;
+
+        if (!(i = new0(InstallInfo, 1))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (!(i->name = strdup(name))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if ((r = hashmap_put(will_install, i->name, i)) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        if (i)
+                install_info_free(i);
+
+        return r;
+}
+
+static int config_parse_also(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                char *n;
+                int r;
+
+                if (!(n = strndup(w, l)))
+                        return -ENOMEM;
+
+                r = install_info_add(n);
+                free(n);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int mark_symlink_for_removal(const char *p) {
+        char *n;
+        int r;
+
+        assert(p);
+        assert(path_is_absolute(p));
+
+        if (!remove_symlinks_to)
+                return 0;
+
+        if (!(n = strdup(p)))
+                return -ENOMEM;
+
+        path_kill_slashes(n);
+
+        if ((r = set_put(remove_symlinks_to, n)) < 0) {
+                free(n);
+                return r == -EEXIST ? 0 : r;
+        }
+
+        return 0;
+}
+
+static int remove_marked_symlinks_fd(int fd, const char *config_path, const char *root, bool *deleted) {
+        int r = 0;
+        DIR *d;
+        struct dirent *de;
+
+        assert(fd >= 0);
+        assert(root);
+        assert(deleted);
+
+        if (!(d = fdopendir(fd))) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        rewinddir(d);
+
+        while ((de = readdir(d))) {
+                bool is_dir = false, is_link = false;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                if (de->d_type == DT_LNK)
+                        is_link = true;
+                else if (de->d_type == DT_DIR)
+                        is_dir = true;
+                else if (de->d_type == DT_UNKNOWN) {
+                        struct stat st;
+
+                        if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+                                log_error("Failed to stat %s/%s: %m", root, de->d_name);
+
+                                if (r == 0)
+                                        r = -errno;
+                                continue;
+                        }
+
+                        is_link = S_ISLNK(st.st_mode);
+                        is_dir = S_ISDIR(st.st_mode);
+                } else
+                        continue;
+
+                if (is_dir) {
+                        int nfd, q;
+                        char *p;
+
+                        if ((nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0) {
+                                log_error("Failed to open %s/%s: %m", root, de->d_name);
+
+                                if (r == 0)
+                                        r = -errno;
+                                continue;
+                        }
+
+                        if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
+                                log_error("Failed to allocate directory string.");
+                                close_nointr_nofail(nfd);
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        /* This will close nfd, regardless whether it succeeds or not */
+                        q = remove_marked_symlinks_fd(nfd, config_path, p, deleted);
+                        free(p);
+
+                        if (r == 0)
+                                q = r;
+
+                } else if (is_link) {
+                        char *p, *dest, *c;
+                        int q;
+
+                        if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
+                                log_error("Failed to allocate symlink string.");
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        if ((q = readlink_and_make_absolute(p, &dest)) < 0) {
+                                log_error("Cannot read symlink %s: %s", p, strerror(-q));
+                                free(p);
+
+                                if (r == 0)
+                                        r = q;
+                                continue;
+                        }
+
+                        if ((c = canonicalize_file_name(dest))) {
+                                /* This might fail if the destination
+                                 * is already removed */
+
+                                free(dest);
+                                dest = c;
+                        }
+
+                        path_kill_slashes(dest);
+                        if (set_get(remove_symlinks_to, dest)) {
+
+                                if (!arg_quiet)
+                                        log_info("rm '%s'", p);
+
+                                if (unlink(p) < 0) {
+                                        log_error("Cannot unlink symlink %s: %m", p);
+
+                                        if (r == 0)
+                                                r = -errno;
+                                } else {
+                                        rmdir_parents(p, config_path);
+                                        path_kill_slashes(p);
+
+                                        if (!set_get(remove_symlinks_to, p)) {
+
+                                                if ((r = mark_symlink_for_removal(p)) < 0) {
+                                                        if (r == 0)
+                                                                r = q;
+                                                } else
+                                                        *deleted = true;
+                                        }
+                                }
+                        }
+
+                        free(p);
+                        free(dest);
+                }
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+static int remove_marked_symlinks(const char *config_path) {
+        int fd, r = 0;
+        bool deleted;
+
+        assert(config_path);
+
+        if (set_size(remove_symlinks_to) <= 0)
+                return 0;
+
+        if ((fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0)
+                return -errno;
+
+        do {
+                int q, cfd;
+                deleted = false;
+
+                if ((cfd = dup(fd)) < 0) {
+                        r = -errno;
+                        break;
+                }
+
+                /* This takes possession of cfd and closes it */
+                if ((q = remove_marked_symlinks_fd(cfd, config_path, config_path, &deleted)) < 0) {
+                        if (r == 0)
+                                r = q;
+                }
+        } while (deleted);
+
+        close_nointr_nofail(fd);
+
+        return r;
+}
+
+static int create_symlink(const char *verb, const char *old_path, const char *new_path) {
+        int r;
+
+        assert(old_path);
+        assert(new_path);
+        assert(verb);
+
+        if (streq(verb, "enable")) {
+                char *dest;
+
+                mkdir_parents(new_path, 0755);
+
+                if (symlink(old_path, new_path) >= 0) {
+
+                        if (!arg_quiet)
+                                log_info("ln -s '%s' '%s'", old_path, new_path);
+
+                        return 0;
+                }
+
+                if (errno != EEXIST) {
+                        log_error("Cannot link %s to %s: %m", old_path, new_path);
+                        return -errno;
+                }
+
+                if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
+
+                        if (errno == EINVAL) {
+                                log_error("Cannot link %s to %s, file exists already and is not a symlink.", old_path, new_path);
+                                return -EEXIST;
+                        }
+
+                        log_error("readlink() failed: %s", strerror(-r));
+                        return r;
+                }
+
+                if (streq(dest, old_path)) {
+                        free(dest);
+                        return 0;
+                }
+
+                if (!arg_force) {
+                        log_error("Cannot link %s to %s, symlink exists already and points to %s.", old_path, new_path, dest);
+                        free(dest);
+                        return -EEXIST;
+                }
+
+                free(dest);
+                unlink(new_path);
+
+                if (!arg_quiet)
+                        log_info("ln -s '%s' '%s'", old_path, new_path);
+
+                if (symlink(old_path, new_path) >= 0)
+                        return 0;
+
+                log_error("Cannot link %s to %s: %m", old_path, new_path);
+                return -errno;
+
+        } else if (streq(verb, "disable")) {
+                char *dest;
+
+                if ((r = mark_symlink_for_removal(old_path)) < 0)
+                        return r;
+
+                if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
+                        if (errno == ENOENT)
+                                return 0;
+
+                        if (errno == EINVAL) {
+                                log_warning("File %s not a symlink, ignoring.", old_path);
+                                return 0;
+                        }
+
+                        log_error("readlink() failed: %s", strerror(-r));
+                        return r;
+                }
+
+                if (!streq(dest, old_path)) {
+                        log_warning("File %s not a symlink to %s but points to %s, ignoring.", new_path, old_path, dest);
+                        free(dest);
+                        return 0;
+                }
+
+                free(dest);
+
+                if ((r = mark_symlink_for_removal(new_path)) < 0)
+                        return r;
+
+                if (!arg_quiet)
+                        log_info("rm '%s'", new_path);
+
+                if (unlink(new_path) >= 0)
+                        return 0;
+
+                log_error("Cannot unlink %s: %m", new_path);
+                return -errno;
+
+        } else if (streq(verb, "is-enabled")) {
+                char *dest;
+
+                if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
+
+                        if (errno == ENOENT || errno == EINVAL)
+                                return 0;
+
+                        log_error("readlink() failed: %s", strerror(-r));
+                        return r;
+                }
+
+                if (streq(dest, old_path)) {
+                        free(dest);
+                        return 1;
+                }
+
+                return 0;
+        }
+
+        assert_not_reached("Unknown action.");
+}
+
+static int install_info_symlink_alias(const char *verb, InstallInfo *i, const char *config_path) {
+        char **s;
+        char *alias_path = NULL;
+        int r;
+
+        assert(verb);
+        assert(i);
+        assert(config_path);
+
+        STRV_FOREACH(s, i->aliases) {
+
+                if (!unit_name_valid(*s)) {
+                        log_error("Invalid name %s.", *s);
+                        r = -EINVAL;
+                        goto finish;
+                }
+
+                free(alias_path);
+                if (!(alias_path = path_make_absolute(*s, config_path))) {
+                        log_error("Out of memory");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if ((r = create_symlink(verb, i->path, alias_path)) != 0)
+                        goto finish;
+
+                if (streq(verb, "disable"))
+                        rmdir_parents(alias_path, config_path);
+        }
+
+        r = 0;
+
+finish:
+        free(alias_path);
+
+        return r;
+}
+
+static int install_info_symlink_wants(const char *verb, InstallInfo *i, const char *config_path) {
+        char **s;
+        char *alias_path = NULL;
+        int r;
+
+        assert(verb);
+        assert(i);
+        assert(config_path);
+
+        STRV_FOREACH(s, i->wanted_by) {
+                if (!unit_name_valid(*s)) {
+                        log_error("Invalid name %s.", *s);
+                        r = -EINVAL;
+                        goto finish;
+                }
+
+                free(alias_path);
+                alias_path = NULL;
+
+                if (asprintf(&alias_path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) {
+                        log_error("Out of memory");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if ((r = create_symlink(verb, i->path, alias_path)) != 0)
+                        goto finish;
+
+                if (streq(verb, "disable"))
+                        rmdir_parents(alias_path, config_path);
+        }
+
+        r = 0;
+
+finish:
+        free(alias_path);
+
+        return r;
+}
+
+static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo *i, const char *config_path) {
+
+        const ConfigItem items[] = {
+                { "Alias",    config_parse_strv, &i->aliases,   "Install" },
+                { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
+                { "Also",     config_parse_also, NULL,          "Install" },
+
+                { NULL, NULL, NULL, NULL }
+        };
+
+        char **p;
+        char *filename = NULL;
+        FILE *f = NULL;
+        int r;
+
+        assert(paths);
+        assert(i);
+
+        STRV_FOREACH(p, paths->unit_path) {
+                int fd;
+
+                if (!(filename = path_make_absolute(i->name, *p))) {
+                        log_error("Out of memory");
+                        return -ENOMEM;
+                }
+
+                /* Ensure that we don't follow symlinks */
+                if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
+                        if ((f = fdopen(fd, "re")))
+                                break;
+
+                if (errno == ELOOP) {
+                        log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
+                        free(filename);
+                        return -errno;
+                }
+
+                if (errno != ENOENT) {
+                        log_error("Failed to open %s: %m", filename);
+                        free(filename);
+                        return -errno;
+                }
+
+                free(filename);
+                filename = NULL;
+        }
+
+        if (!f) {
+                log_error("Couldn't find %s.", i->name);
+                return -ENOENT;
+        }
+
+        i->path = filename;
+
+        if ((r = config_parse(filename, f, NULL, items, true, i)) < 0) {
+                fclose(f);
+                return r;
+        }
+
+        fclose(f);
+
+        if ((r = install_info_symlink_alias(verb, i, config_path)) != 0)
+                return r;
+
+        if ((r = install_info_symlink_wants(verb, i, config_path)) != 0)
+                return r;
+
+        if ((r = mark_symlink_for_removal(filename)) < 0)
+                return r;
+
+        if ((r = remove_marked_symlinks(config_path)) < 0)
+                return r;
+
+        return 0;
+}
+
+static char *get_config_path(void) {
+
+        if (arg_session && arg_global)
+                return strdup(SESSION_CONFIG_UNIT_PATH);
+
+        if (arg_session) {
+                char *p;
+
+                if (session_config_home(&p) < 0)
+                        return NULL;
+
+                return p;
+        }
+
+        return strdup(SYSTEM_CONFIG_UNIT_PATH);
+}
+
+static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
+        DBusError error;
+        int r;
+        LookupPaths paths;
+        char *config_path = NULL;
+        unsigned j;
+        InstallInfo *i;
+        const char *verb = args[0];
+
+        dbus_error_init(&error);
+
+        zero(paths);
+        if ((r = lookup_paths_init(&paths, arg_session ? MANAGER_SESSION : MANAGER_SYSTEM)) < 0) {
+                log_error("Failed to determine lookup paths: %s", strerror(-r));
+                goto finish;
+        }
+
+        if (!(config_path = get_config_path())) {
+                log_error("Failed to determine config path");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        will_install = hashmap_new(string_hash_func, string_compare_func);
+        have_installed = hashmap_new(string_hash_func, string_compare_func);
+
+        if (!will_install || !have_installed) {
+                log_error("Failed to allocate unit sets.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!arg_defaults && streq(verb, "disable"))
+                if (!(remove_symlinks_to = set_new(string_hash_func, string_compare_func))) {
+                        log_error("Failed to allocate symlink sets.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+        for (j = 1; j < n; j++)
+                if ((r = install_info_add(args[j])) < 0)
+                        goto finish;
+
+        while ((i = hashmap_first(will_install))) {
+                int q;
+
+                assert_se(hashmap_move_one(have_installed, will_install, i->name) == 0);
+
+                if ((q = install_info_apply(verb, &paths, i, config_path)) != 0) {
+
+                        if (q < 0) {
+                                if (r == 0)
+                                        r = q;
+                                goto finish;
+                        }
+
+                        /* In test mode and found something */
+                        r = 1;
+                        break;
+                }
+        }
+
+        if (streq(verb, "is-enabled"))
+                r = r > 0 ? 0 : -ENOENT;
+        else if (bus &&
+                 /* Don't try to reload anything if the user asked us to not do this */
+                 !arg_no_reload &&
+                 /* Don't try to reload anything when updating a unit globally */
+                 !arg_global &&
+                 /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */
+                 (arg_session || sd_booted() > 0) &&
+                 /* Don't try to reload anything if we are running in a chroot environment */
+                 (arg_session || running_in_chroot() <= 0) ) {
+                int q;
+
+                if ((q = daemon_reload(bus, args, n)) < 0)
+                        r = q;
+        }
+
+finish:
+        install_info_hashmap_free(will_install);
+        install_info_hashmap_free(have_installed);
+
+        set_free_free(remove_symlinks_to);
+
+        lookup_paths_free(&paths);
+
+        free(config_path);
+
+        return r;
+}
+
 static int systemctl_help(void) {
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -2925,20 +3624,25 @@ static int systemctl_help(void) {
                "  -t --type=TYPE     List only units of a particular type\n"
                "  -p --property=NAME Show only properties by this name\n"
                "  -a --all           Show all units/properties, including dead/empty ones\n"
-               "     --full          Don't ellipsize unit names.\n"
-               "     --fail          When installing a new job, fail if conflicting jobs are\n"
+               "     --full          Don't ellipsize unit names on output\n"
+               "     --fail          When queueing a new job, fail if conflicting jobs are\n"
                "                     pending\n"
+               "  -q --quiet         Suppress output\n"
+               "     --no-block      Do not wait until operation finished\n"
                "     --system        Connect to system bus\n"
                "     --session       Connect to session bus\n"
                "     --order         When generating graph for dot, show only order\n"
-               "     --require        When generating graph for dot, show only requirement\n"
-               "  -q --quiet         Suppress output\n"
-               "     --no-block      Do not wait until operation finished\n"
-               "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
+               "     --require       When generating graph for dot, show only requirement\n"
+               "     --no-wall       Don't send wall message before halt/power-off/reboot\n"
+               "     --global        Enable/disable unit files globally\n"
+               "     --no-reload     When enabling/disabling unit files, don't reload daemon\n"
+               "                     configuration\n"
+               "     --force         When enabling unit files, override existing symlinks\n"
+               "     --defaults      When disabling unit files, remove default symlinks only\n\n"
                "Commands:\n"
                "  list-units                      List units\n"
-               "  start [NAME...]                 Start one or more units\n"
-               "  stop [NAME...]                  Stop one or more units\n"
+               "  start [NAME...]                 Start (activate) one or more units\n"
+               "  stop [NAME...]                  Stop (deactivate) one or more units\n"
                "  reload [NAME...]                Reload one or more units\n"
                "  restart [NAME...]               Start or restart one or more units\n"
                "  try-restart [NAME...]           Restart one or more units if active\n"
@@ -2947,16 +3651,18 @@ static int systemctl_help(void) {
                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
                "                                  otherwise restart if active\n"
                "  isolate [NAME]                  Start one unit and stop all others\n"
-               "  check [NAME...]                 Check whether units are active\n"
-               "  status [NAME...]                Show status of one or more units\n"
+               "  is-active [NAME...]             Check whether units are active\n"
+               "  status [NAME...]                Show runtime status of one or more units\n"
                "  show [NAME...|JOB...]           Show properties of one or more\n"
-               "                                  units/jobs/manager\n"
-               "  reset-maintenance [NAME...]     Reset maintenance state for all, one\n"
+               "                                  units/jobs or the manager\n"
+               "  reset-maintenance [NAME...]     Reset maintenance state for all, one,\n"
                "                                  or more units\n"
+               "  enable [NAME...]                Enable one or more unit files\n"
+               "  disable [NAME...]               Disable one or more unit files\n"
+               "  is-enabled [NAME...]            Check whether unit files are enabled\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-jobs                       List jobs\n"
-               "  cancel [JOB...]                 Cancel one or more jobs\n"
-               "  clear-jobs                      Cancel all jobs\n"
+               "  cancel [JOB...]                 Cancel all, one, or more jobs\n"
                "  monitor                         Monitor unit/job changes\n"
                "  dump                            Dump server status\n"
                "  dot                             Dump dependency graph for dot(1)\n"
@@ -3050,28 +3756,36 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_FAIL = 0x100,
                 ARG_SESSION,
                 ARG_SYSTEM,
+                ARG_GLOBAL,
                 ARG_NO_BLOCK,
                 ARG_NO_WALL,
                 ARG_ORDER,
                 ARG_REQUIRE,
-                ARG_FULL
+                ARG_FULL,
+                ARG_FORCE,
+                ARG_NO_RELOAD,
+                ARG_DEFAULTS
         };
 
         static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'          },
-                { "type",      required_argument, NULL, 't'          },
-                { "property",  required_argument, NULL, 'p'          },
-                { "all",       no_argument,       NULL, 'a'          },
-                { "full",      no_argument,       NULL, ARG_FULL     },
-                { "fail",      no_argument,       NULL, ARG_FAIL     },
-                { "session",   no_argument,       NULL, ARG_SESSION  },
-                { "system",    no_argument,       NULL, ARG_SYSTEM   },
-                { "no-block",  no_argument,       NULL, ARG_NO_BLOCK },
-                { "no-wall",   no_argument,       NULL, ARG_NO_WALL  },
-                { "quiet",     no_argument,       NULL, 'q'          },
-                { "order",     no_argument,       NULL, ARG_ORDER    },
-                { "require",   no_argument,       NULL, ARG_REQUIRE  },
-                { NULL,        0,                 NULL, 0            }
+                { "help",      no_argument,       NULL, 'h'           },
+                { "type",      required_argument, NULL, 't'           },
+                { "property",  required_argument, NULL, 'p'           },
+                { "all",       no_argument,       NULL, 'a'           },
+                { "full",      no_argument,       NULL, ARG_FULL      },
+                { "fail",      no_argument,       NULL, ARG_FAIL      },
+                { "session",   no_argument,       NULL, ARG_SESSION   },
+                { "system",    no_argument,       NULL, ARG_SYSTEM    },
+                { "global",    no_argument,       NULL, ARG_GLOBAL    },
+                { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
+                { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
+                { "quiet",     no_argument,       NULL, 'q'           },
+                { "order",     no_argument,       NULL, ARG_ORDER     },
+                { "require",   no_argument,       NULL, ARG_REQUIRE   },
+                { "force",     no_argument,       NULL, ARG_FORCE     },
+                { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
+                { "defaults",   no_argument,      NULL, ARG_DEFAULTS  },
+                { NULL,        0,                 NULL, 0             }
         };
 
         int c;
@@ -3147,6 +3861,23 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_quiet = true;
                         break;
 
+                case ARG_FORCE:
+                        arg_force = true;
+                        break;
+
+                case ARG_NO_RELOAD:
+                        arg_no_reload = true;
+                        break;
+
+                case ARG_GLOBAL:
+                        arg_global = true;
+                        arg_session = true;
+                        break;
+
+                case ARG_DEFAULTS:
+                        arg_defaults = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -3638,7 +4369,7 @@ static int talk_initctl(void) {
         return 1;
 }
 
-static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
+static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
 
         static const struct {
                 const char* verb;
@@ -3650,42 +4381,46 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 const int argc;
                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
         } verbs[] = {
-                { "list-units",        LESS,  1, list_units      },
-                { "list-jobs",         EQUAL, 1, list_jobs       },
-                { "clear-jobs",        EQUAL, 1, clear_jobs      },
-                { "load",              MORE,  2, load_unit       },
-                { "cancel",            MORE,  2, cancel_job      },
-                { "start",             MORE,  2, start_unit      },
-                { "stop",              MORE,  2, start_unit      },
-                { "reload",            MORE,  2, start_unit      },
-                { "restart",           MORE,  2, start_unit      },
-                { "try-restart",       MORE,  2, start_unit      },
-                { "reload-or-restart", MORE,  2, start_unit      },
-                { "reload-or-try-restart", MORE, 2, start_unit   },
-                { "force-reload",      MORE,  2, start_unit      }, /* For compatibility with SysV */
-                { "condrestart",       MORE,  2, start_unit      }, /* For compatibility with RH */
-                { "isolate",           EQUAL, 2, start_unit      },
-                { "check",             MORE,  2, check_unit      },
-                { "show",              MORE,  1, show            },
-                { "status",            MORE,  2, show            },
-                { "monitor",           EQUAL, 1, monitor         },
-                { "dump",              EQUAL, 1, dump            },
-                { "dot",               EQUAL, 1, dot             },
-                { "snapshot",          LESS,  2, snapshot        },
-                { "delete",            MORE,  2, delete_snapshot },
-                { "daemon-reload",     EQUAL, 1, clear_jobs      },
-                { "daemon-reexec",     EQUAL, 1, clear_jobs      },
-                { "daemon-exit",       EQUAL, 1, clear_jobs      },
-                { "show-environment",  EQUAL, 1, show_enviroment },
-                { "set-environment",   MORE,  2, set_environment },
-                { "unset-environment", MORE,  2, set_environment },
-                { "halt",              EQUAL, 1, start_special   },
-                { "poweroff",          EQUAL, 1, start_special   },
-                { "reboot",            EQUAL, 1, start_special   },
-                { "default",           EQUAL, 1, start_special   },
-                { "rescue",            EQUAL, 1, start_special   },
-                { "emergency",         EQUAL, 1, start_special   },
-                { "reset-maintenance", MORE,  1, reset_maintenance },
+                { "list-units",            LESS,  1, list_units        },
+                { "list-jobs",             EQUAL, 1, list_jobs         },
+                { "clear-jobs",            EQUAL, 1, daemon_reload     },
+                { "load",                  MORE,  2, load_unit         },
+                { "cancel",                MORE,  2, cancel_job        },
+                { "start",                 MORE,  2, start_unit        },
+                { "stop",                  MORE,  2, start_unit        },
+                { "reload",                MORE,  2, start_unit        },
+                { "restart",               MORE,  2, start_unit        },
+                { "try-restart",           MORE,  2, start_unit        },
+                { "reload-or-restart",     MORE,  2, start_unit        },
+                { "reload-or-try-restart", MORE,  2, start_unit        },
+                { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
+                { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
+                { "isolate",               EQUAL, 2, start_unit        },
+                { "is-active",             MORE,  2, check_unit        },
+                { "check",                 MORE,  2, check_unit        },
+                { "show",                  MORE,  1, show              },
+                { "status",                MORE,  2, show              },
+                { "monitor",               EQUAL, 1, monitor           },
+                { "dump",                  EQUAL, 1, dump              },
+                { "dot",                   EQUAL, 1, dot               },
+                { "snapshot",              LESS,  2, snapshot          },
+                { "delete",                MORE,  2, delete_snapshot   },
+                { "daemon-reload",         EQUAL, 1, daemon_reload     },
+                { "daemon-reexec",         EQUAL, 1, daemon_reload     },
+                { "daemon-exit",           EQUAL, 1, daemon_reload     },
+                { "show-environment",      EQUAL, 1, show_enviroment   },
+                { "set-environment",       MORE,  2, set_environment   },
+                { "unset-environment",     MORE,  2, set_environment   },
+                { "halt",                  EQUAL, 1, start_special     },
+                { "poweroff",              EQUAL, 1, start_special     },
+                { "reboot",                EQUAL, 1, start_special     },
+                { "default",               EQUAL, 1, start_special     },
+                { "rescue",                EQUAL, 1, start_special     },
+                { "emergency",             EQUAL, 1, start_special     },
+                { "reset-maintenance",     MORE,  1, reset_maintenance },
+                { "enable",                MORE,  2, enable_unit       },
+                { "disable",               MORE,  2, enable_unit       },
+                { "is-enabled",            MORE,  2, enable_unit       }
         };
 
         int left;
@@ -3694,6 +4429,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
         assert(bus);
         assert(argc >= 0);
         assert(argv);
+        assert(error);
 
         left = argc - optind;
 
@@ -3746,6 +4482,15 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 assert_not_reached("Unknown comparison operator.");
         }
 
+        /* Require a bus connection for all operations but
+         * enable/disable */
+        if (!streq(verbs[i].verb, "enable") &&
+            !streq(verbs[i].verb, "disable") &&
+            !bus) {
+                log_error("Failed to get D-Bus connection: %s", error->message);
+                return -EIO;
+        }
+
         return verbs[i].dispatch(bus, argv + optind, left);
 }
 
@@ -3754,7 +4499,7 @@ static int reload_with_fallback(DBusConnection *bus) {
 
         if (bus) {
                 /* First, try systemd via D-Bus. */
-                if ((r = clear_jobs(bus, NULL, 0)) > 0)
+                if ((r = daemon_reload(bus, NULL, 0)) > 0)
                         return 0;
         }
 
@@ -3890,13 +4635,7 @@ int main(int argc, char*argv[]) {
         switch (arg_action) {
 
         case ACTION_SYSTEMCTL: {
-
-                if (!bus) {
-                        log_error("Failed to get D-Bus connection: %s", error.message);
-                        goto finish;
-                }
-
-                retval = systemctl_main(bus, argc, argv) < 0;
+                retval = systemctl_main(bus, argc, argv, &error) < 0;
                 break;
         }