systemctl: introduce systemctl kill

This commit is contained in:
Lennart Poettering 2010-10-22 16:11:50 +02:00
parent 95e501f8ab
commit 8a0867d6c5
17 changed files with 525 additions and 42 deletions

View File

@ -234,6 +234,57 @@
changes.</para></listitem>
</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>
@ -358,6 +409,18 @@
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
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>

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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" \

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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 },

View File

@ -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);

View File

@ -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

View File

@ -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",

View File

@ -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