Merge pull request #6932 from poettering/notify-pam

fix handling of cgroup empty events for Type=notify services
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-10-02 14:40:10 +02:00 committed by GitHub
commit 81473e6f20
2 changed files with 35 additions and 13 deletions

View file

@ -936,7 +936,18 @@
<para>Note that for each unit making use of this option a PAM session handler process will be maintained as
part of the unit and stays around as long as the unit is active, to ensure that appropriate actions can be
taken when the unit and hence the PAM session terminates. This process is named <literal>(sd-pam)</literal> and
is an immediate child process of the unit's main process.</para></listitem>
is an immediate child process of the unit's main process.</para>
<para>Note that when this option is used for a unit it is very likely (depending on PAM configuration) that the
main unit process will be migrated to its own session scope unit when it is activated. This process will hence
be associated with two units: the unit it was originally started from (and for which
<varname>PAMName=</varname> was configured), and the session scope unit. Any child processes of that process
will however be associated with the session scope unit only. This has implications when used in combination
with <varname>NotifyAccess=</varname><option>all</option>, as these child processes will not be able to affect
changes in the original unit through notification messages. These messages will be considered belonging to the
session scope unit and not the original unit. It is hence not recommended to use <varname>PAMName=</varname> in
combination with <varname>NotifyAccess=</varname><option>all</option>.</para>
</listitem>
</varlistentry>
<varlistentry>

View file

@ -1401,8 +1401,7 @@ static int service_spawn(
static int main_pid_good(Service *s) {
assert(s);
/* Returns 0 if the pid is dead, 1 if it is good, -1 if we
* don't know */
/* Returns 0 if the pid is dead, > 0 if it is good, < 0 if we don't know */
/* If we know the pid file, then let's just check if it is
* still valid */
@ -1423,9 +1422,13 @@ static int main_pid_good(Service *s) {
return -EAGAIN;
}
_pure_ static int control_pid_good(Service *s) {
static int control_pid_good(Service *s) {
assert(s);
/* Returns 0 if the control PID is dead, > 0 if it is good. We never actually return < 0 here, but in order to
* make this function as similar as possible to main_pid_good() and cgroup_good(), we pretend that < 0 also
* means: we can't figure it out. */
return s->control_pid > 0;
}
@ -1434,6 +1437,9 @@ static int cgroup_good(Service *s) {
assert(s);
/* Returns 0 if the cgroup is empty or doesn't exist, > 0 if it is exists and is populated, < 0 if we can't
* figure it out */
if (!UNIT(s)->cgroup_path)
return 0;
@ -1441,7 +1447,7 @@ static int cgroup_good(Service *s) {
if (r < 0)
return r;
return !r;
return r == 0;
}
static bool service_shall_restart(Service *s) {
@ -2865,7 +2871,9 @@ static void service_notify_cgroup_empty_event(Unit *u) {
* SIGCHLD for. */
case SERVICE_START:
if (s->type == SERVICE_NOTIFY) {
if (s->type == SERVICE_NOTIFY &&
main_pid_good(s) == 0 &&
control_pid_good(s) == 0) {
/* No chance of getting a ready notification anymore */
service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL);
break;
@ -2874,7 +2882,10 @@ static void service_notify_cgroup_empty_event(Unit *u) {
/* Fall through */
case SERVICE_START_POST:
if (s->pid_file_pathspec) {
if (s->pid_file_pathspec &&
main_pid_good(s) == 0 &&
control_pid_good(s) == 0) {
/* Give up hoping for the daemon to write its PID file */
log_unit_warning(u, "Daemon never wrote its PID file. Failing.");
@ -2895,7 +2906,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
if (main_pid_good(s) <= 0 && !control_pid_good(s))
if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
service_enter_stop_post(s, SERVICE_SUCCESS);
break;
@ -2903,7 +2914,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
case SERVICE_STOP_POST:
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
if (main_pid_good(s) <= 0 && !control_pid_good(s))
if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
service_enter_dead(s, SERVICE_SUCCESS, true);
break;
@ -3040,7 +3051,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
if (!control_pid_good(s))
if (control_pid_good(s) <= 0)
service_enter_stop_post(s, f);
/* If there is still a control process, wait for that first */
@ -3050,7 +3061,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
if (!control_pid_good(s))
if (control_pid_good(s) <= 0)
service_enter_dead(s, f, true);
break;
@ -3131,7 +3142,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
r = service_load_pid_file(s, !has_start_post);
if (!has_start_post && r < 0) {
r = service_demand_pid_file(s);
if (r < 0 || !cgroup_good(s))
if (r < 0 || cgroup_good(s) == 0)
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL);
break;
}
@ -3153,7 +3164,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
r = service_load_pid_file(s, true);
if (r < 0) {
r = service_demand_pid_file(s);
if (r < 0 || !cgroup_good(s))
if (r < 0 || cgroup_good(s) == 0)
service_enter_stop(s, SERVICE_FAILURE_PROTOCOL);
break;
}