[lxc-devel] [PATCH 8/8] attach: implement remaining options of lxc_attach_set_environment
Christian Seiler
christian at iwakd.de
Tue Aug 13 21:56:20 UTC 2013
This patch implements the extra_env and extra_keep options of
lxc_attach_set_environment.
The Python implementation, the C container API and the lxc-attach
utility are able to utilize this feature; lxc-attach has gained two new
command line options for this.
Signed-off-by: Christian Seiler <christian at iwakd.de>
---
src/lxc/attach.c | 95 ++++++++++++++++++++++++++++++++++++++++++--------
src/lxc/lxc_attach.c | 59 ++++++++++++++++++++++++++++---
2 files changed, 135 insertions(+), 19 deletions(-)
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 742ce76..950fe9a 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -254,23 +254,72 @@ int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra_env, char** extra_keep)
{
- /* TODO: implement extra_env, extra_keep
- * Rationale:
- * - extra_env is an array of strings of the form
- * "VAR=VALUE", which are to be set (after clearing or not,
- * depending on the value of the policy variable)
- * - extra_keep is an array of strings of the form
- * "VAR", which are extra environment variables to be kept
- * around after clearing (if that is done, otherwise, the
- * remain anyway)
- */
- (void) extra_env;
- (void) extra_keep;
-
if (policy == LXC_ATTACH_CLEAR_ENV) {
+ char **extra_keep_store = NULL;
+ char *path_env;
+ size_t n;
+ int path_kept = 0;
+
+ if (extra_keep) {
+ size_t count, i;
+
+ for (count = 0; extra_keep[count]; count++);
+
+ extra_keep_store = calloc(count, sizeof(char *));
+ if (!extra_keep_store) {
+ SYSERROR("failed to allocate memory for storing current "
+ "environment variable values that will be kept");
+ return -1;
+ }
+ for (i = 0; i < count; i++) {
+ char *v = getenv(extra_keep[i]);
+ if (v) {
+ extra_keep_store[i] = strdup(v);
+ if (!extra_keep_store[i]) {
+ SYSERROR("failed to allocate memory for storing current "
+ "environment variable values that will be kept");
+ while (i > 0)
+ free(extra_keep_store[--i]);
+ free(extra_keep_store);
+ return -1;
+ }
+ if (strcmp(extra_keep[i], "PATH") == 0)
+ path_kept = 1;
+ }
+ /* calloc sets entire array to zero, so we don't
+ * need an else */
+ }
+ }
+
if (clearenv()) {
SYSERROR("failed to clear environment");
- /* don't error out though */
+ return -1;
+ }
+
+ if (extra_keep_store) {
+ size_t i;
+ for (i = 0; extra_keep[i]; i++) {
+ if (extra_keep_store[i])
+ setenv(extra_keep[i], extra_keep_store[i], 1);
+ free(extra_keep_store[i]);
+ }
+ free(extra_keep_store);
+ }
+
+ /* always set a default path; shells and execlp tend
+ * to be fine without it, but there is a disturbing
+ * number of C programs out there that just assume
+ * that getenv("PATH") is never NULL and then die a
+ * painful segfault death. */
+ if (!path_kept) {
+ n = confstr(_CS_PATH, NULL, 0);
+ path_env = malloc(n);
+ if (path_env) {
+ confstr(_CS_PATH, path_env, n);
+ setenv("PATH", path_env, 1);
+ free(path_env);
+ }
+ /* don't error out, this is just an extra service */
}
}
@@ -279,6 +328,24 @@ int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra
return -1;
}
+ /* set extra environment variables */
+ if (extra_env) {
+ for (; *extra_env; extra_env++) {
+ /* duplicate the string, just to be on
+ * the safe side, because putenv does not
+ * do it for us */
+ char *p = strdup(*extra_env);
+ /* we just assume the user knows what they
+ * are doing, so we don't do any checks */
+ if (!p) {
+ SYSERROR("failed to allocate memory for additional environment "
+ "variables");
+ return -1;
+ }
+ putenv(p);
+ }
+ }
+
return 0;
}
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index f7ec728..cb00e4a 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -24,6 +24,7 @@
#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/types.h>
+#include <stdlib.h>
#include "attach.h"
#include "arguments.h"
@@ -44,6 +45,8 @@ static const struct option my_longopts[] = {
/* TODO: decide upon short option names */
{"clear-env", no_argument, 0, 500},
{"keep-env", no_argument, 0, 501},
+ {"keep-var", required_argument, 0, 502},
+ {"set-var", required_argument, 0, 'v'},
LXC_COMMON_OPTIONS
};
@@ -52,6 +55,32 @@ static signed long new_personality = -1;
static int namespace_flags = -1;
static int remount_sys_proc = 0;
static lxc_attach_env_policy_t env_policy = LXC_ATTACH_KEEP_ENV;
+static char **extra_env = NULL;
+static ssize_t extra_env_size = 0;
+static char **extra_keep = NULL;
+static ssize_t extra_keep_size = 0;
+
+static int add_to_simple_array(char ***array, ssize_t *capacity, char *value)
+{
+ ssize_t count = 0;
+
+ if (*array)
+ for (; (*array)[count]; count++);
+
+ /* we have to reallocate */
+ if (count >= *capacity - 1) {
+ ssize_t new_capacity = ((count + 1) / 32 + 1) * 32;
+ char **new_array = realloc((void*)*array, sizeof(char *) * new_capacity);
+ if (!new_array)
+ return -1;
+ memset(&new_array[count], 0, sizeof(char*)*(new_capacity - count));
+ *array = new_array;
+ *capacity = new_capacity;
+ }
+
+ (*array)[count] = value;
+ return 0;
+}
static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
@@ -81,6 +110,20 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
case 501: /* keep-env */
env_policy = LXC_ATTACH_KEEP_ENV;
break;
+ case 502: /* keep-var */
+ ret = add_to_simple_array(&extra_keep, &extra_keep_size, arg);
+ if (ret < 0) {
+ lxc_error(args, "memory allocation error");
+ return -1;
+ }
+ break;
+ case 'v':
+ ret = add_to_simple_array(&extra_env, &extra_env_size, arg);
+ if (ret < 0) {
+ lxc_error(args, "memory allocation error");
+ return -1;
+ }
+ break;
}
return 0;
@@ -113,14 +156,18 @@ Options :\n\
mount namespace when using -s in order to properly\n\
reflect the correct namespace context. See the\n\
lxc-attach(1) manual page for details.\n\
- --clear-env\n\
- Clear all environment variables before attaching.\n\
+ --clear-env Clear all environment variables before attaching.\n\
The attached shell/program will start with only\n\
container=lxc set.\n\
- --keep-env\n\
- Keep all current enivornment variables. This\n\
+ --keep-env Keep all current enivornment variables. This\n\
is the current default behaviour, but is likely to\n\
- change in the future.\n",
+ change in the future.\n\
+ -v, --set-var Set an additional variable that is seen by the\n\
+ attached program in the container. May be specified\n\
+ multiple times.\n\
+ --keep-var Keep an additional environment variable. Only\n\
+ applicable if --clear-env is specified. May be used\n\
+ multiple times.\n",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
@@ -153,6 +200,8 @@ int main(int argc, char *argv[])
attach_options.namespaces = namespace_flags;
attach_options.personality = new_personality;
attach_options.env_policy = env_policy;
+ attach_options.extra_env_vars = extra_env;
+ attach_options.extra_keep_env = extra_keep;
if (my_args.argc) {
command.program = my_args.argv[0];
--
1.7.10.4
More information about the lxc-devel
mailing list