mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-11-24 07:20:56 +07:00
systemctl: introduce systemctl kill
This commit is contained in:
parent
95e501f8ab
commit
8a0867d6c5
@ -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>
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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" \
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
49
src/mount.c
49
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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
48
src/socket.c
48
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,
|
||||
|
49
src/swap.c
49
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,
|
||||
|
||||
|
140
src/systemctl.c
140
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 },
|
||||
|
25
src/unit.c
25
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);
|
||||
|
@ -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
|
||||
|
11
src/util.c
11
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",
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user