[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