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