From fbb48d4c66ada1ea7ffb3bdd03cf5e6a3579b600 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Fri, 20 Jul 2018 11:22:43 -0400 Subject: [PATCH] Make final kill signal configurable Usecase is to allow changing the final kill from SIGKILL to SIGQUIT which should create a core dump useful for debugging why the service didn't stop with the SIGTERM --- doc/TRANSIENT-SETTINGS.md | 1 + man/systemd.kill.xml | 27 +++++++++++++++++++++++---- shell-completion/bash/systemd-run | 4 ++-- shell-completion/zsh/_systemd-run | 4 ++-- src/core/dbus-kill.c | 5 +++++ src/core/kill.c | 3 +++ src/core/kill.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 3 ++- src/core/load-fragment.h | 1 + src/core/unit.c | 2 +- src/shared/bus-unit-util.c | 2 +- 11 files changed, 42 insertions(+), 11 deletions(-) diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md index 2d73980f163..bb13cfdbfe7 100644 --- a/doc/TRANSIENT-SETTINGS.md +++ b/doc/TRANSIENT-SETTINGS.md @@ -256,6 +256,7 @@ All process killing settings are available for transient units: ✓ SendSIGHUP= ✓ KillMode= ✓ KillSignal= +✓ FinalKillSignal= ``` ## Service Unit Settings diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml index 2112dea31a4..1a429062406 100644 --- a/man/systemd.kill.xml +++ b/man/systemd.kill.xml @@ -94,7 +94,8 @@ enabled with SendSIGHUP=). If then, after a delay (configured via the TimeoutStopSec= option), processes still remain, the termination request is - repeated with the SIGKILL signal (unless + repeated with the SIGKILL signal or the + signal specified via FinalKillSignal= (unless this is disabled via the SendSIGKILL= option). See kill2 @@ -135,9 +136,27 @@ SendSIGKILL= Specifies whether to send - SIGKILL to remaining processes after a - timeout, if the normal shutdown procedure left processes of - the service around. Takes a boolean value. Defaults to "yes". + SIGKILL (or the signal specified by + FinalKillSignal=) to remaining processes + after a timeout, if the normal shutdown procedure left + processes of the service around. Takes a boolean value. + Defaults to "yes". + + + + + FinalKillSignal= + Specifies which signal to send to remaining + processes after a timeout if SendSIGKILL= + is enabled. The signal configured here should be one that is + not typically caught and processed by services (SIGTERM + is not suitable). Developers can find it useful to use this to + generate a coredump to troubleshoot why a service did not + terminate upon receiving the initial SIGTERM + signal. This can be achieved by configuring LimitCORE= + and setting FinalKillSignal= to either + SIGQUIT or SIGABRT + Defaults to SIGKILL. diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index d317466b26f..4c60130dfa2 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -79,8 +79,8 @@ _systemd_run() { SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= - KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= - LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= + KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= + LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index 0ad4b27a6fe..a8a8e6fe34a 100644 --- a/shell-completion/zsh/_systemd-run +++ b/shell-completion/zsh/_systemd-run @@ -32,8 +32,8 @@ _arguments \ SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \ DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \ BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \ - KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= \ - LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \ + KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \ + LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \ LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \ LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \ PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \ diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c index 028e7ec1c16..3e2a7694a7b 100644 --- a/src/core/dbus-kill.c +++ b/src/core/dbus-kill.c @@ -12,6 +12,7 @@ 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("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), SD_BUS_VTABLE_END @@ -19,6 +20,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(final_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check); int bus_kill_context_set_transient_property( Unit *u, @@ -47,5 +49,8 @@ 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, "FinalKillSignal")) + return bus_set_transient_final_kill_signal(u, name, &c->final_kill_signal, message, flags, error); + return 0; } diff --git a/src/core/kill.c b/src/core/kill.c index 929eebfe37c..73fa556d135 100644 --- a/src/core/kill.c +++ b/src/core/kill.c @@ -9,6 +9,7 @@ void kill_context_init(KillContext *c) { assert(c); c->kill_signal = SIGTERM; + c->final_kill_signal = SIGKILL; c->send_sigkill = true; c->send_sighup = false; } @@ -21,10 +22,12 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) { fprintf(f, "%sKillMode: %s\n" "%sKillSignal: 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(c->final_kill_signal), prefix, yes_no(c->send_sigkill), prefix, yes_no(c->send_sighup)); } diff --git a/src/core/kill.h b/src/core/kill.h index 2d6aa943a61..f4e312d75a5 100644 --- a/src/core/kill.h +++ b/src/core/kill.h @@ -21,6 +21,7 @@ typedef enum KillMode { struct KillContext { KillMode kill_mode; int kill_signal; + int final_kill_signal; bool send_sigkill; bool send_sighup; }; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 290e8001d8c..7a276ea3c8c 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -151,7 +151,8 @@ m4_define(`KILL_CONTEXT_CONFIG_ITEMS', `$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill) $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.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal) +$1.FinalKillSignal, config_parse_signal, 0, offsetof($1, kill_context.final_kill_signal)' )m4_dnl m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS', `$1.Slice, config_parse_unit_slice, 0, 0 diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index dad281ef72a..1cb5ccadf60 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -39,6 +39,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity); CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits); CONFIG_PARSER_PROTOTYPE(config_parse_capability_set); CONFIG_PARSER_PROTOTYPE(config_parse_kill_signal); +CONFIG_PARSER_PROTOTYPE(config_parse_final_kill_signal); CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags); CONFIG_PARSER_PROTOTYPE(config_parse_timer); CONFIG_PARSER_PROTOTYPE(config_parse_trigger_unit); diff --git a/src/core/unit.c b/src/core/unit.c index 113205bf254..23433be31c4 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -4479,7 +4479,7 @@ static int operation_to_signal(KillContext *c, KillOperation k) { return c->kill_signal; case KILL_KILL: - return SIGKILL; + return c->final_kill_signal; case KILL_ABORT: return SIGABRT; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 0c713678e2d..8f90f2c31ae 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1189,7 +1189,7 @@ static int bus_append_kill_property(sd_bus_message *m, const char *field, const return bus_append_parse_boolean(m, field, eq); - if (streq(field, "KillSignal")) + if (STR_IN_SET(field, "KillSignal", "FinalKillSignal")) return bus_append_signal_from_string(m, field, eq);