[systemd-commits] 7 commits - Makefile.am man/systemctl.xml src/ask-password-agent.vala src/bus-errors.h src/dbus-manager.c src/dbus-service.c src/dbus-unit.c src/dbus-unit.h src/execute.c src/execute.h src/fsck.c src/gnome-ask-password-agent.vala src/load-fragment.c src/mount.c src/service.c src/socket.c src/swap.c src/systemctl.c src/unit.c src/unit.h src/util.c src/util.h TODO

Lennart Poettering lennart at kemper.freedesktop.org
Sat Oct 23 08:30:45 PDT 2010


 Makefile.am                       |   12 -
 TODO                              |    7 -
 man/systemctl.xml                 |  190 ++++++++++++++++++++++-----
 src/ask-password-agent.vala       |  258 --------------------------------------
 src/bus-errors.h                  |    1 
 src/dbus-manager.c                |   40 +++++
 src/dbus-service.c                |    1 
 src/dbus-unit.c                   |   28 ++++
 src/dbus-unit.h                   |    7 -
 src/execute.c                     |   19 ++
 src/execute.h                     |   14 ++
 src/fsck.c                        |    8 +
 src/gnome-ask-password-agent.vala |  258 ++++++++++++++++++++++++++++++++++++++
 src/load-fragment.c               |    6 
 src/mount.c                       |   49 +++++++
 src/service.c                     |   58 ++++++++
 src/socket.c                      |   48 +++++++
 src/swap.c                        |   49 +++++++
 src/systemctl.c                   |  140 +++++++++++++++++---
 src/unit.c                        |   25 ++-
 src/unit.h                        |    7 -
 src/util.c                        |   11 +
 src/util.h                        |    2 
 23 files changed, 889 insertions(+), 349 deletions(-)

New commits:
commit d674a4ab52b08dfa8d2221d903011ebf8ae2d11f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:38:14 2010 +0200

    ask-password: rename ask-password-agent to gnome-ask-password-agent

diff --git a/Makefile.am b/Makefile.am
index 5fcf24f..dcaf382 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -89,7 +89,7 @@ bin_PROGRAMS = \
 if HAVE_GTK
 bin_PROGRAMS += \
 	systemadm \
-	systemd-ask-password-agent
+	systemd-gnome-ask-password-agent
 endif
 
 rootlibexec_PROGRAMS = \
@@ -855,10 +855,10 @@ systemadm_LDADD = \
 	$(DBUSGLIB_LIBS) \
 	$(GTK_LIBS)
 
-systemd_ask_password_agent_SOURCES = \
-	src/ask-password-agent.vala
+systemd_gnome_ask_password_agent_SOURCES = \
+	src/gnome-ask-password-agent.vala
 
-systemd_ask_password_agent_CFLAGS = \
+systemd_gnome_ask_password_agent_CFLAGS = \
 	$(AM_CFLAGS) \
 	$(DBUSGLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
@@ -867,7 +867,7 @@ systemd_ask_password_agent_CFLAGS = \
 	-Wno-shadow \
 	-Wno-format-nonliteral
 
-systemd_ask_password_agent_VALAFLAGS = \
+systemd_gnome_ask_password_agent_VALAFLAGS = \
 	--pkg=dbus-glib-1 \
 	--pkg=posix \
 	--pkg=gtk+-2.0 \
@@ -876,7 +876,7 @@ systemd_ask_password_agent_VALAFLAGS = \
 	--pkg=libnotify \
 	-g
 
-systemd_ask_password_agent_LDADD = \
+systemd_gnome_ask_password_agent_LDADD = \
 	$(DBUSGLIB_LIBS) \
 	$(GTK_LIBS)
 
diff --git a/src/ask-password-agent.vala b/src/ask-password-agent.vala
deleted file mode 100644
index 1523e2e..0000000
--- a/src/ask-password-agent.vala
+++ /dev/null
@@ -1,258 +0,0 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-using Gtk;
-using GLib;
-using DBus;
-using Linux;
-using Posix;
-using Notify;
-
-[CCode (cheader_filename = "time.h")]
-extern int clock_gettime(int id, out timespec ts);
-
-public class PasswordDialog : Dialog {
-
-        public Entry entry;
-
-        public PasswordDialog(string message, string icon) {
-                set_title("System Password");
-                set_has_separator(false);
-                set_border_width(8);
-                set_default_response(ResponseType.OK);
-                set_icon_name(icon);
-
-                add_button(STOCK_CANCEL, ResponseType.CANCEL);
-                add_button(STOCK_OK, ResponseType.OK);
-
-                Container content = (Container) get_content_area();
-
-                Box hbox = new HBox(false, 16);
-                hbox.set_border_width(8);
-                content.add(hbox);
-
-                Image image = new Image.from_icon_name(icon, IconSize.DIALOG);
-                hbox.pack_start(image, false, false);
-
-                Box vbox = new VBox(false, 8);
-                hbox.pack_start(vbox, true, true);
-
-                Label label = new Label(message);
-                vbox.pack_start(label, false, false);
-
-                entry = new Entry();
-                entry.set_visibility(false);
-                entry.set_activates_default(true);
-                vbox.pack_start(entry, false, false);
-
-                entry.activate.connect(on_entry_activated);
-
-                show_all();
-        }
-
-        public void on_entry_activated() {
-                response(ResponseType.OK);
-        }
-}
-
-public class MyStatusIcon : StatusIcon {
-
-        File directory;
-        File current;
-        FileMonitor file_monitor;
-
-        string message;
-        string icon;
-        string socket;
-
-        PasswordDialog password_dialog;
-
-        public MyStatusIcon() throws GLib.Error {
-                GLib.Object(icon_name : "dialog-password");
-                set_title("System Password");
-
-                directory = File.new_for_path("/dev/.systemd/ask-password/");
-                file_monitor = directory.monitor_directory(0);
-                file_monitor.changed.connect(file_monitor_changed);
-
-                current = null;
-                look_for_password();
-
-                activate.connect(status_icon_activate);
-        }
-
-        void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) throws GLib.Error {
-
-                if (!file.get_basename().has_prefix("ask."))
-                        return;
-
-                if (event_type == FileMonitorEvent.CREATED ||
-                    event_type == FileMonitorEvent.DELETED)
-                        look_for_password();
-        }
-
-        void look_for_password() throws GLib.Error {
-
-                if (current != null) {
-                        if (!current.query_exists()) {
-                                current = null;
-                                if (password_dialog != null)
-                                        password_dialog.response(ResponseType.REJECT);
-                        }
-                }
-
-                if (current == null) {
-                        FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
-
-                        FileInfo i;
-                        while ((i = enumerator.next_file()) != null) {
-                                if (!i.get_name().has_prefix("ask."))
-                                        continue;
-
-                                current = directory.get_child(i.get_name());
-
-                                if (load_password())
-                                        break;
-
-                                current = null;
-                        }
-                }
-
-                if (current == null)
-                        set_visible(false);
-
-        }
-
-        bool load_password() throws GLib.Error {
-
-                KeyFile key_file = new KeyFile();
-
-                try {
-                        timespec ts;
-
-                        key_file.load_from_file(current.get_path(), KeyFileFlags.NONE);
-
-                        string not_after_as_string = key_file.get_string("Ask", "NotAfter");
-
-                        clock_gettime(1, out ts);
-                        uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
-
-                        uint64 not_after;
-                        if (not_after_as_string.scanf("%llu", out not_after) != 1)
-                                return false;
-
-                        if (not_after < now)
-                                return false;
-
-                        socket = key_file.get_string("Ask", "Socket");
-                } catch (GLib.Error e) {
-                        return false;
-                }
-
-                try {
-                        message = key_file.get_string("Ask", "Message").compress();
-                } catch (GLib.Error e) {
-                        message = "Please Enter System Password!";
-                }
-                set_tooltip_text(message);
-
-                try {
-                        icon = key_file.get_string("Ask", "Icon");
-                } catch (GLib.Error e) {
-                        icon = "dialog-password";
-                }
-                set_from_icon_name(icon);
-
-                set_visible(true);
-
-                Notification n = new Notification(title, message, icon, null);
-                n.attach_to_status_icon(this);
-                n.set_timeout(5000);
-                n.show();
-
-                return true;
-        }
-
-        void status_icon_activate() throws GLib.Error {
-
-                if (current == null)
-                        return;
-
-                if (password_dialog != null) {
-                        password_dialog.present();
-                        return;
-                }
-
-                password_dialog = new PasswordDialog(message, icon);
-
-                int result = password_dialog.run();
-                string password = password_dialog.entry.get_text();
-
-                password_dialog.destroy();
-                password_dialog = null;
-
-                if (result == ResponseType.REJECT ||
-                    result == ResponseType.DELETE_EVENT)
-                        return;
-
-                int to_process;
-
-                Process.spawn_async_with_pipes(
-                                null,
-                                { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket },
-                                null,
-                                0,
-                                null,
-                                null,
-                                out to_process,
-                                null,
-                                null);
-
-                OutputStream stream = new UnixOutputStream(to_process, true);
-
-                stream.write(password, password.length, null);
-        }
-}
-
-static const OptionEntry entries[] = {
-        { null }
-};
-
-void show_error(string e) {
-        var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
-        m.run();
-        m.destroy();
-}
-
-int main(string[] args) {
-        try {
-                Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent");
-                Notify.init("Password Agent");
-
-                MyStatusIcon i = new MyStatusIcon();
-                Gtk.main();
-
-        } catch (DBus.Error e) {
-                show_error(e.message);
-        } catch (GLib.Error e) {
-                show_error(e.message);
-        }
-
-        return 0;
-}
diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala
new file mode 100644
index 0000000..1523e2e
--- /dev/null
+++ b/src/gnome-ask-password-agent.vala
@@ -0,0 +1,258 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+using Gtk;
+using GLib;
+using DBus;
+using Linux;
+using Posix;
+using Notify;
+
+[CCode (cheader_filename = "time.h")]
+extern int clock_gettime(int id, out timespec ts);
+
+public class PasswordDialog : Dialog {
+
+        public Entry entry;
+
+        public PasswordDialog(string message, string icon) {
+                set_title("System Password");
+                set_has_separator(false);
+                set_border_width(8);
+                set_default_response(ResponseType.OK);
+                set_icon_name(icon);
+
+                add_button(STOCK_CANCEL, ResponseType.CANCEL);
+                add_button(STOCK_OK, ResponseType.OK);
+
+                Container content = (Container) get_content_area();
+
+                Box hbox = new HBox(false, 16);
+                hbox.set_border_width(8);
+                content.add(hbox);
+
+                Image image = new Image.from_icon_name(icon, IconSize.DIALOG);
+                hbox.pack_start(image, false, false);
+
+                Box vbox = new VBox(false, 8);
+                hbox.pack_start(vbox, true, true);
+
+                Label label = new Label(message);
+                vbox.pack_start(label, false, false);
+
+                entry = new Entry();
+                entry.set_visibility(false);
+                entry.set_activates_default(true);
+                vbox.pack_start(entry, false, false);
+
+                entry.activate.connect(on_entry_activated);
+
+                show_all();
+        }
+
+        public void on_entry_activated() {
+                response(ResponseType.OK);
+        }
+}
+
+public class MyStatusIcon : StatusIcon {
+
+        File directory;
+        File current;
+        FileMonitor file_monitor;
+
+        string message;
+        string icon;
+        string socket;
+
+        PasswordDialog password_dialog;
+
+        public MyStatusIcon() throws GLib.Error {
+                GLib.Object(icon_name : "dialog-password");
+                set_title("System Password");
+
+                directory = File.new_for_path("/dev/.systemd/ask-password/");
+                file_monitor = directory.monitor_directory(0);
+                file_monitor.changed.connect(file_monitor_changed);
+
+                current = null;
+                look_for_password();
+
+                activate.connect(status_icon_activate);
+        }
+
+        void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) throws GLib.Error {
+
+                if (!file.get_basename().has_prefix("ask."))
+                        return;
+
+                if (event_type == FileMonitorEvent.CREATED ||
+                    event_type == FileMonitorEvent.DELETED)
+                        look_for_password();
+        }
+
+        void look_for_password() throws GLib.Error {
+
+                if (current != null) {
+                        if (!current.query_exists()) {
+                                current = null;
+                                if (password_dialog != null)
+                                        password_dialog.response(ResponseType.REJECT);
+                        }
+                }
+
+                if (current == null) {
+                        FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+                        FileInfo i;
+                        while ((i = enumerator.next_file()) != null) {
+                                if (!i.get_name().has_prefix("ask."))
+                                        continue;
+
+                                current = directory.get_child(i.get_name());
+
+                                if (load_password())
+                                        break;
+
+                                current = null;
+                        }
+                }
+
+                if (current == null)
+                        set_visible(false);
+
+        }
+
+        bool load_password() throws GLib.Error {
+
+                KeyFile key_file = new KeyFile();
+
+                try {
+                        timespec ts;
+
+                        key_file.load_from_file(current.get_path(), KeyFileFlags.NONE);
+
+                        string not_after_as_string = key_file.get_string("Ask", "NotAfter");
+
+                        clock_gettime(1, out ts);
+                        uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
+
+                        uint64 not_after;
+                        if (not_after_as_string.scanf("%llu", out not_after) != 1)
+                                return false;
+
+                        if (not_after < now)
+                                return false;
+
+                        socket = key_file.get_string("Ask", "Socket");
+                } catch (GLib.Error e) {
+                        return false;
+                }
+
+                try {
+                        message = key_file.get_string("Ask", "Message").compress();
+                } catch (GLib.Error e) {
+                        message = "Please Enter System Password!";
+                }
+                set_tooltip_text(message);
+
+                try {
+                        icon = key_file.get_string("Ask", "Icon");
+                } catch (GLib.Error e) {
+                        icon = "dialog-password";
+                }
+                set_from_icon_name(icon);
+
+                set_visible(true);
+
+                Notification n = new Notification(title, message, icon, null);
+                n.attach_to_status_icon(this);
+                n.set_timeout(5000);
+                n.show();
+
+                return true;
+        }
+
+        void status_icon_activate() throws GLib.Error {
+
+                if (current == null)
+                        return;
+
+                if (password_dialog != null) {
+                        password_dialog.present();
+                        return;
+                }
+
+                password_dialog = new PasswordDialog(message, icon);
+
+                int result = password_dialog.run();
+                string password = password_dialog.entry.get_text();
+
+                password_dialog.destroy();
+                password_dialog = null;
+
+                if (result == ResponseType.REJECT ||
+                    result == ResponseType.DELETE_EVENT)
+                        return;
+
+                int to_process;
+
+                Process.spawn_async_with_pipes(
+                                null,
+                                { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket },
+                                null,
+                                0,
+                                null,
+                                null,
+                                out to_process,
+                                null,
+                                null);
+
+                OutputStream stream = new UnixOutputStream(to_process, true);
+
+                stream.write(password, password.length, null);
+        }
+}
+
+static const OptionEntry entries[] = {
+        { null }
+};
+
+void show_error(string e) {
+        var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
+        m.run();
+        m.destroy();
+}
+
+int main(string[] args) {
+        try {
+                Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent");
+                Notify.init("Password Agent");
+
+                MyStatusIcon i = new MyStatusIcon();
+                Gtk.main();
+
+        } catch (DBus.Error e) {
+                show_error(e.message);
+        } catch (GLib.Error e) {
+                show_error(e.message);
+        }
+
+        return 0;
+}

commit b568b917b002425e28ff8009f4c1d4f35a8b03e3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:34:10 2010 +0200

    update fixme

diff --git a/TODO b/TODO
index 899c986..e898e5b 100644
--- a/TODO
+++ b/TODO
@@ -7,9 +7,6 @@
 
 * implicitly import "defaults" settings file into all types
 
-* ability to kill services? i.e. in contrast to stopping them, go directly
-  into killing mode?
-
 * port over to LISTEN_FDS/LISTEN_PID:
    - uuidd    DONE
    - dbus     DONE
@@ -54,8 +51,6 @@
 
 * systemctl auto-pager a la git
 
-* fsck setup: quota flag, check kcmdline/forcefsck, reboot, single user, ac plug
-
 * merge CK
 
 * ask-password tty agent, ask-password plymouth agent
@@ -66,8 +61,6 @@
 
 * document locale.conf, vconsole.conf and possibly the tempfiles.d and modules-load.d mechanism.
 
-* enable syslog.socket by default, activating our kmsg bridge
-
 * when processes remain in a service even though the start command failed enter active
 
 * fix plymouth socket, when plymouth started to use a clean one

commit 59cddb23385b583ae8a9db9d2b10e211ab48495e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:32:29 2010 +0200

    man: numerous updates to document updated systemctl behaviour

diff --git a/man/systemctl.xml b/man/systemctl.xml
index 2fa4488..cdf4f5c 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -77,6 +77,13 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--version</option></term>
+
+                                <listitem><para>Prints a short version
+                                string and exits.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><option>--type=</option></term>
                                 <term><option>-t</option></term>
 
@@ -782,16 +789,6 @@
                                 accessible.</para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><command>daemon-exit</command></term>
-
-                                <listitem><para>Ask the systemd
-                                manager to quit. This is only
-                                supported for session managers
-                                (i.e. in conjunction with the
-                                <option>--session</option> option) and
-                                will fail otherwise.</para></listitem>
-                        </varlistentry>
-                        <varlistentry>
                                 <term><command>show-environment</command></term>
 
                                 <listitem><para>Dump the systemd
@@ -823,7 +820,34 @@
                                 is only removed if it has the
                                 specified value.</para></listitem>
                         </varlistentry>
+                        <varlistentry>
+                                <term><command>default</command></term>
+
+                                <listitem><para>Enter default
+                                mode. This is mostly equivalent to
+                                <command>start
+                                default.target</command>.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><command>rescue</command></term>
+
+                                <listitem><para>Enter rescue
+                                mode. This is mostly equivalent to
+                                <command>isolate
+                                rescue.target</command> but also
+                                prints a wall message to all
+                                users.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><command>emergency</command></term>
 
+                                <listitem><para>Enter emergency
+                                mode. This is mostly equivalent to
+                                <command>isolate
+                                emergency.target</command> but also
+                                prints a wall message to all
+                                users.</para></listitem>
+                        </varlistentry>
                         <varlistentry>
                                 <term><command>halt</command></term>
 
@@ -831,7 +855,14 @@
                                 system. This is mostly equivalent to
                                 <command>start halt.target</command>
                                 but also prints a wall message to all
-                                users.</para></listitem>
+                                users.  If
+                                combined with <option>--force</option>
+                                shutdown of all running services is
+                                skipped, however all processes killed
+                                and all file systems unmounted or
+                                mounted read-only, immediately
+                                followed by the
+                                system halt.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>poweroff</command></term>
@@ -841,7 +872,14 @@
                                 equivalent to <command>start
                                 poweroff.target</command> but also
                                 prints a wall message to all
-                                users.</para></listitem>
+                                users. If
+                                combined with <option>--force</option>
+                                shutdown of all running services is
+                                skipped, however all processes killed
+                                and all file systems unmounted or
+                                mounted read-only, immediately
+                                followed by the
+                                powering off.</para></listitem>
                         </varlistentry>
                         <varlistentry>
                                 <term><command>reboot</command></term>
@@ -851,35 +889,40 @@
                                 equivalent to <command>start
                                 reboot.target</command> but also
                                 prints a wall message to all
-                                users.</para></listitem>
-                        </varlistentry>
-                        <varlistentry>
-                                <term><command>default</command></term>
-
-                                <listitem><para>Enter default
-                                mode. This is mostly equivalent to
-                                <command>start
-                                default.target</command>.</para></listitem>
+                                users. If
+                                combined with <option>--force</option>
+                                shutdown of all running services is
+                                skipped, however all processes killed
+                                and all file systems unmounted or
+                                mounted read-only, immediately
+                                followed by the
+                                reboot.</para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><command>rescue</command></term>
+                                <term><command>kexec</command></term>
 
-                                <listitem><para>Enter rescue
-                                mode. This is mostly equivalent to
-                                <command>isolate
-                                rescue.target</command> but also
-                                prints a wall message to all
-                                users.</para></listitem>
+                                <listitem><para>Shut down and reboot
+                                the system via kexec. This is mostly
+                                equivalent to <command>start
+                                kexec.target</command> but also prints
+                                a wall message to all users. If
+                                combined with <option>--force</option>
+                                shutdown of all running services is
+                                skipped, however all processes killed
+                                and all file systems unmounted or
+                                mounted read-only, immediately
+                                followed by the
+                                reboot.</para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><command>emergency</command></term>
+                                <term><command>exit</command></term>
 
-                                <listitem><para>Enter emergency
-                                mode. This is mostly equivalent to
-                                <command>isolate
-                                emergency.target</command> but also
-                                prints a wall message to all
-                                users.</para></listitem>
+                                <listitem><para>Ask the systemd
+                                manager to quit. This is only
+                                supported for session managers
+                                (i.e. in conjunction with the
+                                <option>--session</option> option) and
+                                will fail otherwise.</para></listitem>
                         </varlistentry>
                 </variablelist>
 

commit ef1de59b5e1d509cf3c619bd2c4975009aba1dd6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:12:56 2010 +0200

    fsck: suppress error message if we cannot change into single user mode since we are already passt early bootup

diff --git a/src/fsck.c b/src/fsck.c
index fe56be7..96dea66 100644
--- a/src/fsck.c
+++ b/src/fsck.c
@@ -31,6 +31,7 @@
 #include "util.h"
 #include "dbus-common.h"
 #include "special.h"
+#include "bus-errors.h"
 
 static bool arg_skip = false;
 static bool arg_force = false;
@@ -74,7 +75,12 @@ static void start_target(const char *target, bool isolate) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to start unit: %s", bus_error_message(&error));
+
+                /* Don't print a waring if we aren't called during
+                 * startup */
+                if (!dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB))
+                        log_error("Failed to start unit: %s", bus_error_message(&error));
+
                 goto finish;
         }
 

commit 288c783a9d9ab6ff1e11332fd3066f7a2a9c4912
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:12:26 2010 +0200

    dbus: epose FsckPassNo property for service objects

diff --git a/src/dbus-service.c b/src/dbus-service.c
index ad3264c..a79f769 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -140,6 +140,7 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
                 { "org.freedesktop.systemd1.Service", "SysVRunLevels",          bus_property_append_string, "s", u->service.sysv_runlevels             },
                 { "org.freedesktop.systemd1.Service", "SysVStartPriority",      bus_property_append_int,    "i", &u->service.sysv_start_priority       },
 #endif
+                { "org.freedesktop.systemd1.Service", "FsckPassNo",             bus_property_append_int,    "i", &u->service.fsck_passno               },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 

commit 6f3525444e177e8413d46c5029a7dced7fb4818d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:12:05 2010 +0200

    man: document systemctl --force

diff --git a/man/systemctl.xml b/man/systemctl.xml
index ca654ca..2fa4488 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -287,11 +287,25 @@
 
                         <varlistentry>
                                 <term><option>--force</option></term>
+                                <term><option>-f</option></term>
 
                                 <listitem><para>When used with
                                 <command>enable</command>, override any
                                 existing conflicting
                                 symlinks.</para></listitem>
+
+                                <listitem><para>When used with
+                                <command>halt</command>,
+                                <command>poweroff</command>,
+                                <command>reboot</command> or
+                                <command>kexec</command> execute
+                                selected operation without shutting
+                                down all units. However, all processes
+                                will be killed forcibly and all file
+                                systems are unmounted or remounted
+                                read-only. This is hence a drastic but
+                                relatively safe option to request an
+                                immediate reboot.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>

commit 8a0867d6c5b47c8697d1ddd815116a548433c718
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Oct 22 16:11:50 2010 +0200

    systemctl: introduce systemctl kill

diff --git a/man/systemctl.xml b/man/systemctl.xml
index 2eb153e..ca654ca 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -235,6 +235,57 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--kill-mode=</option></term>
+
+                                <listitem><para>When used with
+                                <command>kill</command>, choose the
+                                mode how to kill the selected
+                                processes. Must be one of
+                                <option>control-group</option>,
+                                <option>process-group</option> or
+                                <option>process</option> to select
+                                whether to kill the entire control
+                                group, the process group or only the
+                                selected process itself. If ommitted
+                                defaults to
+                                <option>control-group</option> if
+                                <option>--kill-who=all</option> is
+                                set, or <option>process</option>
+                                otherwise. You probably never need to
+                                use this switch.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--kill-who=</option></term>
+
+                                <listitem><para>When used with
+                                <command>kill</command>, choose which
+                                processes to kill. Must be one of
+                                <option>main</option>,
+                                <option>control</option> or
+                                <option>all</option> to select whether
+                                to kill only the main process of the
+                                unit, the control process or all
+                                processes of the unit. If ommitted
+                                defaults to
+                                <option>all</option>.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>---signal=</option></term>
+                                <term><option>-s</option></term>
+
+                                <listitem><para>When used with
+                                <command>kill</command>, choose which
+                                signal to send to selected
+                                processes. Must be one of the well
+                                know signal specifiers such as
+                                SIGTERM, SIGINT or SIGSTOP. If
+                                ommitted defaults to
+                                <option>SIGTERM</option>.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><option>--force</option></term>
 
                                 <listitem><para>When used with
@@ -359,6 +410,18 @@
                                 for details.</para></listitem>
                         </varlistentry>
                         <varlistentry>
+                                <term><command>kill [NAME...]</command></term>
+
+                                <listitem><para>Send a signal to one
+                                or more processes of the unit. Use
+                                <option>--kill-who=</option> to select
+                                which process to kill. Use
+                                <option>--kill-mode=</option> to
+                                select the kill mode and
+                                <option>--signal=</option> to select
+                                the signal to send.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
                                 <term><command>is-active [NAME...]</command></term>
 
                                 <listitem><para>Check whether any of
diff --git a/src/bus-errors.h b/src/bus-errors.h
index d6ccd74..82d4e99 100644
--- a/src/bus-errors.h
+++ b/src/bus-errors.h
@@ -43,6 +43,7 @@
 #define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting"
 #define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
 #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
+#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess"
 
 static inline const char *bus_error(const DBusError *e, int r) {
         if (e && e->message)
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 5263843..c195031 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -84,6 +84,12 @@
         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
         "  </method>\n"                                                 \
+        "  <method name=\"KillUnit\">\n"                                \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
+        "  </method>\n"                                                 \
         "  <method name=\"ResetFailedUnit\">\n"                         \
         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
         "  </method>\n"                                                 \
@@ -430,6 +436,40 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
                 reload_if_possible = true;
                 job_type = JOB_TRY_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
+                const char *name, *swho, *smode;
+                int32_t signo;
+                Unit *u;
+                KillMode mode;
+                KillWho who;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_STRING, &swho,
+                                    DBUS_TYPE_STRING, &smode,
+                                    DBUS_TYPE_INT32, &signo,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, connection, message, &error, -EINVAL);
+
+                if ((mode = kill_mode_from_string(smode)) < 0 ||
+                    (who = kill_who_from_string(swho)) < 0 ||
+                    signo <= 0 ||
+                    signo >= _NSIG)
+                        return bus_send_error_reply(m, connection, message, &error, -EINVAL);
+
+                if (!(u = manager_get_unit(m, name))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+                        return bus_send_error_reply(m, connection, message, &error, -ENOENT);
+                }
+
+                if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
+                        return bus_send_error_reply(m, connection, message, &error, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
                 uint32_t id;
                 Job *j;
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index 45eba8a..47aa8d3 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -367,6 +367,34 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
                 reload_if_possible = true;
                 job_type = JOB_TRY_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) {
+                const char *swho, *smode;
+                int32_t signo;
+                KillMode mode;
+                KillWho who;
+                int r;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &swho,
+                                    DBUS_TYPE_STRING, &smode,
+                                    DBUS_TYPE_INT32, &signo,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, connection, message, &error, -EINVAL);
+
+                if ((mode = kill_mode_from_string(smode)) < 0 ||
+                    (who = kill_who_from_string(swho)) < 0 ||
+                    signo <= 0 ||
+                    signo >= _NSIG)
+                        return bus_send_error_reply(m, connection, message, &error, -EINVAL);
+
+                if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
+                        return bus_send_error_reply(m, connection, message, &error, r);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) {
 
                 unit_reset_failed(u);
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
index 800498b..94e084f 100644
--- a/src/dbus-unit.h
+++ b/src/dbus-unit.h
@@ -56,7 +56,12 @@
         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
         "  </method>\n"                                                 \
-        "  <method name=\"ResetFailed\"/>\n"                       \
+        "  <method name=\"Kill\">\n"                                    \
+        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"ResetFailed\"/>\n"                            \
         "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
         "  <property name=\"Names\" type=\"as\" access=\"read\"/>\n"    \
         "  <property name=\"Following\" type=\"s\" access=\"read\"/>\n" \
diff --git a/src/execute.c b/src/execute.c
index b5afa68..48e55ea 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -1797,6 +1797,8 @@ static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
         [EXEC_INPUT_SOCKET] = "socket"
 };
 
+DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+
 static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
         [EXEC_OUTPUT_INHERIT] = "inherit",
         [EXEC_OUTPUT_NULL] = "null",
@@ -1808,4 +1810,19 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
 
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+static const char* const kill_mode_table[_KILL_MODE_MAX] = {
+        [KILL_CONTROL_GROUP] = "control-group",
+        [KILL_PROCESS_GROUP] = "process-group",
+        [KILL_PROCESS] = "process",
+        [KILL_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
+
+static const char* const kill_who_table[_KILL_WHO_MAX] = {
+        [KILL_MAIN] = "main",
+        [KILL_CONTROL] = "control",
+        [KILL_ALL] = "all"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/execute.h b/src/execute.h
index ed61e3c..dd84c3d 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -55,6 +55,14 @@ typedef enum KillMode {
         _KILL_MODE_INVALID = -1
 } KillMode;
 
+typedef enum KillWho {
+        KILL_MAIN,
+        KILL_CONTROL,
+        KILL_ALL,
+        _KILL_WHO_MAX,
+        _KILL_WHO_INVALID = -1
+} KillWho;
+
 typedef enum ExecInput {
         EXEC_INPUT_NULL,
         EXEC_INPUT_TTY,
@@ -202,4 +210,10 @@ int exec_output_from_string(const char *s);
 const char* exec_input_to_string(ExecInput i);
 int exec_input_from_string(const char *s);
 
+const char *kill_mode_to_string(KillMode k);
+KillMode kill_mode_from_string(const char *s);
+
+const char *kill_who_to_string(KillWho k);
+KillWho kill_who_from_string(const char *s);
+
 #endif
diff --git a/src/load-fragment.c b/src/load-fragment.c
index 0502fc4..74fe786 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1047,11 +1047,7 @@ static int config_parse_kill_signal(
         assert(rvalue);
         assert(sig);
 
-        if ((r = signal_from_string(rvalue)) <= 0)
-                if (startswith(rvalue, "SIG"))
-                        r = signal_from_string(rvalue+3);
-
-        if (r <= 0) {
+        if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
                 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
                 return 0;
         }
diff --git a/src/mount.c b/src/mount.c
index bbc29d8..3fc0f13 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -35,6 +35,7 @@
 #include "unit-name.h"
 #include "dbus-mount.h"
 #include "special.h"
+#include "bus-errors.h"
 
 static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
         [MOUNT_DEAD] = UNIT_INACTIVE,
@@ -1636,6 +1637,52 @@ static void mount_reset_failed(Unit *u) {
         m->failure = false;
 }
 
+static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Mount *m = MOUNT(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(m);
+
+        if (who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes");
+                return -EINVAL;
+        }
+
+        if (m->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ENOENT;
+        }
+
+        if (m->control_pid > 0)
+                if (kill(mode == KILL_PROCESS_GROUP ? -m->control_pid : m->control_pid, signo) < 0)
+                        r = -errno;
+
+        if (mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control pid from being killed via the cgroup */
+                if (m->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(m->meta.cgroup_bondings, signo, pid_set)) < 0)
+                        if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
 static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
         [MOUNT_DEAD] = "dead",
         [MOUNT_MOUNTING] = "mounting",
@@ -1682,6 +1729,8 @@ const UnitVTable mount_vtable = {
         .stop = mount_stop,
         .reload = mount_reload,
 
+        .kill = mount_kill,
+
         .serialize = mount_serialize,
         .deserialize_item = mount_deserialize_item,
 
diff --git a/src/service.c b/src/service.c
index 3ebe60e..6d6c540 100644
--- a/src/service.c
+++ b/src/service.c
@@ -3145,6 +3145,62 @@ static void service_reset_failed(Unit *u) {
         s->failure = false;
 }
 
+static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Service *s = SERVICE(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (s->main_pid <= 0 && who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
+                return -EINVAL;
+        }
+
+        if (s->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ENOENT;
+        }
+
+        if (s->control_pid > 0)
+                if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+                        r = -errno;
+
+        if (s->main_pid > 0)
+                if (kill(mode == KILL_PROCESS_GROUP ? -s->main_pid : s->main_pid, signo) < 0)
+                        r = -errno;
+
+        if (mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control/main pid from being killed via the cgroup */
+                if (s->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if (s->main_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, pid_set)) < 0)
+                        if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
 static const char* const service_state_table[_SERVICE_STATE_MAX] = {
         [SERVICE_DEAD] = "dead",
         [SERVICE_START_PRE] = "start-pre",
@@ -3222,6 +3278,8 @@ const UnitVTable service_vtable = {
 
         .can_reload = service_can_reload,
 
+        .kill = service_kill,
+
         .serialize = service_serialize,
         .deserialize_item = service_deserialize_item,
 
diff --git a/src/socket.c b/src/socket.c
index fc6088c..e8c016c 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -1784,6 +1784,52 @@ static void socket_reset_failed(Unit *u) {
         s->failure = false;
 }
 
+static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Socket *s = SOCKET(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Socket units have no main processes");
+                return -EINVAL;
+        }
+
+        if (s->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ENOENT;
+        }
+
+        if (s->control_pid > 0)
+                if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+                        r = -errno;
+
+        if (mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control pid from being killed via the cgroup */
+                if (s->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, pid_set)) < 0)
+                        if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
 static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
         [SOCKET_DEAD] = "dead",
         [SOCKET_START_PRE] = "start-pre",
@@ -1817,6 +1863,8 @@ const UnitVTable socket_vtable = {
         .done = socket_done,
         .load = socket_load,
 
+        .kill = socket_kill,
+
         .coldplug = socket_coldplug,
 
         .dump = socket_dump,
diff --git a/src/swap.c b/src/swap.c
index cf9644f..f7f9530 100644
--- a/src/swap.c
+++ b/src/swap.c
@@ -35,6 +35,7 @@
 #include "unit-name.h"
 #include "dbus-swap.h"
 #include "special.h"
+#include "bus-errors.h"
 
 static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
         [SWAP_DEAD] = UNIT_INACTIVE,
@@ -1213,6 +1214,52 @@ static void swap_reset_failed(Unit *u) {
         s->failure = false;
 }
 
+static int swap_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+        Swap *s = SWAP(u);
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (who == KILL_MAIN) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Swap units have no main processes");
+                return -EINVAL;
+        }
+
+        if (s->control_pid <= 0 && who == KILL_CONTROL) {
+                dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                return -ENOENT;
+        }
+
+        if (s->control_pid > 0)
+                if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+                        r = -errno;
+
+        if (mode == KILL_CONTROL_GROUP) {
+                int q;
+
+                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+                /* Exclude the control pid from being killed via the cgroup */
+                if (s->control_pid > 0)
+                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                                r = q;
+                                goto finish;
+                        }
+
+                if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, pid_set)) < 0)
+                        if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+                                r = q;
+        }
+
+finish:
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
 static const char* const swap_state_table[_SWAP_STATE_MAX] = {
         [SWAP_DEAD] = "dead",
         [SWAP_ACTIVATING] = "activating",
@@ -1253,6 +1300,8 @@ const UnitVTable swap_vtable = {
         .start = swap_start,
         .stop = swap_stop,
 
+        .kill = swap_kill,
+
         .serialize = swap_serialize,
         .deserialize_item = swap_deserialize_item,
 
diff --git a/src/systemctl.c b/src/systemctl.c
index a037690..ffbe4db 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -74,6 +74,9 @@ static bool arg_full = false;
 static bool arg_force = false;
 static bool arg_defaults = false;
 static char **arg_wall = NULL;
+static const char *arg_kill_who = NULL;
+static const char *arg_kill_mode = NULL;
+static int arg_signal = SIGTERM;
 static usec_t arg_when = 0;
 static enum action {
         ACTION_INVALID,
@@ -1408,6 +1411,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
                                 puts("unknown");
 
                         dbus_error_free(&error);
+                        dbus_message_unref(m);
                         continue;
                 }
 
@@ -1486,6 +1490,71 @@ finish:
         return r;
 }
 
+static int kill_unit(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        int r = 0;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        if (!arg_kill_who)
+                arg_kill_who = "all";
+
+        if (!arg_kill_mode)
+                arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
+
+        for (i = 1; i < n; i++) {
+
+                if (!(m = dbus_message_new_method_call(
+                                      "org.freedesktop.systemd1",
+                                      "/org/freedesktop/systemd1",
+                                      "org.freedesktop.systemd1.Manager",
+                                      "KillUnit"))) {
+                        log_error("Could not allocate message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &args[i],
+                                              DBUS_TYPE_STRING, &arg_kill_who,
+                                              DBUS_TYPE_STRING, &arg_kill_mode,
+                                              DBUS_TYPE_INT32, &arg_signal,
+                                              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))) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        dbus_error_free(&error);
+                        r = -EIO;
+                }
+
+                dbus_message_unref(m);
+
+                if (reply)
+                        dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
 typedef struct ExecStatusInfo {
         char *path;
         char **argv;
@@ -3923,27 +3992,30 @@ static int systemctl_help(void) {
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to or query the systemd manager.\n\n"
-               "  -h --help          Show this help\n"
-               "     --version       Show package version\n"
-               "  -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 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"
-               "     --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"
-               "  -f --force         When enabling unit files, override existing symlinks\n"
-               "                     When shutting down, execute action immediately\n"
-               "     --defaults      When disabling unit files, remove default symlinks only\n\n"
+               "  -h --help           Show this help\n"
+               "     --version        Show package version\n"
+               "  -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 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"
+               "     --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"
+               "     --kill-mode=MODE How to send signal\n"
+               "     --kill-who=WHO   Who to send signal to\n"
+               "  -s --signal=SIGNAL  Which signal to send\n"
+               "  -f --force          When enabling unit files, override existing symlinks\n"
+               "                      When shutting down, execute action immediately\n"
+               "     --defaults       When disabling unit files, remove default symlinks only\n\n"
                "Commands:\n"
                "  list-units                      List units\n"
                "  start [NAME...]                 Start (activate) one or more units\n"
@@ -3956,6 +4028,7 @@ 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"
+               "  kill [NAME...]                  Send signal to processes of a unit\n"
                "  is-active [NAME...]             Check whether units are active\n"
                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
                "  show [NAME...|JOB...]           Show properties of one or more\n"
@@ -4071,7 +4144,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_REQUIRE,
                 ARG_FULL,
                 ARG_NO_RELOAD,
-                ARG_DEFAULTS
+                ARG_DEFAULTS,
+                ARG_KILL_MODE,
+                ARG_KILL_WHO
         };
 
         static const struct option options[] = {
@@ -4093,6 +4168,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "force",     no_argument,       NULL, 'f'           },
                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
                 { "defaults",  no_argument,       NULL, ARG_DEFAULTS  },
+                { "kill-mode", required_argument, NULL, ARG_KILL_MODE },
+                { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
+                { "signal",    required_argument, NULL, 's'           },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -4101,7 +4179,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "ht:p:aqf", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -4192,6 +4270,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_defaults = true;
                         break;
 
+                case ARG_KILL_WHO:
+                        arg_kill_who = optarg;
+                        break;
+
+                case ARG_KILL_MODE:
+                        arg_kill_mode = optarg;
+                        break;
+
+                case 's':
+                        if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
+                                log_error("Failed to parse signal string %s.", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -4785,6 +4878,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
                 { "isolate",               EQUAL, 2, start_unit        },
+                { "kill",                  MORE,  2, kill_unit         },
                 { "is-active",             MORE,  2, check_unit        },
                 { "check",                 MORE,  2, check_unit        },
                 { "show",                  MORE,  1, show              },
diff --git a/src/unit.c b/src/unit.c
index ab6eb20..d2f6080 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -2252,6 +2252,22 @@ bool unit_name_is_valid(const char *n, bool template_ok) {
         return unit_name_is_valid_no_type(n, template_ok);
 }
 
+int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error) {
+        assert(u);
+        assert(w >= 0 && w < _KILL_WHO_MAX);
+        assert(m >= 0 && m < _KILL_MODE_MAX);
+        assert(signo > 0);
+        assert(signo < _NSIG);
+
+        if (m == KILL_NONE)
+                return 0;
+
+        if (!UNIT_VTABLE(u)->kill)
+                return -ENOTSUP;
+
+        return UNIT_VTABLE(u)->kill(u, w, m, signo, error);
+}
+
 static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
         [UNIT_STUB] = "stub",
         [UNIT_LOADED] = "loaded",
@@ -2292,12 +2308,3 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
-
-static const char* const kill_mode_table[_KILL_MODE_MAX] = {
-        [KILL_CONTROL_GROUP] = "control-group",
-        [KILL_PROCESS_GROUP] = "process-group",
-        [KILL_PROCESS] = "process",
-        [KILL_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
diff --git a/src/unit.h b/src/unit.h
index fa869ec..3f0ef01 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -277,6 +277,8 @@ struct UnitVTable {
         int (*stop)(Unit *u);
         int (*reload)(Unit *u);
 
+        int (*kill)(Unit *u, KillWho w, KillMode m, int signo, DBusError *error);
+
         bool (*can_reload)(Unit *u);
 
         /* Write all data that cannot be restored from other sources
@@ -458,6 +460,8 @@ int unit_start(Unit *u);
 int unit_stop(Unit *u);
 int unit_reload(Unit *u);
 
+int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error);
+
 void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns);
 
 int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w);
@@ -520,7 +524,4 @@ UnitActiveState unit_active_state_from_string(const char *s);
 const char *unit_dependency_to_string(UnitDependency i);
 UnitDependency unit_dependency_from_string(const char *s);
 
-const char *kill_mode_to_string(KillMode k);
-KillMode kill_mode_from_string(const char *s);
-
 #endif
diff --git a/src/util.c b/src/util.c
index 58f67b0..cf3cf29 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3339,6 +3339,17 @@ DIR *xopendirat(int fd, const char *name) {
         return fdopendir(openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
 }
 
+int signal_from_string_try_harder(const char *s) {
+        int signo;
+        assert(s);
+
+        if ((signo = signal_from_string(s)) <= 0)
+                if (startswith(s, "SIG"))
+                        return signal_from_string(s+3);
+
+        return signo;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/util.h b/src/util.h
index e87fb23..b257ee5 100644
--- a/src/util.h
+++ b/src/util.h
@@ -391,4 +391,6 @@ int ip_tos_from_string(const char *s);
 const char *signal_to_string(int i);
 int signal_from_string(const char *s);
 
+int signal_from_string_try_harder(const char *s);
+
 #endif



More information about the systemd-commits mailing list