[systemd-devel] [PATCH] Added support for EnvironmentDir

Pekka Lundstrom pekka.lundstrom at jollamobile.com
Mon Dec 10 05:56:15 PST 2012


Signed-off-by: Pekka Lundstrom <pekka.lundstrom at jollamobile.com>
---
 man/systemd.exec.xml                  |   27 ++++++++
 src/core/dbus-execute.c               |   33 ++++++++++
 src/core/dbus-execute.h               |    1 +
 src/core/execute.c                    |  116 ++++++++++++++++++++++++++++++++-
 src/core/execute.h                    |    4 +-
 src/core/load-fragment-gperf.gperf.m4 |    1 +
 src/core/load-fragment.c              |   15 +++++
 src/core/load-fragment.h              |    1 +
 src/systemctl/systemctl.c             |   18 +++++
 9 files changed, 212 insertions(+), 4 deletions(-)

diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 6ca7405..0d0131b 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -307,6 +307,33 @@
                                 later setting will override the
                                 earlier setting. </para></listitem>
                         </varlistentry>
+                        <varlistentry>
+                                <term><varname>EnvironmentDir=</varname></term>
+                                <listitem><para>Similar to
+                                <varname>EnvironmentFile=</varname> but
+                                reads the environment variables from a
+                                directory containing files. Each file in
+                                that directory named with ".conf" suffix
+                                is read and prosessed and these files
+                                should follow same syntax as files
+                                listed with <varname>EnvironmentFile=</varname>.
+                                The argument passed should be an absolute
+                                path to the directory, optionally prefixed with
+                                "-", which indicates that if the directory
+                                does not exist it won't be read and no
+                                error or warning message is
+                                logged. Same goes for files in that directory.
+                                The directories listed with this
+                                directive will be read shortly before
+                                the process is executed. Settings from
+                                these files override settings made
+                                with <varname>EnvironmentFile=</varname>.
+                                If the same variable is set twice from
+                                these directories the directories will be read in
+                                the order they are specified and the
+                                later setting will override the
+                                earlier setting. </para></listitem>
+                        </varlistentry>
 
                         <varlistentry>
                                 <term><varname>StandardInput=</varname></term>
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index e815cb5..9e5167e 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -65,6 +65,38 @@ int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void
         return 0;
 }
 
+int bus_execute_append_env_dirs(DBusMessageIter *i, const char *property, void *data) {
+        char **env_dirs = data, **j;
+        DBusMessageIter sub, sub2;
+
+        assert(i);
+        assert(property);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
+                return -ENOMEM;
+
+        STRV_FOREACH(j, env_dirs) {
+                dbus_bool_t b = false;
+                char *dname = *j;
+
+                if (dname[0] == '-') {
+                        b = true;
+                        dname++;
+                }
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &dname) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
 int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
         ExecContext *c = data;
         int32_t n;
@@ -376,6 +408,7 @@ int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property,
 const BusProperty bus_exec_context_properties[] = {
         { "Environment",              bus_property_append_strv,             "as", offsetof(ExecContext, environment),            true },
         { "EnvironmentFiles",         bus_execute_append_env_files,      "a(sb)", offsetof(ExecContext, environment_files),      true },
+        { "EnvironmentDirs",          bus_execute_append_env_dirs,       "a(sb)", offsetof(ExecContext, environment_dirs),       true },
         { "UMask",                    bus_property_append_mode,              "u", offsetof(ExecContext, umask)                        },
         { "LimitCPU",                 bus_execute_append_rlimits,            "t", 0 },
         { "LimitFSIZE",               bus_execute_append_rlimits,            "t", 0 },
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
index eaa1b73..8bd3fb6 100644
--- a/src/core/dbus-execute.h
+++ b/src/core/dbus-execute.h
@@ -121,4 +121,5 @@ int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, v
 int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data);
 int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_env_dirs(DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data);
diff --git a/src/core/execute.c b/src/core/execute.c
index 7628470..9dfecc7 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1001,6 +1001,7 @@ int exec_spawn(ExecCommand *command,
         char *line;
         int socket_fd;
         char _cleanup_strv_free_ **files_env = NULL;
+        char _cleanup_strv_free_ **dirs_env = NULL;
 
         assert(command);
         assert(context);
@@ -1021,7 +1022,7 @@ int exec_spawn(ExecCommand *command,
         } else
                 socket_fd = -1;
 
-        r = exec_context_load_environment(context, &files_env);
+        r = exec_context_load_files_environment(context, &files_env);
         if (r < 0) {
                 log_struct(LOG_ERR,
                            "UNIT=%s", unit_id,
@@ -1031,6 +1032,16 @@ int exec_spawn(ExecCommand *command,
                 return r;
         }
 
+        r = exec_context_load_dirs_environment(context, &dirs_env);
+        if (r < 0) {
+                log_struct(LOG_ERR,
+                           "UNIT=%s", unit_id,
+                           "MESSAGE=Failed to load environment directories: %s", strerror(-r),
+                           "ERRNO=%d", -r,
+                           NULL);
+                return r;
+        }
+
         if (!argv)
                 argv = command->argv;
 
@@ -1471,11 +1482,12 @@ int exec_spawn(ExecCommand *command,
                 assert(n_env <= 7);
 
                 if (!(final_env = strv_env_merge(
-                                      5,
+                                      6,
                                       environment,
                                       our_env,
                                       context->environment,
                                       files_env,
+                                      dirs_env,
                                       pam_env,
                                       NULL))) {
                         err = -ENOMEM;
@@ -1555,6 +1567,9 @@ void exec_context_done(ExecContext *c) {
         strv_free(c->environment_files);
         c->environment_files = NULL;
 
+        strv_free(c->environment_dirs);
+        c->environment_dirs = NULL;
+
         for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
                 free(c->rlimit[l]);
                 c->rlimit[l] = NULL;
@@ -1646,7 +1661,7 @@ void exec_command_free_array(ExecCommand **c, unsigned n) {
         }
 }
 
-int exec_context_load_environment(const ExecContext *c, char ***l) {
+int exec_context_load_files_environment(const ExecContext *c, char ***l) {
         char **i, **r = NULL;
 
         assert(c);
@@ -1704,6 +1719,98 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
         return 0;
 }
 
+int exec_context_load_dirs_environment(const ExecContext *c, char ***l) {
+        char **i, **r = NULL;
+
+        assert(c);
+        assert(l);
+
+        STRV_FOREACH(i, c->environment_dirs) {
+                char *dname;
+                struct stat   sts;
+                DIR           *d;
+                struct dirent *dir;
+                int k;
+                bool ignore = false;
+                char **p;
+                char fname[PATH_MAX];
+                char *sptr;
+
+                dname = *i;
+
+                if (dname[0] == '-') {
+                        ignore = true;
+                        dname++;
+               }
+
+                if (!path_is_absolute(dname)) {
+                        if (ignore)
+                                continue;
+                        strv_free(r);
+                        return -EINVAL;
+                }
+
+                /* Make sure dname exist */
+                if ((stat (dname, &sts)) != 0) {
+                        if (ignore)
+                                continue;
+                        strv_free(r);
+                        return -EINVAL;
+                }
+                /* Make sure it is directory */
+                if (!S_ISDIR(sts.st_mode)) {
+                        if (ignore)
+                                continue;
+                        strv_free(r);
+                        return -EINVAL;
+                }
+                /* Scan all files on this dir */
+                d = opendir(dname);
+                if (!d) {
+                        if (ignore)
+                                continue;
+                        strv_free(r);
+                        return -EINVAL;
+                }
+                while ((dir = readdir(d)) != NULL) {
+                        /* Read only regular files and symlinks */
+                        if ((dir->d_type != DT_REG) && (dir->d_type != DT_LNK)) {
+                                continue;
+                        }
+                        /* Take only .conf files */
+                        if ((sptr = strrchr(dir->d_name, '.')) == NULL) {
+                                continue;
+                        }
+                        if ((strlen(sptr) != 5) || (strncmp(sptr, ".conf", 5) != 0)) {
+                                continue;
+                        }
+                        snprintf(fname, sizeof(fname), "%s/%s", dname, dir->d_name);
+                        if ((k = load_env_file(fname, &p)) < 0) {
+                                if (ignore)
+                                        continue;
+                                strv_free(r);
+                                return k;
+                        }
+
+                        if (r == NULL)
+                                r = p;
+                        else {
+                                char **m;
+
+                                m = strv_env_merge(2, r, p);
+                                strv_free(r);
+                                strv_free(p);
+                                if (!m)
+                                        return -ENOMEM;
+                                r = m;
+                        }
+                }
+        }
+
+        *l = r;
+        return 0;
+}
+
 static void strv_fprintf(FILE *f, char **l) {
         char **g;
 
@@ -1749,6 +1856,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         STRV_FOREACH(e, c->environment_files)
                 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
 
+        STRV_FOREACH(e, c->environment_dirs)
+                fprintf(f, "%sEnvironmentDir: %s\n", prefix, *e);
+
         if (c->tcpwrap_name)
                 fprintf(f,
                         "%sTCPWrapName: %s\n",
diff --git a/src/core/execute.h b/src/core/execute.h
index 2bcd2e1..3862afc 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -83,6 +83,7 @@ struct ExecCommand {
 struct ExecContext {
         char **environment;
         char **environment_files;
+        char **environment_dirs;
 
         struct rlimit *rlimit[RLIMIT_NLIMITS];
         char *working_directory, *root_directory;
@@ -196,7 +197,8 @@ void exec_context_done(ExecContext *c);
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
 void exec_context_tty_reset(const ExecContext *context);
 
-int exec_context_load_environment(const ExecContext *c, char ***l);
+int exec_context_load_files_environment(const ExecContext *c, char ***l);
+int exec_context_load_dirs_environment(const ExecContext *c, char ***l);
 
 void exec_status_start(ExecStatus *s, pid_t pid);
 void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 7212053..87b7847 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -33,6 +33,7 @@ $1.CPUAffinity,                  config_parse_exec_cpu_affinity,     0,
 $1.UMask,                        config_parse_mode,                  0,                             offsetof($1, exec_context.umask)
 $1.Environment,                  config_parse_unit_strv_printf,      0,                             offsetof($1, exec_context.environment)
 $1.EnvironmentFile,              config_parse_unit_env_file,         0,                             offsetof($1, exec_context.environment_files)
+$1.EnvironmentDir,               config_parse_unit_env_dir,          0,                             offsetof($1, exec_context.environment_dirs)
 $1.StandardInput,                config_parse_input,                 0,                             offsetof($1, exec_context.std_input)
 $1.StandardOutput,               config_parse_output,                0,                             offsetof($1, exec_context.std_output)
 $1.StandardError,                config_parse_output,                0,                             offsetof($1, exec_context.std_error)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index e35fdbc..50cae81 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1472,6 +1472,20 @@ int config_parse_unit_env_file(
         return 0;
 }
 
+int config_parse_unit_env_dir(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        return config_parse_unit_env_file(filename, line, section, lvalue,
+                                         ltype, rvalue, data, userdata);
+}
+
 int config_parse_ip_tos(
                 const char *filename,
                 unsigned line,
@@ -2498,6 +2512,7 @@ void unit_dump_config_items(FILE *f) {
                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
                 { config_parse_mode,                  "MODE" },
                 { config_parse_unit_env_file,         "FILE" },
+                { config_parse_unit_env_dir,          "PATH" },
                 { config_parse_output,                "OUTPUT" },
                 { config_parse_input,                 "INPUT" },
                 { config_parse_facility,              "FACILITY" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 24f7384..cb98961 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -67,6 +67,7 @@ int config_parse_path_unit(const char *filename, unsigned line, const char *sect
 int config_parse_socket_service(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_service_sockets(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_env_file(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_env_dir(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_ip_tos(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_condition_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_condition_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 3abd7dc..177db54 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2659,6 +2659,24 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentDirs")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *path;
+                                dbus_bool_t ignore;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
+                                        printf("EnvironmentDir=%s (ignore_errors=%s)\n", path, yes_no(ignore));
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
 
                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
                         DBusMessageIter sub, sub2;
-- 
1.7.9.5



More information about the systemd-devel mailing list