diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index f0b48e4a41..06ae6b3252 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -936,7 +936,18 @@ 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 (sd-pam) and - is an immediate child process of the unit's main process. + is an immediate child process of the unit's main process. + + 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 + PAMName= 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 NotifyAccess=, 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 PAMName= in + combination with NotifyAccess=. + diff --git a/src/core/service.c b/src/core/service.c index 1a4455bd22..ffbfc5c459 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -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; }