[systemd-devel] [PATCH] service: ExecConfigTest command to test config before startup/restart/reloading of service.

Mirco Tischler mt-ml at gmx.de
Tue Jan 11 07:56:40 PST 2011


The ExecConfigTest command is trigerred before each ExecStart/Pre,
ExecReload
and ExecRestart command and the execution of those commands is denied when
the ExecConfigTest fails.
---
 src/load-fragment.c |    1 +
 src/service.c       |   52
+++++++++++++++++++++++++++++++++++++++++++++++++++
 src/service.h       |    2 +
 3 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/src/load-fragment.c b/src/load-fragment.c
index 261180d..b268f81 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1853,6 +1853,7 @@ static int load_from_path(Unit *u, const char *path) {
                 { "ExecReload",            
config_parse_exec,           
u->service.exec_command+SERVICE_EXEC_RELOAD,     "Service" },
                 { "ExecStop",              
config_parse_exec,           
u->service.exec_command+SERVICE_EXEC_STOP,       "Service" },
                 { "ExecStopPost",          
config_parse_exec,           
u->service.exec_command+SERVICE_EXEC_STOP_POST,  "Service" },
+                { "ExecConfigTest",        
config_parse_exec,           
u->service.exec_command+SERVICE_EXEC_CONFIG_TEST,"Service" },
                 { "RestartSec",            
config_parse_usec,           
&u->service.restart_usec,                        "Service" },
                 { "TimeoutSec",            
config_parse_usec,           
&u->service.timeout_usec,                        "Service" },
                 { "Type",                  
config_parse_service_type,   
&u->service.type,                                "Service" },
diff --git a/src/service.c b/src/service.c
index a28eb8a..829bd5a 100644
--- a/src/service.c
+++ b/src/service.c
@@ -1941,6 +1941,27 @@ static void service_enter_running(Service *s,
bool success) {
                 service_enter_stop(s, true);
 }
 
+static int service_enter_config_test(Service *s) {
+        int r = 0;
+
+        assert(s);
+
+        s->control_command_id = SERVICE_EXEC_CONFIG_TEST;
+        if ((s->control_command =
s->exec_command[SERVICE_EXEC_CONFIG_TEST]))
+                 if((r = service_spawn(s,
+                                       s->control_command,
+                                       true,
+                                       false,
+                                       !s->permissions_start_only,
+                                       !s->root_directory_start_only,
+                                       false,
+                                       false,
+                                       &s->control_pid) < 0))
+                         service_set_state(s, SERVICE_CONFIG_TEST);
+
+        return r;
+}
+
 static void service_enter_start_post(Service *s) {
         int r;
         assert(s);
@@ -1980,6 +2001,13 @@ static void service_enter_start(Service *s) {
         assert(s->exec_command[SERVICE_EXEC_START]);
         assert(!s->exec_command[SERVICE_EXEC_START]->command_next ||
s->type == SERVICE_ONESHOT);
 
+        if(s->exec_command[SERVICE_EXEC_CONFIG_TEST] &&
!s->exec_command[SERVICE_EXEC_START_PRE]) {
+                if((r = service_enter_config_test(s) < 0)) {
+                                log_warning("%s failed config test, not
starting: %s", s->meta.id, strerror(-r));
+                                goto fail;
+                }
+         }
+
         if (s->type == SERVICE_FORKING)
                 service_unwatch_control_pid(s);
         else
@@ -2044,6 +2072,13 @@ static void service_enter_start_pre(Service *s) {
 
         service_unwatch_control_pid(s);
 
+        if(s->exec_command[SERVICE_EXEC_CONFIG_TEST]) {
+                if((r = service_enter_config_test(s) < 0)) {
+                        log_warning("%s failed config test, not
reloading: %s", s->meta.id, strerror(-r));
+                        goto fail;
+                }
+        }
+
         s->control_command_id = SERVICE_EXEC_START_PRE;
         if ((s->control_command =
s->exec_command[SERVICE_EXEC_START_PRE])) {
                 if ((r = service_spawn(s,
@@ -2082,6 +2117,15 @@ static void service_enter_restart(Service *s) {
                         goto fail;
         }
 
+        if(s->exec_command[SERVICE_EXEC_CONFIG_TEST]) {
+                        if((r = service_enter_config_test(s) < 0)) {
+                                log_warning("%s failed config test, not
restarting: %s", s->meta.id, strerror(-r));
+                                service_enter_running(s, true);
+                                return;
+                        }
+                }
+
+
         service_enter_dead(s, true, false);
 
         if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s),
JOB_FAIL, false, &error, NULL)) < 0)
@@ -2102,6 +2146,14 @@ static void service_enter_reload(Service *s) {
 
         assert(s);
 
+        if(s->exec_command[SERVICE_EXEC_CONFIG_TEST]){
+                if((r = service_enter_config_test(s) < 0)) {
+                        log_warning("%s failed config test, not
reloading: %s", s->meta.id, strerror(-r));
+                        service_enter_running(s, true);
+                        return;
+                }
+        }
+
         service_unwatch_control_pid(s);
 
         s->control_command_id = SERVICE_EXEC_RELOAD;
diff --git a/src/service.h b/src/service.h
index 500bebf..df2a218 100644
--- a/src/service.h
+++ b/src/service.h
@@ -35,6 +35,7 @@ typedef enum ServiceState {
         SERVICE_RUNNING,
         SERVICE_EXITED,            /* Nothing is running anymore, but
RemainAfterExit is true, ehnce this is OK */
         SERVICE_RELOAD,
+        SERVICE_CONFIG_TEST,
         SERVICE_STOP,              /* No STOP_PRE state, instead just
register multiple STOP executables */
         SERVICE_STOP_SIGTERM,
         SERVICE_STOP_SIGKILL,
@@ -74,6 +75,7 @@ typedef enum ServiceExecCommand {
         SERVICE_EXEC_RELOAD,
         SERVICE_EXEC_STOP,
         SERVICE_EXEC_STOP_POST,
+        SERVICE_EXEC_CONFIG_TEST,
         _SERVICE_EXEC_COMMAND_MAX,
         _SERVICE_EXEC_COMMAND_INVALID = -1
 } ServiceExecCommand;
-- 1.7.3.4


More information about the systemd-devel mailing list