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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel