chiark / gitweb /
service: add StartLimitInterval/StartLimitBurst/StartLimitAction
authorMichael Olbrich <m.olbrich@pengutronix.de>
Thu, 9 Feb 2012 12:05:23 +0000 (13:05 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 Feb 2012 20:01:29 +0000 (21:01 +0100)
src/dbus-service.c
src/load-fragment-gperf.gperf.m4
src/load-fragment.c
src/load-fragment.h
src/service.c
src/service.h

index fedfc1d..7809164 100644 (file)
@@ -46,6 +46,9 @@
         "  <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"StartLimitAction\" type=\"s\" access=\"read\"/>\n" \
         BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
         BUS_EXEC_COMMAND_INTERFACE("ExecStart")                         \
         BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
@@ -101,6 +104,7 @@ static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, Se
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
 
 static const BusProperty bus_exec_main_status_properties[] = {
         { "ExecMainStartTimestamp",         bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime)  },
@@ -123,6 +127,9 @@ static const BusProperty bus_service_properties[] = {
         { "WatchdogUSec",           bus_property_append_usec,         "t", offsetof(Service, watchdog_usec)                },
         { "WatchdogTimestamp",      bus_property_append_usec,         "t", offsetof(Service, watchdog_timestamp.realtime)  },
         { "WatchdogTimestampMonotonic",bus_property_append_usec,      "t", offsetof(Service, watchdog_timestamp.monotonic) },
+        { "StartLimitInterval",     bus_property_append_usec,         "t", offsetof(Service, start_limit.interval)         },
+        { "StartLimitBurst",        bus_property_append_uint32,       "u", offsetof(Service, start_limit.burst)            },
+        { "StartLimitAction",       bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action)       },
         BUS_EXEC_COMMAND_PROPERTY("ExecStartPre",  offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]),  true ),
         BUS_EXEC_COMMAND_PROPERTY("ExecStart",     offsetof(Service, exec_command[SERVICE_EXEC_START]),      true ),
         BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
index 9708ff8..44ce4bb 100644 (file)
@@ -136,6 +136,9 @@ Service.ExecStopPost,            config_parse_exec,                  SERVICE_EXE
 Service.RestartSec,              config_parse_usec,                  0,                             offsetof(Service, restart_usec)
 Service.TimeoutSec,              config_parse_usec,                  0,                             offsetof(Service, timeout_usec)
 Service.WatchdogSec,             config_parse_usec,                  0,                             offsetof(Service, watchdog_usec)
+Service.StartLimitInterval,      config_parse_usec,                  0,                             offsetof(Service, start_limit.interval)
+Service.StartLimitBurst,         config_parse_unsigned,              0,                             offsetof(Service, start_limit.burst)
+Service.StartLimitAction,        config_parse_start_limit_action,    0,                             offsetof(Service, start_limit_action)
 Service.Type,                    config_parse_service_type,          0,                             offsetof(Service, type)
 Service.Restart,                 config_parse_service_restart,       0,                             offsetof(Service, restart)
 Service.PermissionsStartOnly,    config_parse_bool,                  0,                             offsetof(Service, permissions_start_only)
index b2d43fb..b963d7f 100644 (file)
@@ -1648,6 +1648,7 @@ int config_parse_unit_condition_null(
 }
 
 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
 
 int config_parse_unit_cgroup_attr(
                 const char *filename,
index fbb31f9..79fc76d 100644 (file)
@@ -76,6 +76,7 @@ int config_parse_unit_condition_string(const char *filename, unsigned line, cons
 int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_notify_access(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_start_limit_action(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
index 9ccb1b6..e782421 100644 (file)
@@ -23,7 +23,9 @@
 #include <signal.h>
 #include <dirent.h>
 #include <unistd.h>
+#include <sys/reboot.h>
 
+#include "manager.h"
 #include "unit.h"
 #include "service.h"
 #include "load-fragment.h"
@@ -125,7 +127,7 @@ static void service_init(Unit *u) {
 
         exec_context_init(&s->exec_context);
 
-        RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
+        RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
 
         s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
 }
@@ -2324,8 +2326,56 @@ fail:
         service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
 }
 
+static int service_start_limit_test(Service *s) {
+        assert(s);
+
+        if (ratelimit_test(&s->start_limit))
+                return 0;
+
+        switch (s->start_limit_action) {
+
+        case SERVICE_START_LIMIT_NONE:
+                log_warning("%s start request repeated too quickly, refusing to start.", UNIT(s)->id);
+                break;
+
+        case SERVICE_START_LIMIT_REBOOT: {
+                DBusError error;
+                int r;
+
+                dbus_error_init(&error);
+
+                log_warning("%s start request repeated too quickly, rebooting.", UNIT(s)->id);
+
+                r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
+                if (r < 0) {
+                        log_error("Failed to reboot: %s.", bus_error(&error, r));
+                        dbus_error_free(&error);
+                }
+
+                break;
+        }
+
+        case SERVICE_START_LIMIT_REBOOT_FORCE:
+                log_warning("%s start request repeated too quickly, force rebooting.", UNIT(s)->id);
+                UNIT(s)->manager->exit_code = MANAGER_REBOOT;
+                break;
+
+        case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
+                log_warning("%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
+                reboot(RB_AUTOBOOT);
+                break;
+
+        default:
+                log_error("start limit action=%i", s->start_limit_action);
+                assert_not_reached("Unknown StartLimitAction.");
+        }
+
+        return -ECANCELED;
+}
+
 static int service_start(Unit *u) {
         Service *s = SERVICE(u);
+        int r;
 
         assert(s);
 
@@ -2348,10 +2398,9 @@ static int service_start(Unit *u) {
         assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED || s->state == SERVICE_AUTO_RESTART);
 
         /* Make sure we don't enter a busy loop of some kind. */
-        if (!ratelimit_test(&s->ratelimit)) {
-                log_warning("%s start request repeated too quickly, refusing to start.", u->id);
-                return -ECANCELED;
-        }
+        r = service_start_limit_test(s);
+        if (r < 0)
+                return r;
 
         s->result = SERVICE_SUCCESS;
         s->reload_result = SERVICE_SUCCESS;
@@ -3665,6 +3714,14 @@ 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"
+};
+DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
+
 const UnitVTable service_vtable = {
         .suffix = ".service",
         .object_size = sizeof(Service),
index 02726ef..60b1051 100644 (file)
@@ -100,6 +100,15 @@ typedef enum ServiceResult {
         _SERVICE_RESULT_INVALID = -1
 } ServiceResult;
 
+typedef enum StartLimitAction {
+        SERVICE_START_LIMIT_NONE,
+        SERVICE_START_LIMIT_REBOOT,
+        SERVICE_START_LIMIT_REBOOT_FORCE,
+        SERVICE_START_LIMIT_REBOOT_IMMEDIATE,
+        _SERVICE_START_LIMIT_MAX,
+        _SERVICE_START_LIMIT_INVALID = -1
+} StartLimitAction;
+
 struct Service {
         Unit meta;
 
@@ -169,7 +178,9 @@ struct Service {
 
         char *status_text;
 
-        RateLimit ratelimit;
+        RateLimit start_limit;
+        StartLimitAction start_limit_action;
+
 
         UnitRef accept_socket;
 
@@ -203,4 +214,7 @@ NotifyAccess notify_access_from_string(const char *s);
 const char* service_result_to_string(ServiceResult i);
 ServiceResult service_result_from_string(const char *s);
 
+const char* start_limit_action_to_string(StartLimitAction i);
+StartLimitAction start_limit_action_from_string(const char *s);
+
 #endif