[systemd-devel] [PATCH V3] service: Support environment variable substition for PIDFile=
harald at redhat.com
harald at redhat.com
Wed Apr 10 07:32:17 PDT 2013
From: Harald Hoyer <harald at redhat.com>
This patch adds environment variable substition for PIDFile=. To read
the environment files only once, ExecContext holds a copy of the
environment gathered.
RFE: https://bugzilla.redhat.com/show_bug.cgi?id=840260
$ cat test.service
[Unit]
Description=test
[Service]
PIDFile=${PIDFILE}
EnvironmentFile=/etc/test-file
ExecStart=/bin/bash -c 'sleep 10000& jobs -p > $$PIDFILE; exit 0'
Type=forking
$ cat /etc/test-file
PIDFILE=/tmp/test.pid
$ systemctl status test.service
test.service - test
Loaded: loaded (/usr/lib/systemd/system/test.service; static)
Active: active (running) since Mi 2013-04-10 15:06:42 CEST; 2s ago
Process: 22407 ExecStart=/bin/bash -c sleep 10000& jobs -p > $$PIDFILE; exit 0 (code=exited, status=0/SUCCESS)
Main PID: 22408 (sleep)
CGroup: name=systemd:/system/test.service
└─22408 sleep 10000
Apr 10 15:06:42 lenovo systemd[1]: Started test.
---
man/systemd.service.xml | 3 +++
src/core/execute.c | 24 +++++++++++--------
src/core/execute.h | 1 +
src/core/load-fragment-gperf.gperf.m4 | 2 +-
src/core/service.c | 45 +++++++++++++++++++++++++++++++----
src/core/service.h | 1 +
6 files changed, 60 insertions(+), 16 deletions(-)
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index b82a5c1..14ce395 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -276,6 +276,9 @@
the daemon after start-up of the
service. systemd will not write to the
file configured here.</para>
+ <para>Basic environment variable
+ substitution is supported like in
+ <varname>ExecStart=</varname>.</para>
</listitem>
</varlistentry>
diff --git a/src/core/execute.c b/src/core/execute.c
index fabd38e..09fb49f 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -997,7 +997,6 @@ int exec_spawn(ExecCommand *command,
int r;
char *line;
int socket_fd;
- char _cleanup_strv_free_ **files_env = NULL;
assert(command);
assert(context);
@@ -1018,14 +1017,16 @@ int exec_spawn(ExecCommand *command,
} else
socket_fd = -1;
- r = exec_context_load_environment(context, &files_env);
- if (r < 0) {
- log_struct_unit(LOG_ERR,
- unit_id,
- "MESSAGE=Failed to load environment files: %s", strerror(-r),
- "ERRNO=%d", -r,
- NULL);
- return r;
+ if (!context->files_environment) {
+ r = exec_context_load_environment(context, &context->files_environment);
+ if (r < 0) {
+ log_struct_unit(LOG_ERR,
+ unit_id,
+ "MESSAGE=Failed to load environment files: %s", strerror(-r),
+ "ERRNO=%d", -r,
+ NULL);
+ return r;
+ }
}
if (!argv)
@@ -1498,7 +1499,7 @@ int exec_spawn(ExecCommand *command,
environment,
our_env,
context->environment,
- files_env,
+ context->files_environment,
pam_env,
NULL);
if (!final_env) {
@@ -1619,6 +1620,9 @@ void exec_context_done(ExecContext *c, bool reloading_or_reexecuting) {
strv_free(c->environment_files);
c->environment_files = NULL;
+ strv_free(c->files_environment);
+ c->files_environment = NULL;
+
for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
free(c->rlimit[l]);
c->rlimit[l] = NULL;
diff --git a/src/core/execute.h b/src/core/execute.h
index 3ce9221..1ba08a5 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -85,6 +85,7 @@ struct ExecCommand {
struct ExecContext {
char **environment;
char **environment_files;
+ char **files_environment;
struct rlimit *rlimit[RLIMIT_NLIMITS];
char *working_directory, *root_directory;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index d5e579f..4592f3d 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -140,7 +140,7 @@ Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_H
Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, 0
Unit.ConditionNull, config_parse_unit_condition_null, 0, 0
m4_dnl
-Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file)
+Service.PIDFile, config_parse_unit_string_printf, 0, offsetof(Service, pid_file)
Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command)
Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command)
Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command)
diff --git a/src/core/service.c b/src/core/service.c
index a104b30..00ac168 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -275,6 +275,9 @@ static void service_done(Unit *u) {
free(s->pid_file);
s->pid_file = NULL;
+ free(s->pid_file_env);
+ s->pid_file_env = NULL;
+
#ifdef HAVE_SYSV_COMPAT
free(s->sysv_runlevels);
s->sysv_runlevels = NULL;
@@ -703,7 +706,9 @@ static int service_load_sysv_path(Service *s, const char *path) {
}
free(s->pid_file);
+ free(s->pid_file_env);
s->pid_file = fn;
+ s->pid_file_env = NULL;
}
} else if (state == DESCRIPTION) {
@@ -1382,12 +1387,39 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (!s->pid_file)
return -ENOENT;
- r = read_one_line_file(s->pid_file, &k);
+ if (!s->pid_file_env) {
+ if (!s->exec_context.files_environment) {
+ r = exec_context_load_environment(&s->exec_context, &s->exec_context.files_environment);
+ if (r < 0) {
+ log_struct_unit(LOG_ERR,
+ UNIT(s)->id,
+ "MESSAGE=Failed to load environment files: %s", strerror(-r),
+ "ERRNO=%d", -r,
+ NULL);
+ }
+ }
+
+ if (s->exec_context.files_environment) {
+ char _cleanup_free_ **final_env = NULL;
+
+ final_env = strv_env_merge(2, s->exec_context.environment, s->exec_context.files_environment, NULL);
+ s->pid_file_env = replace_env(s->pid_file, final_env);
+ } else
+ s->pid_file_env = replace_env(s->pid_file, s->exec_context.environment);
+ }
+
+ if (!s->pid_file_env)
+ s->pid_file_env = strdup(s->pid_file);
+
+ if (!s->pid_file_env)
+ return -ENOMEM;
+
+ r = read_one_line_file(s->pid_file_env, &k);
if (r < 0) {
if (may_warn)
log_info_unit(UNIT(s)->id,
"PID file %s not readable (yet?) after %s.",
- s->pid_file, service_state_to_string(s->state));
+ s->pid_file_env, service_state_to_string(s->state));
return r;
}
@@ -1396,7 +1428,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (may_warn)
log_info_unit(UNIT(s)->id,
"Failed to read PID from file %s: %s",
- s->pid_file, strerror(-r));
+ s->pid_file_env, strerror(-r));
return r;
}
@@ -1404,7 +1436,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (may_warn)
log_info_unit(UNIT(s)->id,
"PID %lu read from file %s does not exist.",
- (unsigned long) pid, s->pid_file);
+ (unsigned long) pid, s->pid_file_env);
return -ESRCH;
}
@@ -2874,7 +2906,10 @@ static int service_demand_pid_file(Service *s) {
if (!ps)
return -ENOMEM;
- ps->path = strdup(s->pid_file);
+ if (s->pid_file_env)
+ ps->path = strdup(s->pid_file_env);
+ else
+ ps->path = strdup(s->pid_file);
if (!ps->path) {
free(ps);
return -ENOMEM;
diff --git a/src/core/service.h b/src/core/service.h
index d1e53bf..ae491a8 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -122,6 +122,7 @@ struct Service {
/* If set we'll read the main daemon PID from this file */
char *pid_file;
+ char *pid_file_env;
usec_t restart_usec;
usec_t timeout_start_usec;
--
1.8.2
More information about the systemd-devel
mailing list