[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