[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