1
0
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:
Lennart Poettering 2023-02-15 10:25:51 +01:00
parent d51e31ac41
commit a721cd0016
13 changed files with 172 additions and 79 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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