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 <christ...@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


------------------------------------------------------------------------------
Get 100% visibility into Java/.NET code with AppDynamics Lite!
It's a free troubleshooting tool designed for production.
Get down to code-level detail for bottlenecks, with <2% overhead. 
Download for free and get started troubleshooting in minutes. 
http://pubads.g.doubleclick.net/gampad/clk?id=48897031&iu=/4140/ostg.clktrk
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to