diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 0e9c724e82..4a0699289c 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -160,3 +160,10 @@ This adds the new options `cgroup2`, `cgroup2:ro`, `cgroup2:force`,
`cgroup2:ro:force` for the `lxc.mount.auto` configuration key. For example, if
a user specifies `cgroup2:force` LXC will pre-mount a pure `cgroup2` layout for
the container even if the host is running with a hybrid layout.
+
+## environment\_runtime\_hooks
+
+This introduces `lxc.environment.runtime` and `lxc.environment.hooks`
+configuration keys to allow environment variables to be applied only to the
+container init process or only to hooks respectively.
+`lxc.environment` remains and still applies to both.
diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 20ae63fd42..39efffbe56 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -2990,7 +2990,14 @@
- This configuration parameter can be specified multiple times; once
+ Subkeys are available to narrow the scope of environment variables:
+ lxc.environment.runtime applies only to
+ the container's init process (and all its descendents),
+ and lxc.environment.hooks applies only to hooks.
+
+
+
+ These configuration parameters can be specified multiple times; once
for each environment variable you wish to configure.
@@ -3001,8 +3008,8 @@
- Specify an environment variable to pass into the container.
- Example:
+ Environment variables applied both to the container init process
+ and to hooks. Example:
lxc.environment = APP_ENV=production
@@ -3017,6 +3024,29 @@
+
+
+
+
+
+
+
+ Environment variables applied only to the container's init
+ process.
+
+
+
+
+
+
+
+
+
+
+ Environment variables applied only to hooks.
+
+
+
diff --git a/src/lxc/api_extensions.h b/src/lxc/api_extensions.h
index 6a0b9fe98d..54ca565f86 100644
--- a/src/lxc/api_extensions.h
+++ b/src/lxc/api_extensions.h
@@ -52,6 +52,7 @@ static char *api_extensions[] = {
"idmapped_mounts_v2",
"core_scheduling",
"cgroup2_auto_mounting",
+ "environment_runtime_hooks",
};
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 8f2f7a37c3..f22f83f0df 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -879,7 +879,11 @@ static int lxc_attach_set_environment(struct attach_context *ctx,
/* Set container environment variables.*/
if (ctx->container->lxc_conf) {
- ret = lxc_set_environment(ctx->container->lxc_conf);
+ ret = lxc_set_environment(&ctx->container->lxc_conf->environment);
+ if (ret < 0)
+ return -1;
+
+ ret = lxc_set_environment(&ctx->container->lxc_conf->environment_runtime);
if (ret < 0)
return -1;
}
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 1899b2806d..7533e28309 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -3209,6 +3209,8 @@ struct lxc_conf *lxc_conf_init(void)
new->root_nsuid_map = NULL;
new->root_nsgid_map = NULL;
INIT_LIST_HEAD(&new->environment);
+ INIT_LIST_HEAD(&new->environment_runtime);
+ INIT_LIST_HEAD(&new->environment_hooks);
INIT_LIST_HEAD(&new->limits);
INIT_LIST_HEAD(&new->sysctls);
INIT_LIST_HEAD(&new->procs);
@@ -4239,18 +4241,18 @@ int lxc_clear_groups(struct lxc_conf *c)
return 0;
}
-int lxc_clear_environment(struct lxc_conf *c)
+int lxc_clear_environment(struct list_head *environment)
{
struct environment_entry *env, *nenv;
- list_for_each_entry_safe(env, nenv, &c->environment, head) {
+ list_for_each_entry_safe(env, nenv, environment, head) {
list_del(&env->head);
free(env->key);
free(env->val);
free(env);
}
- INIT_LIST_HEAD(&c->environment);
+ INIT_LIST_HEAD(environment);
return 0;
}
@@ -4359,7 +4361,7 @@ void lxc_conf_free(struct lxc_conf *conf)
lxc_clear_mount_entries(conf);
lxc_clear_idmaps(conf);
lxc_clear_groups(conf);
- lxc_clear_environment(conf);
+ lxc_clear_environment(&conf->environment);
lxc_clear_limits(conf, "lxc.prlimit");
lxc_clear_sysctls(conf, "lxc.sysctl");
lxc_clear_procs(conf, "lxc.proc");
@@ -5210,11 +5212,11 @@ void suggest_default_idmap(void)
ERROR("lxc.idmap = g 0 %u %u", gid, grange);
}
-int lxc_set_environment(const struct lxc_conf *conf)
+int lxc_set_environment(const struct list_head *environment)
{
struct environment_entry *env;
- list_for_each_entry(env, &conf->environment, head) {
+ list_for_each_entry(env, environment, head) {
int ret;
ret = setenv(env->key, env->val, 1);
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 31cd39e3f7..762d58901d 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -506,10 +506,17 @@ struct lxc_conf {
unsigned int monitor_unshare;
unsigned int monitor_signal_pdeath;
- /* list of environment variables we'll add to the container when
- * started */
+ /* list of environment variables to provide to both the container's init
+ * process and hooks */
struct list_head environment;
+ /* list of environment variables to provide to the container's init
+ * process */
+ struct list_head environment_runtime;
+
+ /* list of environment variables to provide to container hooks */
+ struct list_head environment_hooks;
+
/* text representation of the config file */
char *unexpanded_config;
size_t unexpanded_len;
@@ -599,7 +606,7 @@ __hidden extern int lxc_clear_automounts(struct lxc_conf *c);
__hidden extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
__hidden extern int lxc_clear_idmaps(struct lxc_conf *c);
__hidden extern int lxc_clear_groups(struct lxc_conf *c);
-__hidden extern int lxc_clear_environment(struct lxc_conf *c);
+__hidden extern int lxc_clear_environment(struct list_head *environment);
__hidden extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
__hidden extern int lxc_delete_autodev(struct lxc_handler *handler);
__hidden extern int lxc_clear_autodev_tmpfs_size(struct lxc_conf *c);
@@ -710,7 +717,7 @@ static inline int lxc_personality(personality_t persona)
return personality(persona);
}
-__hidden extern int lxc_set_environment(const struct lxc_conf *conf);
+__hidden extern int lxc_set_environment(const struct list_head *environment);
__hidden extern int parse_cap(const char *cap_name, __u32 *cap);
#endif /* __LXC_CONF_H */
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 5045741bb0..7163cd1b22 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -80,6 +80,8 @@ lxc_config_define(console_rotate);
lxc_config_define(console_size);
lxc_config_define(unsupported_key);
lxc_config_define(environment);
+lxc_config_define(environment_runtime);
+lxc_config_define(environment_hooks);
lxc_config_define(ephemeral);
lxc_config_define(execute_cmd);
lxc_config_define(group);
@@ -211,6 +213,8 @@ static struct lxc_config_t config_jump_table[] = {
{ "lxc.console.rotate", true, set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
{ "lxc.console.size", true, set_config_console_size, get_config_console_size, clr_config_console_size, },
{ "lxc.sched.core", true, set_config_sched_core, get_config_sched_core, clr_config_sched_core, },
+ { "lxc.environment.runtime", true, set_config_environment_runtime, get_config_environment_runtime, clr_config_environment_runtime },
+ { "lxc.environment.hooks", true, set_config_environment_hooks, get_config_environment_hooks, clr_config_environment_hooks },
{ "lxc.environment", true, set_config_environment, get_config_environment, clr_config_environment, },
{ "lxc.ephemeral", true, set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
{ "lxc.execute.cmd", true, set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
@@ -1574,15 +1578,15 @@ static int set_config_group(const char *key, const char *value,
return 0;
}
-static int set_config_environment(const char *key, const char *value,
- struct lxc_conf *lxc_conf, void *data)
+static int set_config_environment_impl(const char *value,
+ struct list_head *environment)
{
__do_free char *dup = NULL, *val = NULL;
__do_free struct environment_entry *new_env = NULL;
char *env_val;
if (lxc_config_value_empty(value))
- return lxc_clear_environment(lxc_conf);
+ return lxc_clear_environment(environment);
new_env = zalloc(sizeof(struct environment_entry));
if (!new_env)
@@ -1609,12 +1613,30 @@ static int set_config_environment(const char *key, const char *value,
new_env->key = move_ptr(dup);
new_env->val = move_ptr(val);
- list_add_tail(&new_env->head, &lxc_conf->environment);
+ list_add_tail(&new_env->head, environment);
move_ptr(new_env);
return 0;
}
+static int set_config_environment(const char *key, const char *value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ return set_config_environment_impl(value, &lxc_conf->environment);
+}
+
+static int set_config_environment_runtime(const char *key, const char* value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ return set_config_environment_impl(value, &lxc_conf->environment_runtime);
+}
+
+static int set_config_environment_hooks(const char *key, const char* value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ return set_config_environment_impl(value, &lxc_conf->environment_hooks);
+}
+
static int set_config_tty_max(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
@@ -4473,8 +4495,8 @@ static int get_config_group(const char *key, char *retv, int inlen,
return fulllen;
}
-static int get_config_environment(const char *key, char *retv, int inlen,
- struct lxc_conf *c, void *data)
+static int get_config_environment_impl(char *retv, int inlen,
+ struct list_head *environment)
{
int len, fulllen = 0;
struct environment_entry *env;
@@ -4484,13 +4506,32 @@ static int get_config_environment(const char *key, char *retv, int inlen,
else
memset(retv, 0, inlen);
- list_for_each_entry(env, &c->environment, head) {
+ list_for_each_entry(env, environment, head) {
strprint(retv, inlen, "%s=%s\n", env->key, env->val);
}
return fulllen;
}
+static int get_config_environment(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ return get_config_environment_impl(retv, inlen, &c->environment);
+}
+
+static int get_config_environment_runtime(const char *key, char *retv,
+ int inlen, struct lxc_conf *c,
+ void *data)
+{
+ return get_config_environment_impl(retv, inlen, &c->environment_runtime);
+}
+
+static int get_config_environment_hooks(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ return get_config_environment_impl(retv, inlen, &c->environment_hooks);
+}
+
static int get_config_execute_cmd(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
@@ -5211,7 +5252,19 @@ static inline int clr_config_group(const char *key, struct lxc_conf *c,
static inline int clr_config_environment(const char *key, struct lxc_conf *c,
void *data)
{
- return lxc_clear_environment(c);
+ return lxc_clear_environment(&c->environment);
+}
+
+static inline int clr_config_environment_runtime(const char *key,
+ struct lxc_conf *c, void *data)
+{
+ return lxc_clear_environment(&c->environment_runtime);
+}
+
+static inline int clr_config_environment_hooks(const char *key,
+ struct lxc_conf *c, void *data)
+{
+ return lxc_clear_environment(&c->environment_hooks);
}
static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
@@ -6607,6 +6660,9 @@ int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
} else if (strequal(key, "lxc.console")) {
strprint(retv, inlen, "logfile\n");
strprint(retv, inlen, "path\n");
+ } else if (strequal(key, "lxc.environment")) {
+ strprint(retv, inlen, "runtime\n");
+ strprint(retv, inlen, "hooks\n");
} else if (strequal(key, "lxc.seccomp")) {
strprint(retv, inlen, "profile\n");
} else if (strequal(key, "lxc.signal")) {
diff --git a/src/lxc/start.c b/src/lxc/start.c
index d566dd5ddb..b8559bbebf 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1451,7 +1451,11 @@ static int do_start(void *data)
* to allow them to be used by the various hooks, such as the start
* hook below.
*/
- ret = lxc_set_environment(handler->conf);
+ ret = lxc_set_environment(&handler->conf->environment);
+ if (ret < 0)
+ goto out_warn_father;
+
+ ret = lxc_set_environment(&handler->conf->environment_hooks);
if (ret < 0)
goto out_warn_father;
@@ -1552,7 +1556,11 @@ static int do_start(void *data)
if (ret < 0)
SYSERROR("Failed to clear environment.");
- ret = lxc_set_environment(handler->conf);
+ ret = lxc_set_environment(&handler->conf->environment);
+ if (ret < 0)
+ goto out_warn_father;
+
+ ret = lxc_set_environment(&handler->conf->environment_runtime);
if (ret < 0)
goto out_warn_father;