diff options
Diffstat (limited to 'src/core/service.c')
-rw-r--r-- | src/core/service.c | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/src/core/service.c b/src/core/service.c index 180854b57c..61246d831d 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1179,6 +1179,25 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) { return rn_fds; } +static bool service_exec_needs_notify_socket(Service *s, ExecFlags flags) { + assert(s); + + /* Notifications are accepted depending on the process and + * the access setting of the service: + * process: \ access: NONE MAIN EXEC ALL + * main no yes yes yes + * control no no yes yes + * other (forked) no no no yes */ + + if (flags & EXEC_IS_CONTROL) + /* A control process */ + return IN_SET(s->notify_access, NOTIFY_EXEC, NOTIFY_ALL); + + /* We only spawn main processes and control processes, so any + * process that is not a control process is a main process */ + return s->notify_access != NOTIFY_NONE; +} + static int service_spawn( Service *s, ExecCommand *c, @@ -1252,7 +1271,7 @@ static int service_spawn( if (!our_env) return -ENOMEM; - if ((flags & EXEC_IS_CONTROL) ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE) + if (service_exec_needs_notify_socket(s, flags)) if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) return -ENOMEM; @@ -1695,7 +1714,7 @@ static void service_enter_running(Service *s, ServiceResult f) { } } else if (f != SERVICE_SUCCESS) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); else if (s->remain_after_exit) service_set_state(s, SERVICE_EXITED); else @@ -1832,7 +1851,7 @@ static void service_enter_start(Service *s) { fail: log_unit_warning_errno(UNIT(s), r, "Failed to run 'start' task: %m"); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); } static void service_enter_start_pre(Service *s) { @@ -1978,9 +1997,7 @@ static void service_run_next_control(Service *s) { fail: log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m"); - if (s->state == SERVICE_START_PRE) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); - else if (s->state == SERVICE_STOP) + if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_STOP)) service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); else if (s->state == SERVICE_STOP_POST) service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); @@ -2579,17 +2596,22 @@ static void service_notify_cgroup_empty_event(Unit *u) { * SIGCHLD for. */ case SERVICE_START: - case SERVICE_START_POST: - if (s->type == SERVICE_NOTIFY) + if (s->type == SERVICE_NOTIFY) { /* No chance of getting a ready notification anymore */ - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); - else if (s->pid_file_pathspec) { + service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL); + break; + } + + /* Fall through */ + + case SERVICE_START_POST: + if (s->pid_file_pathspec) { /* Give up hoping for the daemon to write its PID file */ log_unit_warning(u, "Daemon never wrote its PID file. Failing."); service_unwatch_pid_file(s); if (s->state == SERVICE_START) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL); else service_enter_stop(s, SERVICE_FAILURE_PROTOCOL); } @@ -2723,17 +2745,17 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (f == SERVICE_SUCCESS) service_enter_start_post(s); else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; } else if (s->type == SERVICE_NOTIFY) { /* Only enter running through a notification, so that the * SERVICE_START state signifies that no ready notification * has been received */ if (f != SERVICE_SUCCESS) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); else if (!s->remain_after_exit) /* The service has never been active */ - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL); break; } @@ -2813,7 +2835,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (f == SERVICE_SUCCESS) service_enter_start(s); else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; case SERVICE_START: @@ -2822,7 +2844,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; if (f != SERVICE_SUCCESS) { - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; } @@ -2839,7 +2861,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (!has_start_post && r < 0) { r = service_demand_pid_file(s); if (r < 0 || !cgroup_good(s)) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL); break; } } else @@ -2935,7 +2957,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us case SERVICE_START_PRE: case SERVICE_START: log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", s->state == SERVICE_START ? "Start" : "Start-pre"); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_START_POST: @@ -3056,7 +3078,18 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) if (s->main_pid != 0) log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid); else - log_unit_debug(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid); + log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid); + return; + } else if (s->notify_access == NOTIFY_EXEC && pid != s->main_pid && pid != s->control_pid) { + if (s->main_pid != 0 && s->control_pid != 0) + log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT" and control PID "PID_FMT, + pid, s->main_pid, s->control_pid); + else if (s->main_pid != 0) + log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid); + else if (s->control_pid != 0) + log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for control PID "PID_FMT, pid, s->control_pid); + else + log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID and control PID which are currently not known", pid); return; } else log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", pid, isempty(cc) ? "n/a" : cc); @@ -3066,6 +3099,8 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) { if (parse_pid(e, &pid) < 0) log_unit_warning(u, "Failed to parse MAINPID= field in notification message: %s", e); + else if (pid == s->control_pid) + log_unit_warning(u, "A control process cannot also be the main process"); else { service_set_main_pid(s, pid); unit_watch_pid(UNIT(s), pid); @@ -3381,6 +3416,7 @@ DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand); static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { [NOTIFY_NONE] = "none", [NOTIFY_MAIN] = "main", + [NOTIFY_EXEC] = "exec", [NOTIFY_ALL] = "all" }; |