chiark / gitweb /
service: rename StartLimitAction enum to FailureAction
[elogind.git] / src / core / service.c
index 67467b2d6d01a66cc14ac1072bf4474c60b24f42..694a2658e9744beeb7ecff0031daa8a72d8c91b9 100644 (file)
@@ -24,6 +24,8 @@
 #include <dirent.h>
 #include <unistd.h>
 #include <sys/reboot.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <sys/reboot.h>
+#include <linux/reboot.h>
+#include <sys/syscall.h>
 
 #include "manager.h"
 #include "unit.h"
 
 #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->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;
         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;
 
 
                                 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;
                                 }
 
                                         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)
                                  * 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
                                 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 "-");
 
                                 char_array_0(runlevels);
                                 k = delete_chars(runlevels, WHITESPACE "-");
-
                                 if (k[0]) {
                                         char *d;
 
                                 if (k[0]) {
                                         char *d;
 
-                                        if (!(d = strdup(k))) {
+                                        d = strdup(k);
+                                        if (!d) {
                                                 r = -ENOMEM;
                                                 goto finish;
                                         }
                                                 r = -ENOMEM;
                                                 goto finish;
                                         }
@@ -992,9 +990,9 @@ static int service_load_sysv_path(Service *s, const char *path) {
                 u->description = d;
         }
 
                 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;
 
         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;
 }
 
         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);
 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);
 
 
         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 ||
         if (allow_restart &&
             !s->forbid_restart &&
             (s->restart == SERVICE_RESTART_ALWAYS ||
@@ -2373,26 +2376,27 @@ fail:
         service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
 }
 
         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);
 
         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;
 
                 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,
                 _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,
 
                 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;
         }
 
                 break;
         }
 
-        case SERVICE_START_LIMIT_REBOOT_FORCE:
+        case SERVICE_FAILURE_ACTION_REBOOT_FORCE:
                 log_warning_unit(UNIT(s)->id,
                 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;
 
                 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,
                 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();
                 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,
                 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;
 }
 
         }
 
         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;
 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);
 
 
 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),
 
 const UnitVTable service_vtable = {
         .object_size = sizeof(Service),