X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fservice.c;h=1e3e875c3fd36dde473baeef694733184537cb33;hp=1c127bdbcb2ffc5c6926d210a63d278ea90078a8;hb=41f9172f427bdbb8221c64029f78364b8dd4e527;hpb=956b78e8e3636bbf04e264ca96128edc2cbf3626 diff --git a/src/core/service.c b/src/core/service.c index 1c127bdbc..1e3e875c3 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -33,6 +33,7 @@ #include "log.h" #include "strv.h" #include "unit-name.h" +#include "unit-printf.h" #include "dbus-service.h" #include "special.h" #include "bus-errors.h" @@ -134,7 +135,8 @@ static void service_init(Unit *u) { assert(u); assert(u->load_state == UNIT_STUB); - s->timeout_usec = DEFAULT_TIMEOUT_USEC; + s->timeout_start_usec = DEFAULT_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_TIMEOUT_USEC; s->restart_usec = DEFAULT_RESTART_USEC; s->type = _SERVICE_TYPE_INVALID; @@ -293,6 +295,16 @@ static void service_done(Unit *u) { s->control_command = NULL; s->main_command = NULL; + set_free(s->restart_ignore_status.code); + s->restart_ignore_status.code = NULL; + set_free(s->restart_ignore_status.signal); + s->restart_ignore_status.signal = NULL; + + set_free(s->success_status.code); + s->success_status.code = NULL; + set_free(s->success_status.signal); + s->success_status.signal = NULL; + /* This will leak a process, but at least no memory or any of * our resources */ service_unwatch_main_pid(s); @@ -914,9 +926,12 @@ static int service_load_sysv_path(Service *s, const char *path) { UNIT(s)->default_dependencies = false; /* Don't timeout special services during boot (like fsck) */ - s->timeout_usec = 0; - } else - s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_start_usec = 0; + s->timeout_stop_usec = 0; + } else { + s->timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC; + } /* Special setting for all SysV services */ s->type = SERVICE_FORKING; @@ -1241,9 +1256,9 @@ static int service_load(Unit *u) { if (s->type == _SERVICE_TYPE_INVALID) s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE; - /* Oneshot services have disabled timeout by default */ - if (s->type == SERVICE_ONESHOT && !s->timeout_defined) - s->timeout_usec = 0; + /* Oneshot services have disabled start timeout by default */ + if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined) + s->timeout_start_usec = 0; service_fix_output(s); @@ -1603,11 +1618,10 @@ static int service_coldplug(Unit *u) { s->deserialized_state == SERVICE_FINAL_SIGTERM || s->deserialized_state == SERVICE_FINAL_SIGKILL || s->deserialized_state == SERVICE_AUTO_RESTART) { - - if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) { + if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_start_usec > 0) { usec_t k; - k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec; + k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_start_usec; if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0) return r; @@ -1753,8 +1767,9 @@ static int service_spawn( } } - if (timeout && s->timeout_usec) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + if (timeout && s->timeout_start_usec) { + r = unit_watch_timer(UNIT(s), s->timeout_start_usec, &s->timer_watch); + if (r < 0) goto fail; } else unit_unwatch_timer(UNIT(s), &s->timer_watch); @@ -1897,7 +1912,12 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) || (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) || (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL || - s->result == SERVICE_FAILURE_CORE_DUMP)))) { + s->result == SERVICE_FAILURE_CORE_DUMP))) && + (s->result != SERVICE_FAILURE_EXIT_CODE || + !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) && + (s->result != SERVICE_FAILURE_SIGNAL || + !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status))) + ) { r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch); if (r < 0) @@ -2011,9 +2031,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f } if (wait_for_exit) { - if (s->timeout_usec > 0) - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + if (s->timeout_stop_usec > 0) { + r = unit_watch_timer(UNIT(s), s->timeout_stop_usec, &s->timer_watch); + if (r < 0) goto fail; + } service_set_state(s, state); } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) @@ -2486,7 +2508,7 @@ static int service_start(Unit *u) { /* Make sure we don't enter a busy loop of some kind. */ r = service_start_limit_test(s); if (r < 0) { - service_notify_sockets_dead(s, true); + service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false); return r; } @@ -2867,7 +2889,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { assert(s); assert(pid >= 0); - if (UNIT(s)->fragment_path ? is_clean_exit(code, status) : is_clean_exit_lsb(code, status)) + if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) : + is_clean_exit_lsb(code, status, &s->success_status)) f = SERVICE_SUCCESS; else if (code == CLD_EXITED) f = SERVICE_FAILURE_EXIT_CODE; @@ -2938,12 +2961,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { else service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); break; - } else { - assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY); - - /* Fall through */ } + /* Fall through */ + case SERVICE_RUNNING: service_enter_running(s, f); break; @@ -3013,7 +3034,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case SERVICE_START: - assert(s->type == SERVICE_FORKING); + if (s->type != SERVICE_FORKING) + /* Maybe spurious event due to a reload that changed the type? */ + break; if (f != SERVICE_SUCCESS) { service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); @@ -3798,7 +3821,8 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = { [SERVICE_FAILURE_EXIT_CODE] = "exit-code", [SERVICE_FAILURE_SIGNAL] = "signal", [SERVICE_FAILURE_CORE_DUMP] = "core-dump", - [SERVICE_FAILURE_WATCHDOG] = "watchdog" + [SERVICE_FAILURE_WATCHDOG] = "watchdog", + [SERVICE_FAILURE_START_LIMIT] = "start-limit" }; DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);