[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