[systemd-devel] [PATCH] service: allow service to inhibit respawn with special return code

Lukas Nykryn lnykryn at redhat.com
Tue Jul 24 07:43:53 PDT 2012


In some cases, like wrong configuration, restarting after error
exit code does not help, so administrator can specify RestartIgnoreCodes
which will not cause restart of a service.
---
 man/systemd.service.xml               |    7 ++++
 src/core/load-fragment-gperf.gperf.m4 |    1 +
 src/core/load-fragment.c              |   59 +++++++++++++++++++++++++++++++++
 src/core/load-fragment.h              |    1 +
 src/core/service.c                    |   16 ++++++++-
 src/core/service.h                    |    2 +
 6 files changed, 85 insertions(+), 1 deletions(-)

diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index f43201d..6b724ea 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -558,6 +558,13 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><varname>RestartIgnoreCodes=</varname></term>
+                                <listitem><para>Specify return codes list, which
+                                will prevent service from restart. Codes are
+                                separated by whitespace.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><varname>PermissionsStartOnly=</varname></term>
                                 <listitem><para>Takes a boolean
                                 argument. If true, the permission
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index d6a4711..ff40a64 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -151,6 +151,7 @@ Service.StartLimitBurst,         config_parse_unsigned,              0,
 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.RestartIgnoreCodes,      config_parse_service_restart_ignore, 0,                             offsetof(Service, restart_ignored_codes)
 Service.PermissionsStartOnly,    config_parse_bool,                  0,                             offsetof(Service, permissions_start_only)
 Service.RootDirectoryStartOnly,  config_parse_bool,                  0,                             offsetof(Service, root_directory_start_only)
 Service.RemainAfterExit,         config_parse_bool,                  0,                             offsetof(Service, remain_after_exit)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index bbd82b9..fa002e8 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2084,6 +2084,65 @@ int config_parse_syscall_filter(
         return 0;
 }
 
+int config_parse_service_restart_ignore(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char *w;
+        unsigned k=0;
+        size_t l;
+        char *state;
+        int r;
+        int **ignored = data;
+        Service *s = userdata;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+        assert(userdata);
+
+        FOREACH_WORD(w, l, rvalue, state)
+                k++;
+
+        if (*ignored) {
+                s->n_restart_ignored_codes = 0;
+                free(*ignored);
+                *ignored = NULL;
+        }
+
+        *ignored = new(int, k);
+        if (!*ignored)
+                return -ENOMEM;
+
+        s->n_restart_ignored_codes = k;
+
+        k=0;
+        FOREACH_WORD(w, l, rvalue, state){
+                char *temp = new0(char, l+1);
+                if (!temp)
+                        return -ENOMEM;
+                strncpy(temp, w, l);
+                if ((r = safe_atoi(temp, &(*ignored)[k++])) < 0) {
+                        log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, w);
+                        s->n_restart_ignored_codes = 0;
+                        free(*ignored);
+                        *ignored = NULL;
+                        free(temp);
+                        return r;
+                }
+                free(temp);
+        }
+
+        return 0;
+}
+
 #define FOLLOW_MAX 8
 
 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 24f7384..1064e95 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -82,6 +82,7 @@ int config_parse_unit_blkio_weight(const char *filename, unsigned line, const ch
 int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_requires_mounts_for(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_syscall_filter(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_service_restart_ignore(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
diff --git a/src/core/service.c b/src/core/service.c
index 1c127bd..ead59af 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -288,6 +288,9 @@ static void service_done(Unit *u) {
         free(s->status_text);
         s->status_text = NULL;
 
+        free(s->restart_ignored_codes);
+        s->restart_ignored_codes = NULL;
+
         exec_context_done(&s->exec_context);
         exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
         s->control_command = NULL;
@@ -1882,6 +1885,16 @@ static int cgroup_good(Service *s) {
         return !r;
 }
 
+static int check_ignored_rc(Service *s){
+        int i;
+        assert(s);
+
+        for (i = 0; i < s->n_restart_ignored_codes; i++)
+                if(s->main_exec_status.status == s->restart_ignored_codes[i])
+                        return 1;
+        return 0;
+}
+
 static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
         int r;
         assert(s);
@@ -1897,7 +1910,8 @@ 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 || !check_ignored_rc(s))) {
 
                 r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
                 if (r < 0)
diff --git a/src/core/service.h b/src/core/service.h
index cc63347..d67a519 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -115,6 +115,8 @@ struct Service {
 
         ServiceType type;
         ServiceRestart restart;
+        int *restart_ignored_codes;
+        int n_restart_ignored_codes;
 
         /* If set we'll read the main daemon PID from this file */
         char *pid_file;
-- 
1.7.6.5



More information about the systemd-devel mailing list