core: optionally send SIGHUP in addition to the configured kill signal

This is useful to fake session ends for processes like shells.
This commit is contained in:
Lennart Poettering 2013-07-30 01:54:59 +02:00
parent 5a4555ba6b
commit 82659fd757
13 changed files with 97 additions and 68 deletions

View File

@ -115,16 +115,21 @@
<option>control-group</option>.</para>
<para>Processes will first be
terminated via <constant>SIGTERM</constant> (unless the
signal to send is changed via
<varname>KillSignal=</varname>). If
terminated via
<constant>SIGTERM</constant> (unless
the signal to send is changed via
<varname>KillSignal=</varname>). Optionally,
this is immediately followed by a
<constant>SIGHUP</constant> (if
enabled with
<varname>SendSIGHUP=</varname>). If
then after a delay (configured via the
<varname>TimeoutSec=</varname> option)
<varname>TimeoutStopSec=</varname> option)
processes still remain, the
termination request is repeated with
the <constant>SIGKILL</constant> signal (unless this is
disabled via the
<varname>SendSIGKILL=</varname>
the <constant>SIGKILL</constant>
signal (unless this is disabled via
the <varname>SendSIGKILL=</varname>
option). See
<citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for more
@ -139,6 +144,20 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SendSIGHUP=</varname></term>
<listitem><para>Specifies whether to
send <constant>SIGHUP</constant> to
remaining processes immediately after
sending the signal configured with
<varname>KillSignal=</varname>. This
is useful to indicate to shells and
shell-like programs that their
connection has been severed. Takes a
boolean value. Defaults to "no".
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SendSIGKILL=</varname></term>
<listitem><para>Specifies whether to
@ -149,6 +168,7 @@
value. Defaults to "yes".
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

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

View File

@ -29,10 +29,8 @@
#define BUS_KILL_CONTEXT_INTERFACE \
" <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
" <property name=\"SendSIGKILL\" type=\"b\" access=\"read\"/>\n"
#define BUS_KILL_COMMAND_INTERFACE(name) \
" <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
" <property name=\"SendSIGKILL\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"SendSIGHUP\" type=\"b\" access=\"read\"/>\n"
extern const BusProperty bus_kill_context_properties[];

View File

@ -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] = {

View File

@ -41,6 +41,7 @@ struct KillContext {
KillMode kill_mode;
int kill_signal;
bool send_sigkill;
bool send_sighup;
};
typedef enum KillWho {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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