Signed-off-by: Pekka Lundstrom <pekka.lundst...@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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel