core: add support for RestartKillSignal= to override signal used for restart jobs

v2:
- if RestartKillSignal= is not specified, fall back to KillSignal=. This is necessary
  to preserve backwards compatibility (and keep KillSignal= generally useful).
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-10-01 15:15:06 +02:00
parent 28a2dfe801
commit a232ebcc2c
15 changed files with 85 additions and 16 deletions

View File

@ -80,7 +80,7 @@ _systemd_run() {
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group=
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth=
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment=
KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=
LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE=
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=

View File

@ -35,7 +35,7 @@ _arguments \
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \
KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \
LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \

View File

@ -8,10 +8,28 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
static int property_get_restart_kill_signal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
KillContext *c = userdata;
int s;
assert(c);
s = restart_kill_signal(c);
return sd_bus_message_append_basic(reply, 'i', &s);
}
const sd_bus_vtable bus_kill_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestartKillSignal", "i", property_get_restart_kill_signal, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FinalKillSignal", "i", bus_property_get_int, offsetof(KillContext, final_kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), SD_BUS_VTABLE_PROPERTY_CONST),
@ -21,6 +39,7 @@ const sd_bus_vtable bus_kill_vtable[] = {
static BUS_DEFINE_SET_TRANSIENT_PARSE(kill_mode, KillMode, kill_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(restart_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(final_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(watchdog_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
@ -51,6 +70,9 @@ int bus_kill_context_set_transient_property(
if (streq(name, "KillSignal"))
return bus_set_transient_kill_signal(u, name, &c->kill_signal, message, flags, error);
if (streq(name, "RestartKillSignal"))
return bus_set_transient_restart_kill_signal(u, name, &c->restart_kill_signal, message, flags, error);
if (streq(name, "FinalKillSignal"))
return bus_set_transient_final_kill_signal(u, name, &c->final_kill_signal, message, flags, error);

View File

@ -9,6 +9,7 @@ void kill_context_init(KillContext *c) {
assert(c);
c->kill_signal = SIGTERM;
/* restart_kill_signal is unset by default and we fall back to kill_signal */
c->final_kill_signal = SIGKILL;
c->send_sigkill = true;
c->send_sighup = false;
@ -23,11 +24,13 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
fprintf(f,
"%sKillMode: %s\n"
"%sKillSignal: SIG%s\n"
"%sRestartKillSignal: SIG%s\n"
"%sFinalKillSignal: SIG%s\n"
"%sSendSIGKILL: %s\n"
"%sSendSIGHUP: %s\n",
prefix, kill_mode_to_string(c->kill_mode),
prefix, signal_to_string(c->kill_signal),
prefix, signal_to_string(restart_kill_signal(c)),
prefix, signal_to_string(c->final_kill_signal),
prefix, yes_no(c->send_sigkill),
prefix, yes_no(c->send_sighup));

View File

@ -21,6 +21,7 @@ typedef enum KillMode {
struct KillContext {
KillMode kill_mode;
int kill_signal;
int restart_kill_signal;
int final_kill_signal;
int watchdog_signal;
bool send_sigkill;
@ -47,3 +48,9 @@ KillMode kill_mode_from_string(const char *s) _pure_;
const char *kill_who_to_string(KillWho k) _const_;
KillWho kill_who_from_string(const char *s) _pure_;
static inline int restart_kill_signal(const KillContext *c) {
if (c->restart_kill_signal != 0)
return c->restart_kill_signal;
return c->kill_signal;
}

View File

@ -161,6 +161,7 @@ m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup)
$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
$1.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal)
$1.RestartKillSignal, config_parse_signal, 0, offsetof($1, kill_context.restart_kill_signal)
$1.FinalKillSignal, config_parse_signal, 0, offsetof($1, kill_context.final_kill_signal)
$1.WatchdogSignal, config_parse_signal, 0, offsetof($1, kill_context.watchdog_signal)'
)m4_dnl

View File

@ -866,6 +866,8 @@ static int state_to_kill_operation(MountState state) {
switch (state) {
case MOUNT_REMOUNTING_SIGTERM:
return KILL_RESTART;
case MOUNT_UNMOUNTING_SIGTERM:
return KILL_TERMINATE;

View File

@ -1838,13 +1838,17 @@ fail:
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
static int state_to_kill_operation(ServiceState state) {
static int state_to_kill_operation(Service *s, ServiceState state) {
switch (state) {
case SERVICE_STOP_WATCHDOG:
return KILL_WATCHDOG;
case SERVICE_STOP_SIGTERM:
if (unit_has_job_type(UNIT(s), JOB_RESTART))
return KILL_RESTART;
_fallthrough_;
case SERVICE_FINAL_SIGTERM:
return KILL_TERMINATE;
@ -1875,7 +1879,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
r = unit_kill_context(
UNIT(s),
&s->kill_context,
state_to_kill_operation(state),
state_to_kill_operation(s, state),
s->main_pid,
s->control_pid,
s->main_pid_alien);

View File

@ -2077,6 +2077,16 @@ fail:
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
}
static int state_to_kill_operation(Socket *s, SocketState state) {
if (state == SOCKET_STOP_PRE_SIGTERM && unit_has_job_type(UNIT(s), JOB_RESTART))
return KILL_RESTART;
if (state == SOCKET_FINAL_SIGTERM)
return KILL_TERMINATE;
return KILL_KILL;
}
static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
int r;
@ -2088,8 +2098,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
r = unit_kill_context(
UNIT(s),
&s->kill_context,
!IN_SET(state, SOCKET_STOP_PRE_SIGTERM, SOCKET_FINAL_SIGTERM) ?
KILL_KILL : KILL_TERMINATE,
state_to_kill_operation(s, state),
-1,
s->control_pid,
false);

View File

@ -712,21 +712,32 @@ static void swap_enter_dead_or_active(Swap *s, SwapResult f) {
swap_enter_dead(s, f);
}
static int state_to_kill_operation(Swap *s, SwapState state) {
if (state == SWAP_DEACTIVATING_SIGTERM) {
if (unit_has_job_type(UNIT(s), JOB_RESTART))
return KILL_RESTART;
else
return KILL_TERMINATE;
}
return KILL_KILL;
}
static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
int r;
KillOperation kop;
assert(s);
if (s->result == SWAP_SUCCESS)
s->result = f;
if (state == SWAP_DEACTIVATING_SIGTERM)
kop = KILL_TERMINATE;
else
kop = KILL_KILL;
r = unit_kill_context(UNIT(s), &s->kill_context, kop, -1, s->control_pid, false);
r = unit_kill_context(UNIT(s),
&s->kill_context,
state_to_kill_operation(s, state),
-1,
s->control_pid,
false);
if (r < 0)
goto fail;

View File

@ -4695,6 +4695,9 @@ static int operation_to_signal(KillContext *c, KillOperation k) {
case KILL_TERMINATE_AND_LOG:
return c->kill_signal;
case KILL_RESTART:
return restart_kill_signal(c);
case KILL_KILL:
return c->final_kill_signal;

View File

@ -18,6 +18,7 @@ typedef struct UnitRef UnitRef;
typedef enum KillOperation {
KILL_TERMINATE,
KILL_TERMINATE_AND_LOG,
KILL_RESTART,
KILL_KILL,
KILL_WATCHDOG,
_KILL_OPERATION_MAX,

View File

@ -1355,15 +1355,12 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
if (streq(field, "KillMode"))
return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
if (STR_IN_SET(field, "KillSignal", "RestartKillSignal", "FinalKillSignal", "WatchdogSignal"))
return bus_append_signal_from_string(m, field, eq);
return 0;

View File

@ -19,6 +19,14 @@ systemd-run --unit=four -p Type=exec /bin/sleep infinity
! systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity
! systemd-run --unit=six -p Type=exec /tmp/brokenbinary
systemd-run --unit=seven -p KillSignal=SIGTERM -p RestartKillSignal=SIGINT -p Type=exec /bin/sleep infinity
# Both TERM and SIGINT happen to have the same number on all architectures
test $(systemctl show --value -p KillSignal seven.service) -eq 15
test $(systemctl show --value -p RestartKillSignal seven.service) -eq 2
systemctl restart seven.service
systemctl stop seven.service
systemd-analyze log-level info
echo OK > /testok

View File

@ -185,6 +185,7 @@ RequiresMountsFor=
Requisite=
Restart=
RestartForceExitStatus=
RestartKillSignal=
RestartPreventExitStatus=
RestartSec=
ReusePort=