X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fservice.c;h=694a2658e9744beeb7ecff0031daa8a72d8c91b9;hp=67467b2d6d01a66cc14ac1072bf4474c60b24f42;hb=bf500566323bbc2240d1fdd1165a8c908faf4098;hpb=6a0f1f6d5af7c7300d3db7a0ba2b068f8abd222b diff --git a/src/core/service.c b/src/core/service.c index 67467b2d6..694a2658e 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "manager.h" #include "unit.h" @@ -300,6 +302,9 @@ static void service_done(Unit *u) { free(s->status_text); s->status_text = NULL; + free(s->reboot_arg); + s->reboot_arg = NULL; + s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX); s->control_command = NULL; @@ -664,13 +669,8 @@ static int service_load_sysv_path(Service *s, const char *path) { state = NORMAL; - if (sscanf(t+10, "%15s %i %*i", - runlevels, - &start_priority) != 2) { - - log_warning_unit(u->id, - "[%s:%u] Failed to parse chkconfig line. Ignoring.", - path, line); + if (sscanf(t+10, "%15s %i %*i", runlevels, &start_priority) != 2) { + log_warning_unit(u->id, "[%s:%u] Failed to parse chkconfig line. Ignoring.", path, line); continue; } @@ -678,19 +678,17 @@ static int service_load_sysv_path(Service *s, const char *path) { * symlink farms is preferred over the * data from the LSB header. */ if (start_priority < 0 || start_priority > 99) - log_warning_unit(u->id, - "[%s:%u] Start priority out of range. Ignoring.", - path, line); + log_warning_unit(u->id, "[%s:%u] Start priority out of range. Ignoring.", path, line); else - s->sysv_start_priority = start_priority; + log_debug_unit(u->id, "[%s:%u] Ignoring start priority set in the chkconfig file.", path, line); char_array_0(runlevels); k = delete_chars(runlevels, WHITESPACE "-"); - if (k[0]) { char *d; - if (!(d = strdup(k))) { + d = strdup(k); + if (!d) { r = -ENOMEM; goto finish; } @@ -992,9 +990,9 @@ static int service_load_sysv_path(Service *s, const char *path) { u->description = d; } - /* The priority that has been set in /etc/rcN.d/ hierarchies - * takes precedence over what is stored as default in the LSB - * header */ + /* Initialize the start priority from what has been set in the + * /etc/rcN.d/ hierarchies if we load the unit file as SysV + * init script. */ if (s->sysv_start_priority_from_rcnd >= 0) s->sysv_start_priority = s->sysv_start_priority_from_rcnd; @@ -1842,6 +1840,8 @@ static int cgroup_good(Service *s) { return !r; } +static int service_execute_action(Service *s, FailureAction action, const char *reason, bool log_action_none); + static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) { int r; assert(s); @@ -1851,6 +1851,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD); + if (s->result != SERVICE_SUCCESS) + service_execute_action(s, s->failure_action, "failed", false); + if (allow_restart && !s->forbid_restart && (s->restart == SERVICE_RESTART_ALWAYS || @@ -2373,26 +2376,27 @@ fail: service_enter_stop(s, SERVICE_FAILURE_RESOURCES); } -static int service_start_limit_test(Service *s) { +static int service_execute_action(Service *s, FailureAction action, const char *reason, bool log_action_none) { assert(s); - if (ratelimit_test(&s->start_limit)) - return 0; + if (action == SERVICE_FAILURE_ACTION_REBOOT || + action == SERVICE_FAILURE_ACTION_REBOOT_FORCE) + update_reboot_param_file(s->reboot_arg); - switch (s->start_limit_action) { + switch (action) { - case SERVICE_START_LIMIT_NONE: - log_warning_unit(UNIT(s)->id, - "%s start request repeated too quickly, refusing to start.", - UNIT(s)->id); + case SERVICE_FAILURE_ACTION_NONE: + if (log_action_none) + log_warning_unit(UNIT(s)->id, + "%s %s, refusing to start.", UNIT(s)->id, reason); break; - case SERVICE_START_LIMIT_REBOOT: { + case SERVICE_FAILURE_ACTION_REBOOT: { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; log_warning_unit(UNIT(s)->id, - "%s start request repeated too quickly, rebooting.", UNIT(s)->id); + "%s %s, rebooting.", UNIT(s)->id, reason); r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, @@ -2404,28 +2408,44 @@ static int service_start_limit_test(Service *s) { break; } - case SERVICE_START_LIMIT_REBOOT_FORCE: + case SERVICE_FAILURE_ACTION_REBOOT_FORCE: log_warning_unit(UNIT(s)->id, - "%s start request repeated too quickly, forcibly rebooting.", UNIT(s)->id); + "%s %s, forcibly rebooting.", UNIT(s)->id, reason); UNIT(s)->manager->exit_code = MANAGER_REBOOT; break; - case SERVICE_START_LIMIT_REBOOT_IMMEDIATE: + case SERVICE_FAILURE_ACTION_REBOOT_IMMEDIATE: log_warning_unit(UNIT(s)->id, - "%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id); + "%s %s, rebooting immediately.", UNIT(s)->id, reason); sync(); + if (s->reboot_arg) { + log_info("Rebooting with argument '%s'.", s->reboot_arg); + syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, s->reboot_arg); + } + + log_info("Rebooting."); reboot(RB_AUTOBOOT); break; default: log_error_unit(UNIT(s)->id, - "start limit action=%i", s->start_limit_action); - assert_not_reached("Unknown StartLimitAction."); + "failure action=%i", action); + assert_not_reached("Unknown FailureAction."); } return -ECANCELED; } +static int service_start_limit_test(Service *s) { + assert(s); + + if (ratelimit_test(&s->start_limit)) + return 0; + + return service_execute_action(s, s->start_limit_action, "start request repeated too quickly", true); +} + static int service_start(Unit *u) { Service *s = SERVICE(u); int r; @@ -3812,13 +3832,13 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = { DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); -static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = { - [SERVICE_START_LIMIT_NONE] = "none", - [SERVICE_START_LIMIT_REBOOT] = "reboot", - [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force", - [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate" +static const char* const failure_action_table[_SERVICE_FAILURE_ACTION_MAX] = { + [SERVICE_FAILURE_ACTION_NONE] = "none", + [SERVICE_FAILURE_ACTION_REBOOT] = "reboot", + [SERVICE_FAILURE_ACTION_REBOOT_FORCE] = "reboot-force", + [SERVICE_FAILURE_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate" }; -DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction); +DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction); const UnitVTable service_vtable = { .object_size = sizeof(Service),