[lxc-devel] [PATCH] [resend?] Add a unexpanded lxc_conf

Serge Hallyn serge.hallyn at ubuntu.com
Thu Jun 12 14:24:38 UTC 2014


Currently when a container's configuration file has lxc.includes,
any future write_config() will expand the lxc.includes.  This
affects container clones (and snapshots) as well as users of the
API who make an update and then c.save_config().

To fix this, separately track the expanded and unexpanded lxc_conf.  The
unexpanded conf does not contain values read from lxc.includes.  The
expanded conf does.  Lxc functions mainly need the expanded conf to
figure out how to configure the container.  The unexpanded conf is used
at write_config().

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/conf.c         | 13 +++++++++++++
 src/lxc/conf.h         |  4 ++++
 src/lxc/confile.c      | 45 ++++++++++++++++++++++++++++++++++++++++++---
 src/lxc/confile.h      |  2 +-
 src/lxc/lxc_execute.c  |  2 +-
 src/lxc/lxccontainer.c | 38 +++++++++++++++++++++++++++++++-------
 src/lxc/lxccontainer.h | 10 ++++++++++
 7 files changed, 102 insertions(+), 12 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 4b52550..521a48d 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2689,6 +2689,7 @@ struct lxc_conf *lxc_conf_init(void)
 	lxc_list_init(&new->caps);
 	lxc_list_init(&new->keepcaps);
 	lxc_list_init(&new->id_map);
+	lxc_list_init(&new->includes);
 	for (i=0; i<NUM_LXC_HOOKS; i++)
 		lxc_list_init(&new->hooks[i]);
 	lxc_list_init(&new->groups);
@@ -4364,6 +4365,17 @@ static void lxc_clear_saved_nics(struct lxc_conf *conf)
 	free(conf->saved_nics);
 }
 
+static inline void lxc_clear_includes(struct lxc_conf *conf)
+{
+	struct lxc_list *it,*next;
+
+	lxc_list_for_each_safe(it, &conf->includes, next) {
+		lxc_list_del(it);
+		free(it->elem);
+		free(it);
+	}
+}
+
 void lxc_conf_free(struct lxc_conf *conf)
 {
 	if (!conf)
@@ -4402,6 +4414,7 @@ void lxc_conf_free(struct lxc_conf *conf)
 	lxc_clear_saved_nics(conf);
 	lxc_clear_idmaps(conf);
 	lxc_clear_groups(conf);
+	lxc_clear_includes(conf);
 	free(conf);
 }
 
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index f5fab3d..53590bc 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -283,6 +283,7 @@ struct saved_nic {
 
 struct lxc_conf {
 	int is_execute;
+	bool unexpanded;
 	char *fstab;
 	int tty;
 	int pts;
@@ -338,6 +339,9 @@ struct lxc_conf {
 
 	/* set to true when rootfs has been setup */
 	bool rootfs_setup;
+
+	/* list of included files */
+	struct lxc_list includes;
 };
 
 int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 70097f8..2ab3fcb 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1552,10 +1552,34 @@ static int config_console(const char *key, const char *value,
 	return config_path_item(&lxc_conf->console.path, value);
 }
 
+static int add_include_file(const char *fname, struct lxc_conf *lxc_conf)
+{
+	struct lxc_list *list;
+	char *v;
+	int len = strlen(fname);
+
+	list = malloc(sizeof(*list));
+	if (!list)
+		return -1;
+	lxc_list_init(list);
+	v = malloc(len+1);
+	if (!v) {
+		free(list);
+		return -1;
+	}
+	strncpy(v, fname, len);
+	v[len] = '\0';
+	list->elem = v;
+	lxc_list_add_tail(&lxc_conf->includes, list);
+	return 0;
+}
+
 static int config_includefile(const char *key, const char *value,
 			  struct lxc_conf *lxc_conf)
 {
-	return lxc_config_read(value, lxc_conf);
+	if (lxc_conf->unexpanded)
+		return add_include_file(value, lxc_conf);
+	return lxc_config_read(value, lxc_conf, NULL);
 }
 
 static int config_rootfs(const char *key, const char *value,
@@ -1673,8 +1697,10 @@ static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
 	return parse_line(buffer, conf);
 }
 
-int lxc_config_read(const char *file, struct lxc_conf *conf)
+int lxc_config_read(const char *file, struct lxc_conf *conf, struct lxc_conf *unexp_conf)
 {
+	int ret;
+
 	if( access(file, R_OK) == -1 ) {
 		return -1;
 	}
@@ -1682,7 +1708,16 @@ int lxc_config_read(const char *file, struct lxc_conf *conf)
 	if( ! conf->rcfile ) {
 		conf->rcfile = strdup( file );
 	}
-	return lxc_file_for_each_line(file, parse_line, conf);
+	ret = lxc_file_for_each_line(file, parse_line, conf);
+	if (ret)
+		return ret;
+	if (!unexp_conf)
+		return 0;
+	if (!unexp_conf->rcfile) {
+		unexp_conf->rcfile = strdup( file );
+	}
+
+	return lxc_file_for_each_line(file, parse_line, unexp_conf);
 }
 
 int lxc_config_define_add(struct lxc_list *defines, char* arg)
@@ -2223,6 +2258,10 @@ void write_config(FILE *fout, struct lxc_conf *c)
 	struct lxc_list *it;
 	int i;
 
+	lxc_list_for_each(it, &c->includes) {
+		fprintf(fout, "lxc.include = %s\n", (char *)it->elem);
+	}
+
 	if (c->fstab)
 		fprintf(fout, "lxc.mount = %s\n", c->fstab);
 	lxc_list_for_each(it, &c->mount_list) {
diff --git a/src/lxc/confile.h b/src/lxc/confile.h
index 171614a..7e34089 100644
--- a/src/lxc/confile.h
+++ b/src/lxc/confile.h
@@ -39,7 +39,7 @@ struct lxc_config_t {
 extern struct lxc_config_t *lxc_getconfig(const char *key);
 extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv, int inlen);
 extern int lxc_listconfigs(char *retv, int inlen);
-extern int lxc_config_read(const char *file, struct lxc_conf *conf);
+extern int lxc_config_read(const char *file, struct lxc_conf *conf, struct lxc_conf *unexp_conf);
 
 extern int lxc_config_define_add(struct lxc_list *defines, char* arg);
 extern int lxc_config_define_load(struct lxc_list *defines,
diff --git a/src/lxc/lxc_execute.c b/src/lxc/lxc_execute.c
index 6949e2b..b602793 100644
--- a/src/lxc/lxc_execute.c
+++ b/src/lxc/lxc_execute.c
@@ -131,7 +131,7 @@ int main(int argc, char *argv[])
 		return 1;
 	}
 
-	if (rcfile && lxc_config_read(rcfile, conf)) {
+	if (rcfile && lxc_config_read(rcfile, conf, NULL)) {
 		ERROR("failed to read configuration file");
 		return 1;
 	}
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 5cedb27..bb7b4bb 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -238,6 +238,10 @@ static void lxc_container_free(struct lxc_container *c)
 		lxc_conf_free(c->lxc_conf);
 		c->lxc_conf = NULL;
 	}
+	if (c->lxc_unexp_conf) {
+		lxc_conf_free(c->lxc_unexp_conf);
+		c->lxc_unexp_conf = NULL;
+	}
 	if (c->config_path) {
 		free(c->config_path);
 		c->config_path = NULL;
@@ -410,7 +414,14 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
 {
 	if (!c->lxc_conf)
 		c->lxc_conf = lxc_conf_init();
-	if (c->lxc_conf && !lxc_config_read(fname, c->lxc_conf))
+	if (!c->lxc_unexp_conf) {
+		c->lxc_unexp_conf = lxc_conf_init();
+		if (c->lxc_unexp_conf)
+			c->lxc_unexp_conf->unexpanded = true;
+	}
+	if (c->lxc_conf && c->lxc_unexp_conf &&
+			!lxc_config_read(fname, c->lxc_conf,
+					 c->lxc_unexp_conf))
 		return true;
 	return false;
 }
@@ -1196,9 +1207,15 @@ out_error:
 
 static void lxcapi_clear_config(struct lxc_container *c)
 {
-	if (c && c->lxc_conf) {
-		lxc_conf_free(c->lxc_conf);
-		c->lxc_conf = NULL;
+	if (c) {
+		if (c->lxc_conf) {
+			lxc_conf_free(c->lxc_conf);
+			c->lxc_conf = NULL;
+		}
+		if (c->lxc_unexp_conf) {
+			lxc_conf_free(c->lxc_unexp_conf);
+			c->lxc_unexp_conf = NULL;
+		}
 	}
 }
 
@@ -1321,6 +1338,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 	/* reload config to get the rootfs */
 	lxc_conf_free(c->lxc_conf);
 	c->lxc_conf = NULL;
+	c->lxc_unexp_conf = NULL;
 	if (!load_config_locked(c, c->configfile))
 		goto out_unlock;
 
@@ -1845,7 +1863,7 @@ static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file)
 	fout = fopen(alt_file, "w");
 	if (!fout)
 		goto out;
-	write_config(fout, c->lxc_conf);
+	write_config(fout, c->lxc_unexp_conf);
 	fclose(fout);
 	ret = true;
 
@@ -2072,11 +2090,17 @@ static bool set_config_item_locked(struct lxc_container *c, const char *key, con
 
 	if (!c->lxc_conf)
 		c->lxc_conf = lxc_conf_init();
-	if (!c->lxc_conf)
+	if (!c->lxc_unexp_conf) {
+		c->lxc_unexp_conf = lxc_conf_init();
+		c->lxc_unexp_conf->unexpanded = true;
+	}
+	if (!c->lxc_conf || !c->lxc_unexp_conf)
 		return false;
 	config = lxc_getconfig(key);
 	if (!config)
 		return false;
+	if (config->cb(key, v, c->lxc_unexp_conf) != 0)
+		return false;
 	return (0 == config->cb(key, v, c->lxc_conf));
 }
 
@@ -2677,7 +2701,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
 		SYSERROR("open %s", newpath);
 		goto out;
 	}
-	write_config(fout, c->lxc_conf);
+	write_config(fout, c->lxc_unexp_conf);
 	fclose(fout);
 	c->lxc_conf->rootfs.path = origroot;
 
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 1d0628a..d1de399 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -99,6 +99,16 @@ struct lxc_container {
 	 */
 	struct lxc_conf *lxc_conf;
 
+	/*!
+	 * \private
+	 * The non-common, unexpanded configuration.  This includes the
+	 * list of lxc.include files, and does not contain any
+	 * individual configuration items from the include files.
+	 * Anything coming from the container's own configuration file
+	 * or from lxcapi_set_config_item() does get added here.
+	 */
+	struct lxc_conf *lxc_unexp_conf;
+
 	// public fields
 	/*! Human-readable string representing last error */
 	char *error_string;
-- 
1.9.1



More information about the lxc-devel mailing list