mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
pid1: add a new D-Bus method for enquing POSIX signals with values to unit processes
This augments the existing KillUnit() + Kill() methods with QueueSignalUnit() + QueueSignal(), which are what sigqueue() is to kill(). This is useful for sending our new SIGRTMIN+18 control signals to system services.
This commit is contained in:
parent
d51e31ac41
commit
a721cd0016
@ -112,6 +112,10 @@ node /org/freedesktop/systemd1 {
|
|||||||
KillUnit(in s name,
|
KillUnit(in s name,
|
||||||
in s whom,
|
in s whom,
|
||||||
in i signal);
|
in i signal);
|
||||||
|
QueueSignalUnit(in s name,
|
||||||
|
in s whom,
|
||||||
|
in i signal,
|
||||||
|
in i value);
|
||||||
CleanUnit(in s name,
|
CleanUnit(in s name,
|
||||||
in as mask);
|
in as mask);
|
||||||
FreezeUnit(in s name);
|
FreezeUnit(in s name);
|
||||||
@ -826,6 +830,8 @@ node /org/freedesktop/systemd1 {
|
|||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="KillUnit()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="KillUnit()"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-method" generated="True" extra-ref="QueueSignalUnit()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="CleanUnit()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="CleanUnit()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="FreezeUnit()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="FreezeUnit()"/>
|
||||||
@ -1286,6 +1292,13 @@ node /org/freedesktop/systemd1 {
|
|||||||
<varname>ExecStop=</varname> and is spawned in parallel to the main daemon process in order to shut it
|
<varname>ExecStop=</varname> and is spawned in parallel to the main daemon process in order to shut it
|
||||||
down.</para>
|
down.</para>
|
||||||
|
|
||||||
|
<para><function>QueueSignalUnit()</function> is similar to <function>KillUnit()</function> but may be
|
||||||
|
used to enqueue a POSIX Realtime Signal (i.e. <constant>SIGRTMIN+…</constant> and
|
||||||
|
<constant>SIGRTMAX-…</constant>) to the selected process(es). Takes the same paramaters as
|
||||||
|
<function>KillUnit()</function> with one additional argument: an integer that is passed in the
|
||||||
|
<varname>sival_int</varname> value accompanying the queued signal. See <citerefentry project="man-pages"><refentrytitle>sigqueue</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
|
||||||
|
details.</para>
|
||||||
|
|
||||||
<para><function>GetJob()</function> returns the job object path for a specific job, identified by its
|
<para><function>GetJob()</function> returns the job object path for a specific job, identified by its
|
||||||
id.</para>
|
id.</para>
|
||||||
|
|
||||||
@ -1731,7 +1744,8 @@ node /org/freedesktop/systemd1 {
|
|||||||
<para>Read access is generally granted to all clients. Additionally, for unprivileged clients, some
|
<para>Read access is generally granted to all clients. Additionally, for unprivileged clients, some
|
||||||
operations are allowed through the polkit privilege system. Operations which modify unit state
|
operations are allowed through the polkit privilege system. Operations which modify unit state
|
||||||
(<function>StartUnit()</function>, <function>StopUnit()</function>, <function>KillUnit()</function>,
|
(<function>StartUnit()</function>, <function>StopUnit()</function>, <function>KillUnit()</function>,
|
||||||
<function>RestartUnit()</function> and similar, <function>SetProperty()</function>) require
|
<function>QueueSignalUnit()</function>, <function>RestartUnit()</function> and similar,
|
||||||
|
<function>SetProperty()</function>) require
|
||||||
<interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
|
<interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
|
||||||
enablement state (<function>EnableUnitFiles()</function>, <function>DisableUnitFiles()</function>,
|
enablement state (<function>EnableUnitFiles()</function>, <function>DisableUnitFiles()</function>,
|
||||||
<function>EnableUnitFilesWithFlags()</function>, <function>DisableUnitFilesWithFlags()</function>,
|
<function>EnableUnitFilesWithFlags()</function>, <function>DisableUnitFilesWithFlags()</function>,
|
||||||
@ -1778,6 +1792,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
out a(uosos) affected_jobs);
|
out a(uosos) affected_jobs);
|
||||||
Kill(in s whom,
|
Kill(in s whom,
|
||||||
in i signal);
|
in i signal);
|
||||||
|
QueueSignal(in s whom,
|
||||||
|
in i signal,
|
||||||
|
in i value);
|
||||||
ResetFailed();
|
ResetFailed();
|
||||||
SetProperties(in b runtime,
|
SetProperties(in b runtime,
|
||||||
in a(sv) properties);
|
in a(sv) properties);
|
||||||
@ -2084,6 +2101,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="Kill()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="Kill()"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-method" generated="True" extra-ref="QueueSignal()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="ResetFailed()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="ResetFailed()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="SetProperties()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="SetProperties()"/>
|
||||||
@ -2302,12 +2321,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
<para><function>Start()</function>, <function>Stop()</function>, <function>Reload()</function>,
|
<para><function>Start()</function>, <function>Stop()</function>, <function>Reload()</function>,
|
||||||
<function>Restart()</function>, <function>TryRestart()</function>,
|
<function>Restart()</function>, <function>TryRestart()</function>,
|
||||||
<function>ReloadOrRestart()</function>, <function>ReloadOrTryRestart()</function>,
|
<function>ReloadOrRestart()</function>, <function>ReloadOrTryRestart()</function>,
|
||||||
<function>Kill()</function>, <function>ResetFailed()</function>, and
|
<function>Kill()</function>, <function>QueueSignal()</function>, <function>ResetFailed()</function>,
|
||||||
<function>SetProperties()</function> implement the same operation as the respective methods on the
|
and <function>SetProperties()</function> implement the same operation as the respective methods on the
|
||||||
<interfacename>Manager</interfacename> object (see above). However, these methods operate on the unit
|
<interfacename>Manager</interfacename> object (see above). However, these methods operate on the unit
|
||||||
object and hence do not take a unit name parameter. Invoking the methods directly on the Manager
|
object and hence do not take a unit name parameter. Invoking the methods directly on the Manager object
|
||||||
object has the advantage of not requiring a <function>GetUnit()</function> call to get the unit object
|
has the advantage of not requiring a <function>GetUnit()</function> call to get the unit object for a
|
||||||
for a specific unit name. Calling the methods on the Manager object is hence a round trip
|
specific unit name. Calling the methods on the Manager object is hence a round trip
|
||||||
optimization.</para>
|
optimization.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
@ -3034,6 +3034,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
method_kill_unit,
|
method_kill_unit,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD_WITH_ARGS("QueueSignalUnit",
|
||||||
|
SD_BUS_ARGS("s", name, "s", whom, "i", signal, "i", value),
|
||||||
|
SD_BUS_NO_RESULT,
|
||||||
|
method_kill_unit,
|
||||||
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD_WITH_ARGS("CleanUnit",
|
SD_BUS_METHOD_WITH_ARGS("CleanUnit",
|
||||||
SD_BUS_ARGS("s", name, "as", mask),
|
SD_BUS_ARGS("s", name, "as", mask),
|
||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
|
@ -513,10 +513,11 @@ int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_
|
|||||||
|
|
||||||
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
Unit *u = ASSERT_PTR(userdata);
|
Unit *u = ASSERT_PTR(userdata);
|
||||||
|
int32_t value = 0;
|
||||||
const char *swho;
|
const char *swho;
|
||||||
int32_t signo;
|
int32_t signo;
|
||||||
KillWho who;
|
KillWho who;
|
||||||
int r;
|
int r, code;
|
||||||
|
|
||||||
assert(message);
|
assert(message);
|
||||||
|
|
||||||
@ -528,17 +529,30 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (startswith(sd_bus_message_get_member(message), "QueueSignal")) {
|
||||||
|
r = sd_bus_message_read(message, "i", &value);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
code = SI_QUEUE;
|
||||||
|
} else
|
||||||
|
code = SI_USER;
|
||||||
|
|
||||||
if (isempty(swho))
|
if (isempty(swho))
|
||||||
who = KILL_ALL;
|
who = KILL_ALL;
|
||||||
else {
|
else {
|
||||||
who = kill_who_from_string(swho);
|
who = kill_who_from_string(swho);
|
||||||
if (who < 0)
|
if (who < 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument: %s", swho);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SIGNAL_VALID(signo))
|
if (!SIGNAL_VALID(signo))
|
||||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
|
||||||
|
|
||||||
|
if (code == SI_QUEUE && !((signo >= SIGRTMIN) && (signo <= SIGRTMAX)))
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
|
"Value parameter only accepted for realtime signals (SIGRTMIN…SIGRTMAX), refusing for signal SIG%s.", signal_to_string(signo));
|
||||||
|
|
||||||
r = bus_verify_manage_units_async_full(
|
r = bus_verify_manage_units_async_full(
|
||||||
u,
|
u,
|
||||||
"kill",
|
"kill",
|
||||||
@ -552,7 +566,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||||
|
|
||||||
r = unit_kill(u, who, signo, error);
|
r = unit_kill(u, who, signo, code, value, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -984,6 +998,11 @@ const sd_bus_vtable bus_unit_vtable[] = {
|
|||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
bus_unit_method_kill,
|
bus_unit_method_kill,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD_WITH_ARGS("QueueSignal",
|
||||||
|
SD_BUS_ARGS("s", whom, "i", signal, "i", value),
|
||||||
|
SD_BUS_NO_RESULT,
|
||||||
|
bus_unit_method_kill,
|
||||||
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("ResetFailed",
|
SD_BUS_METHOD("ResetFailed",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -2158,12 +2158,12 @@ static void mount_reset_failed(Unit *u) {
|
|||||||
m->clean_result = MOUNT_SUCCESS;
|
m->clean_result = MOUNT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
static int mount_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
|
||||||
Mount *m = MOUNT(u);
|
Mount *m = MOUNT(u);
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
return unit_kill_common(u, who, signo, -1, m->control_pid, error);
|
return unit_kill_common(u, who, signo, code, value, -1, m->control_pid, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mount_control_pid(Unit *u) {
|
static int mount_control_pid(Unit *u) {
|
||||||
|
@ -246,6 +246,10 @@
|
|||||||
send_interface="org.freedesktop.systemd1.Manager"
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
send_member="KillUnit"/>
|
send_member="KillUnit"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
|
send_member="QueueSignalUnit"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.systemd1"
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
send_interface="org.freedesktop.systemd1.Manager"
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
send_member="ResetFailedUnit"/>
|
send_member="ResetFailedUnit"/>
|
||||||
@ -390,6 +394,10 @@
|
|||||||
send_interface="org.freedesktop.systemd1.Unit"
|
send_interface="org.freedesktop.systemd1.Unit"
|
||||||
send_member="Kill"/>
|
send_member="Kill"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
|
send_interface="org.freedesktop.systemd1.Unit"
|
||||||
|
send_member="QueueSignal"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.systemd1"
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
send_interface="org.freedesktop.systemd1.Unit"
|
send_interface="org.freedesktop.systemd1.Unit"
|
||||||
send_member="ResetFailed"/>
|
send_member="ResetFailed"/>
|
||||||
|
@ -530,8 +530,8 @@ static void scope_reset_failed(Unit *u) {
|
|||||||
s->result = SCOPE_SUCCESS;
|
s->result = SCOPE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
static int scope_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
|
||||||
return unit_kill_common(u, who, signo, -1, -1, error);
|
return unit_kill_common(u, who, signo, code, value, -1, -1, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scope_get_timeout(Unit *u, usec_t *timeout) {
|
static int scope_get_timeout(Unit *u, usec_t *timeout) {
|
||||||
|
@ -4596,12 +4596,12 @@ static void service_reset_failed(Unit *u) {
|
|||||||
s->flush_n_restarts = false;
|
s->flush_n_restarts = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
static int service_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
|
||||||
Service *s = SERVICE(u);
|
Service *s = SERVICE(u);
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
|
return unit_kill_common(u, who, signo, code, value, s->main_pid, s->control_pid, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_main_pid(Unit *u) {
|
static int service_main_pid(Unit *u) {
|
||||||
|
@ -247,8 +247,8 @@ static int slice_stop(Unit *u) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
static int slice_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
|
||||||
return unit_kill_common(u, who, signo, -1, -1, error);
|
return unit_kill_common(u, who, signo, code, value, -1, -1, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
|
static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
|
||||||
|
@ -3299,8 +3299,8 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
|
|||||||
socket_set_state(s, SOCKET_RUNNING);
|
socket_set_state(s, SOCKET_RUNNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
static int socket_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
|
||||||
return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error);
|
return unit_kill_common(u, who, signo, code, value, -1, SOCKET(u)->control_pid, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_get_timeout(Unit *u, usec_t *timeout) {
|
static int socket_get_timeout(Unit *u, usec_t *timeout) {
|
||||||
|
@ -1480,8 +1480,8 @@ static void swap_reset_failed(Unit *u) {
|
|||||||
s->clean_result = SWAP_SUCCESS;
|
s->clean_result = SWAP_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
static int swap_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
|
||||||
return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
|
return unit_kill_common(u, who, signo, code, value, -1, SWAP(u)->control_pid, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int swap_get_timeout(Unit *u, usec_t *timeout) {
|
static int swap_get_timeout(Unit *u, usec_t *timeout) {
|
||||||
|
150
src/core/unit.c
150
src/core/unit.c
@ -3785,15 +3785,16 @@ bool unit_will_restart(Unit *u) {
|
|||||||
return UNIT_VTABLE(u)->will_restart(u);
|
return UNIT_VTABLE(u)->will_restart(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
|
int unit_kill(Unit *u, KillWho w, int signo, int code, int value, sd_bus_error *error) {
|
||||||
assert(u);
|
assert(u);
|
||||||
assert(w >= 0 && w < _KILL_WHO_MAX);
|
assert(w >= 0 && w < _KILL_WHO_MAX);
|
||||||
assert(SIGNAL_VALID(signo));
|
assert(SIGNAL_VALID(signo));
|
||||||
|
assert(IN_SET(code, SI_USER, SI_QUEUE));
|
||||||
|
|
||||||
if (!UNIT_VTABLE(u)->kill)
|
if (!UNIT_VTABLE(u)->kill)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
return UNIT_VTABLE(u)->kill(u, w, signo, error);
|
return UNIT_VTABLE(u)->kill(u, w, signo, code, value, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_notify_cgroup_oom(Unit *u, bool managed_oom) {
|
void unit_notify_cgroup_oom(Unit *u, bool managed_oom) {
|
||||||
@ -3838,21 +3839,48 @@ static int kill_common_log(pid_t pid, int signo, void *userdata) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kill_or_sigqueue(pid_t pid, int signo, int code, int value) {
|
||||||
|
assert(pid > 0);
|
||||||
|
assert(SIGNAL_VALID(signo));
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
|
||||||
|
case SI_USER:
|
||||||
|
log_debug("Killing " PID_FMT " with signal SIG%s.", pid, signal_to_string(signo));
|
||||||
|
return RET_NERRNO(kill(pid, signo));
|
||||||
|
|
||||||
|
case SI_QUEUE:
|
||||||
|
log_debug("Enqueuing value %i to " PID_FMT " on signal SIG%s.", value, pid, signal_to_string(signo));
|
||||||
|
return RET_NERRNO(sigqueue(pid, signo, (const union sigval) { .sival_int = value }));
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int unit_kill_common(
|
int unit_kill_common(
|
||||||
Unit *u,
|
Unit *u,
|
||||||
KillWho who,
|
KillWho who,
|
||||||
int signo,
|
int signo,
|
||||||
|
int code,
|
||||||
|
int value,
|
||||||
pid_t main_pid,
|
pid_t main_pid,
|
||||||
pid_t control_pid,
|
pid_t control_pid,
|
||||||
sd_bus_error *error) {
|
sd_bus_error *error) {
|
||||||
|
|
||||||
int r = 0;
|
|
||||||
bool killed = false;
|
bool killed = false;
|
||||||
|
int ret = 0, r;
|
||||||
|
|
||||||
/* This is the common implementation for explicit user-requested killing of unit processes, shared by
|
/* This is the common implementation for explicit user-requested killing of unit processes, shared by
|
||||||
* various unit types. Do not confuse with unit_kill_context(), which is what we use when we want to
|
* various unit types. Do not confuse with unit_kill_context(), which is what we use when we want to
|
||||||
* stop a service ourselves. */
|
* stop a service ourselves. */
|
||||||
|
|
||||||
|
assert(u);
|
||||||
|
assert(who >= 0);
|
||||||
|
assert(who < _KILL_WHO_MAX);
|
||||||
|
assert(SIGNAL_VALID(signo));
|
||||||
|
assert(IN_SET(code, SI_USER, SI_QUEUE));
|
||||||
|
|
||||||
if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
|
if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
|
||||||
if (main_pid < 0)
|
if (main_pid < 0)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
|
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
|
||||||
@ -3867,71 +3895,85 @@ int unit_kill_common(
|
|||||||
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
|
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL))
|
if (control_pid > 0 &&
|
||||||
if (control_pid > 0) {
|
IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL)) {
|
||||||
_cleanup_free_ char *comm = NULL;
|
_cleanup_free_ char *comm = NULL;
|
||||||
(void) get_process_comm(control_pid, &comm);
|
(void) get_process_comm(control_pid, &comm);
|
||||||
|
|
||||||
|
r = kill_or_sigqueue(control_pid, signo, code, value);
|
||||||
|
if (r < 0) {
|
||||||
|
ret = r;
|
||||||
|
|
||||||
|
/* Report this failure both to the logs and to the client */
|
||||||
|
sd_bus_error_set_errnof(
|
||||||
|
error, r,
|
||||||
|
"Failed to send signal SIG%s to control process " PID_FMT " (%s): %m",
|
||||||
|
signal_to_string(signo), control_pid, strna(comm));
|
||||||
|
log_unit_warning_errno(
|
||||||
|
u, r,
|
||||||
|
"Failed to send signal SIG%s to control process " PID_FMT " (%s) on client request: %m",
|
||||||
|
signal_to_string(signo), control_pid, strna(comm));
|
||||||
|
} else {
|
||||||
|
log_unit_info(u, "Sent signal SIG%s to control process " PID_FMT " (%s) on client request.",
|
||||||
|
signal_to_string(signo), control_pid, strna(comm));
|
||||||
|
killed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (main_pid > 0 &&
|
||||||
|
IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL)) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *comm = NULL;
|
||||||
|
(void) get_process_comm(main_pid, &comm);
|
||||||
|
|
||||||
|
r = kill_or_sigqueue(main_pid, signo, code, value);
|
||||||
|
if (r < 0) {
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = r;
|
||||||
|
|
||||||
if (kill(control_pid, signo) < 0) {
|
|
||||||
/* Report this failure both to the logs and to the client */
|
|
||||||
sd_bus_error_set_errnof(
|
sd_bus_error_set_errnof(
|
||||||
error, errno,
|
error, r,
|
||||||
"Failed to send signal SIG%s to control process " PID_FMT " (%s): %m",
|
"Failed to send signal SIG%s to main process " PID_FMT " (%s): %m",
|
||||||
signal_to_string(signo), control_pid, strna(comm));
|
|
||||||
r = log_unit_warning_errno(
|
|
||||||
u, errno,
|
|
||||||
"Failed to send signal SIG%s to control process " PID_FMT " (%s) on client request: %m",
|
|
||||||
signal_to_string(signo), control_pid, strna(comm));
|
|
||||||
} else {
|
|
||||||
log_unit_info(u, "Sent signal SIG%s to control process " PID_FMT " (%s) on client request.",
|
|
||||||
signal_to_string(signo), control_pid, strna(comm));
|
|
||||||
killed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL))
|
|
||||||
if (main_pid > 0) {
|
|
||||||
_cleanup_free_ char *comm = NULL;
|
|
||||||
(void) get_process_comm(main_pid, &comm);
|
|
||||||
|
|
||||||
if (kill(main_pid, signo) < 0) {
|
|
||||||
if (r == 0)
|
|
||||||
sd_bus_error_set_errnof(
|
|
||||||
error, errno,
|
|
||||||
"Failed to send signal SIG%s to main process " PID_FMT " (%s): %m",
|
|
||||||
signal_to_string(signo), main_pid, strna(comm));
|
|
||||||
|
|
||||||
r = log_unit_warning_errno(
|
|
||||||
u, errno,
|
|
||||||
"Failed to send signal SIG%s to main process " PID_FMT " (%s) on client request: %m",
|
|
||||||
signal_to_string(signo), main_pid, strna(comm));
|
signal_to_string(signo), main_pid, strna(comm));
|
||||||
} else {
|
|
||||||
log_unit_info(u, "Sent signal SIG%s to main process " PID_FMT " (%s) on client request.",
|
|
||||||
signal_to_string(signo), main_pid, strna(comm));
|
|
||||||
killed = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && u->cgroup_path) {
|
log_unit_warning_errno(
|
||||||
|
u, r,
|
||||||
|
"Failed to send signal SIG%s to main process " PID_FMT " (%s) on client request: %m",
|
||||||
|
signal_to_string(signo), main_pid, strna(comm));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log_unit_info(u, "Sent signal SIG%s to main process " PID_FMT " (%s) on client request.",
|
||||||
|
signal_to_string(signo), main_pid, strna(comm));
|
||||||
|
killed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: if we shall enqueue rather than kill we won't do this via the cgroup mechanism, since it
|
||||||
|
* doesn't really make much sense (and given that enqueued values are a relatively expensive
|
||||||
|
* resource, and we shouldn't allow us to be subjects for such allocation sprees) */
|
||||||
|
if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && u->cgroup_path && code == SI_USER) {
|
||||||
_cleanup_set_free_ Set *pid_set = NULL;
|
_cleanup_set_free_ Set *pid_set = NULL;
|
||||||
int q;
|
|
||||||
|
|
||||||
/* Exclude the main/control pids from being killed via the cgroup */
|
/* Exclude the main/control pids from being killed via the cgroup */
|
||||||
pid_set = unit_pid_set(main_pid, control_pid);
|
pid_set = unit_pid_set(main_pid, control_pid);
|
||||||
if (!pid_set)
|
if (!pid_set)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, kill_common_log, u);
|
r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, kill_common_log, u);
|
||||||
if (q < 0) {
|
if (r < 0) {
|
||||||
if (!IN_SET(q, -ESRCH, -ENOENT)) {
|
if (!IN_SET(r, -ESRCH, -ENOENT)) {
|
||||||
if (r == 0)
|
if (ret == 0) {
|
||||||
|
ret = r;
|
||||||
|
|
||||||
sd_bus_error_set_errnof(
|
sd_bus_error_set_errnof(
|
||||||
error, q,
|
error, r,
|
||||||
"Failed to send signal SIG%s to auxiliary processes: %m",
|
"Failed to send signal SIG%s to auxiliary processes: %m",
|
||||||
signal_to_string(signo));
|
signal_to_string(signo));
|
||||||
|
}
|
||||||
|
|
||||||
r = log_unit_warning_errno(
|
log_unit_warning_errno(
|
||||||
u, q,
|
u, r,
|
||||||
"Failed to send signal SIG%s to auxiliary processes on client request: %m",
|
"Failed to send signal SIG%s to auxiliary processes on client request: %m",
|
||||||
signal_to_string(signo));
|
signal_to_string(signo));
|
||||||
}
|
}
|
||||||
@ -3940,10 +3982,10 @@ int unit_kill_common(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If the "fail" versions of the operation are requested, then complain if the set of processes we killed is empty */
|
/* If the "fail" versions of the operation are requested, then complain if the set of processes we killed is empty */
|
||||||
if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_MAIN_FAIL))
|
if (ret == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_MAIN_FAIL))
|
||||||
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No matching processes to kill");
|
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No matching processes to kill");
|
||||||
|
|
||||||
return r;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unit_following_set(Unit *u, Set **s) {
|
int unit_following_set(Unit *u, Set **s) {
|
||||||
|
@ -619,7 +619,7 @@ typedef struct UnitVTable {
|
|||||||
int (*stop)(Unit *u);
|
int (*stop)(Unit *u);
|
||||||
int (*reload)(Unit *u);
|
int (*reload)(Unit *u);
|
||||||
|
|
||||||
int (*kill)(Unit *u, KillWho w, int signo, sd_bus_error *error);
|
int (*kill)(Unit *u, KillWho w, int signo, int code, int value, sd_bus_error *error);
|
||||||
|
|
||||||
/* Clear out the various runtime/state/cache/logs/configuration data */
|
/* Clear out the various runtime/state/cache/logs/configuration data */
|
||||||
int (*clean)(Unit *u, ExecCleanMask m);
|
int (*clean)(Unit *u, ExecCleanMask m);
|
||||||
@ -889,8 +889,8 @@ int unit_start(Unit *u, ActivationDetails *details);
|
|||||||
int unit_stop(Unit *u);
|
int unit_stop(Unit *u);
|
||||||
int unit_reload(Unit *u);
|
int unit_reload(Unit *u);
|
||||||
|
|
||||||
int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error);
|
int unit_kill(Unit *u, KillWho w, int signo, int code, int value, sd_bus_error *error);
|
||||||
int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t control_pid, sd_bus_error *error);
|
int unit_kill_common(Unit *u, KillWho who, int signo, int code, int value, pid_t main_pid, pid_t control_pid, sd_bus_error *error);
|
||||||
|
|
||||||
void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
|
void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ static void wait_for_service_finish(Manager *m, Unit *unit) {
|
|||||||
n = now(CLOCK_MONOTONIC);
|
n = now(CLOCK_MONOTONIC);
|
||||||
if (ts + timeout < n) {
|
if (ts + timeout < n) {
|
||||||
log_error("Test timeout when testing %s", unit->id);
|
log_error("Test timeout when testing %s", unit->id);
|
||||||
r = unit_kill(unit, KILL_ALL, SIGKILL, NULL);
|
r = unit_kill(unit, KILL_ALL, SIGKILL, SI_USER, 0, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to kill %s: %m", unit->id);
|
log_error_errno(r, "Failed to kill %s: %m", unit->id);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
Loading…
Reference in New Issue
Block a user