[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