[lxc-devel] [PATCH 8/8] attach: implement remaining options of lxc_attach_set_environment

Serge Hallyn serge.hallyn at ubuntu.com
Wed Aug 14 20:58:02 UTC 2013


Quoting Christian Seiler (christian at iwakd.de):
> 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>

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

The only oddness I see is that

> ---
>  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;

The freeing seems unnecessary as you're about to rexit(-1), right?

> +					}
> +					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 at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel




More information about the lxc-devel mailing list