diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml
index 2a810e257f..517a891777 100644
--- a/man/systemd.kill.xml
+++ b/man/systemd.kill.xml
@@ -115,16 +115,21 @@
.
Processes will first be
- terminated via SIGTERM (unless the
- signal to send is changed via
- KillSignal=). If
+ terminated via
+ SIGTERM (unless
+ the signal to send is changed via
+ KillSignal=). Optionally,
+ this is immediately followed by a
+ SIGHUP (if
+ enabled with
+ SendSIGHUP=). If
then after a delay (configured via the
- TimeoutSec= option)
+ TimeoutStopSec= option)
processes still remain, the
termination request is repeated with
- the SIGKILL signal (unless this is
- disabled via the
- SendSIGKILL=
+ the SIGKILL
+ signal (unless this is disabled via
+ the SendSIGKILL=
option). See
kill2
for more
@@ -139,6 +144,20 @@
+
+ SendSIGHUP=
+ Specifies whether to
+ send SIGHUP to
+ remaining processes immediately after
+ sending the signal configured with
+ KillSignal=. This
+ is useful to indicate to shells and
+ shell-like programs that their
+ connection has been severed. Takes a
+ boolean value. Defaults to "no".
+
+
+
SendSIGKILL=
Specifies whether to
@@ -149,6 +168,7 @@
value. Defaults to "yes".
+
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index 165f63074b..e970ea329c 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -31,5 +31,6 @@ const BusProperty bus_kill_context_properties[] = {
{ "KillMode", bus_kill_append_mode, "s", offsetof(KillContext, kill_mode) },
{ "KillSignal", bus_property_append_int, "i", offsetof(KillContext, kill_signal) },
{ "SendSIGKILL", bus_property_append_bool, "b", offsetof(KillContext, send_sigkill) },
+ { "SendSIGHUP", bus_property_append_bool, "b", offsetof(KillContext, send_sighup) },
{ NULL, }
};
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
index 238fbd36d6..8c8bff5927 100644
--- a/src/core/dbus-kill.h
+++ b/src/core/dbus-kill.h
@@ -29,10 +29,8 @@
#define BUS_KILL_CONTEXT_INTERFACE \
" \n" \
" \n" \
- " \n"
-
-#define BUS_KILL_COMMAND_INTERFACE(name) \
- " \n"
+ " \n" \
+ " \n"
extern const BusProperty bus_kill_context_properties[];
diff --git a/src/core/kill.c b/src/core/kill.c
index 0775653f73..ea947c23ae 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -29,6 +29,7 @@ void kill_context_init(KillContext *c) {
c->kill_signal = SIGTERM;
c->send_sigkill = true;
+ c->send_sighup = false;
}
void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
@@ -40,10 +41,12 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
fprintf(f,
"%sKillMode: %s\n"
"%sKillSignal: SIG%s\n"
- "%sSendSIGKILL: %s\n",
+ "%sSendSIGKILL: %s\n"
+ "%sSendSIGHUP: %s\n",
prefix, kill_mode_to_string(c->kill_mode),
prefix, signal_to_string(c->kill_signal),
- prefix, yes_no(c->send_sigkill));
+ prefix, yes_no(c->send_sigkill),
+ prefix, yes_no(c->send_sighup));
}
static const char* const kill_mode_table[_KILL_MODE_MAX] = {
diff --git a/src/core/kill.h b/src/core/kill.h
index 71a0513e84..41773f07ae 100644
--- a/src/core/kill.h
+++ b/src/core/kill.h
@@ -41,6 +41,7 @@ struct KillContext {
KillMode kill_mode;
int kill_signal;
bool send_sigkill;
+ bool send_sighup;
};
typedef enum KillWho {
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 0c337bca9c..2b0106ffe2 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -79,6 +79,7 @@ $1.UtmpIdentifier, config_parse_unit_string_printf, 0,
)m4_dnl
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_kill_signal, 0, offsetof($1, kill_context.kill_signal)'
)m4_dnl
diff --git a/src/core/unit.c b/src/core/unit.c
index 0e9329f8c9..b56be83a31 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2542,6 +2542,34 @@ int unit_kill(Unit *u, KillWho w, int signo, DBusError *error) {
return UNIT_VTABLE(u)->kill(u, w, signo, error);
}
+static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
+ Set *pid_set;
+ int r;
+
+ pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ if (!pid_set)
+ return NULL;
+
+ /* Exclude the main/control pids from being killed via the cgroup */
+ if (main_pid > 0) {
+ r = set_put(pid_set, LONG_TO_PTR(main_pid));
+ if (r < 0)
+ goto fail;
+ }
+
+ if (control_pid > 0) {
+ r = set_put(pid_set, LONG_TO_PTR(control_pid));
+ if (r < 0)
+ goto fail;
+ }
+
+ return pid_set;
+
+fail:
+ set_free(pid_set);
+ return NULL;
+}
+
int unit_kill_common(
Unit *u,
KillWho who,
@@ -2582,23 +2610,11 @@ int unit_kill_common(
_cleanup_set_free_ Set *pid_set = NULL;
int q;
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ /* Exclude the main/control pids from being killed via the cgroup */
+ pid_set = unit_pid_set(main_pid, control_pid);
if (!pid_set)
return -ENOMEM;
- /* Exclude the control/main pid from being killed via the cgroup */
- if (control_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(control_pid));
- if (q < 0)
- return q;
- }
-
- if (main_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(main_pid));
- if (q < 0)
- return q;
- }
-
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
@@ -2949,8 +2965,12 @@ int unit_kill_context(
log_warning_unit(u->id, "Failed to kill main process %li (%s): %s",
(long) main_pid, strna(comm), strerror(-r));
- } else
+ } else {
wait_for_exit = !main_pid_alien;
+
+ if (c->send_sighup)
+ kill(main_pid, SIGHUP);
+ }
}
if (control_pid > 0) {
@@ -2963,36 +2983,38 @@ int unit_kill_context(
log_warning_unit(u->id,
"Failed to kill control process %li (%s): %s",
(long) control_pid, strna(comm), strerror(-r));
- } else
+ } else {
wait_for_exit = true;
+
+ if (c->send_sighup)
+ kill(control_pid, SIGHUP);
+ }
}
if (c->kill_mode == KILL_CONTROL_GROUP && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ /* Exclude the main/control pids from being killed via the cgroup */
+ pid_set = unit_pid_set(main_pid, control_pid);
if (!pid_set)
return -ENOMEM;
- /* Exclude the main/control pids from being killed via the cgroup */
- if (main_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(main_pid));
- if (r < 0)
- return r;
- }
-
- if (control_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(control_pid));
- if (r < 0)
- return r;
- }
-
r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
- } else if (r > 0)
+ } else if (r > 0) {
wait_for_exit = true;
+ if (c->send_sighup) {
+ set_free(pid_set);
+
+ pid_set = unit_pid_set(main_pid, control_pid);
+ if (!pid_set)
+ return -ENOMEM;
+
+ cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, true, true, false, pid_set);
+ }
+ }
}
return wait_for_exit;
diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in
index 0426050ee8..2fd9dd8478 100644
--- a/units/console-getty.service.m4.in
+++ b/units/console-getty.service.m4.in
@@ -25,10 +25,7 @@ TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
-
-# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
-# terminates cleanly.
-KillSignal=SIGHUP
+SendSIGHUP=yes
[Install]
WantedBy=getty.target
diff --git a/units/console-shell.service.m4.in b/units/console-shell.service.m4.in
index dac2ac212b..3f4904a0ee 100644
--- a/units/console-shell.service.m4.in
+++ b/units/console-shell.service.m4.in
@@ -25,10 +25,7 @@ StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
-
-# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
-# terminates cleanly.
-KillSignal=SIGHUP
+SendSIGHUP=yes
[Install]
WantedBy=getty.target
diff --git a/units/emergency.service.in b/units/emergency.service.in
index 442f0e0ee6..94c090f654 100644
--- a/units/emergency.service.in
+++ b/units/emergency.service.in
@@ -25,7 +25,4 @@ StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
-
-# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
-# terminates cleanly.
-KillSignal=SIGHUP
+SendSIGHUP=yes
diff --git a/units/getty@.service.m4 b/units/getty@.service.m4
index 7853652009..253da85f8e 100644
--- a/units/getty@.service.m4
+++ b/units/getty@.service.m4
@@ -38,14 +38,11 @@ TTYVHangup=yes
TTYVTDisallocate=yes
KillMode=process
IgnoreSIGPIPE=no
+SendSIGHUP=yes
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=
-# Some login implementations ignore SIGTERM, so we send SIGHUP
-# instead, to ensure that login terminates cleanly.
-KillSignal=SIGHUP
-
[Install]
WantedBy=getty.target
diff --git a/units/rescue.service.m4.in b/units/rescue.service.m4.in
index 269797a12e..552ef8981b 100644
--- a/units/rescue.service.m4.in
+++ b/units/rescue.service.m4.in
@@ -25,7 +25,5 @@ StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
-
-# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
-# terminates cleanly.
-KillSignal=SIGHUP
+IgnoreSIGPIPE=no
+SendSIGHUP=yes
diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4
index 5e16963e92..e32c6b7aff 100644
--- a/units/serial-getty@.service.m4
+++ b/units/serial-getty@.service.m4
@@ -32,7 +32,4 @@ TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
-
-# Some login implementations ignore SIGTERM, so we send SIGHUP
-# instead, to ensure that login terminates cleanly.
-KillSignal=SIGHUP
+SendSIGHUP=yes