[lxc-devel] [PATCH 3/4] lxc-create menuconfig: enable -m | --menuconfig option

Sheng Yong shyodx at gmail.com
Fri Apr 18 15:30:18 UTC 2014


	* execute `$datadir/lxc/scripts/mconf $datadir/lxc/scripts/create.conf'
	* read .config to fill lxc_arguments

Signed-off-by: Sheng Yong <shyodx at gmail.com>
---
 src/lxc/Makefile.am  |   1 +
 src/lxc/lxc_create.c | 416 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 417 insertions(+)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index ab8a46e..99f7f38 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -116,6 +116,7 @@ AM_CFLAGS=-I$(top_srcdir)/src \
 	-DLXCINITDIR=\"$(LXCINITDIR)\" \
 	-DLIBEXECDIR=\"$(LIBEXECDIR)\" \
 	-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\" \
+	-DLXCSCRIPTDIR=\"$(LXCSCRIPTDIR)\" \
 	-DLOGPATH=\"$(LOGPATH)\" \
 	-DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
 	-DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
diff --git a/src/lxc/lxc_create.c b/src/lxc/lxc_create.c
index 6b595f9..8a6a49d 100644
--- a/src/lxc/lxc_create.c
+++ b/src/lxc/lxc_create.c
@@ -32,9 +32,65 @@
 #include "bdev.h"
 #include "arguments.h"
 #include "utils.h"
+#include "parse.h"
+#include "confile.h"
 
 lxc_log_define(lxc_create_ui, lxc);
 
+static int create_config_file(const char *, const char *, struct lxc_conf *);
+static int create_config_template(const char *, const char *, struct lxc_conf *);
+static int create_config_backdev(const char *, const char *, struct lxc_conf *);
+static int create_config_backdev_lvm(const char *, const char *, struct lxc_conf *);
+static int create_config_lxc_path(const char *, const char *, struct lxc_conf *);
+static int create_config_log_file(const char *, const char *, struct lxc_conf *);
+static int create_config_log_prio(const char *, const char *, struct lxc_conf *);
+static int create_config_quiet(const char *, const char *, struct lxc_conf *);
+
+static struct lxc_config_t create_config[] = {
+
+	{ "CONFIG_FILE",              create_config_file          },
+	{ "TEMP_none",                create_config_template      },
+	{ "TEMP_alpine",              create_config_template      },
+	{ "TEMP_altlinux",            create_config_template      },
+	{ "TEMP_archlinux",           create_config_template      },
+	{ "TEMP_busybox",             create_config_template      },
+	{ "TEMP_centos",              create_config_template      },
+	{ "TEMP_cirros",              create_config_template      },
+	{ "TEMP_debian",              create_config_template      },
+	{ "TEMP_download",            create_config_template      },
+	{ "TEMP_fedora",              create_config_template      },
+	{ "TEMP_gentoo",              create_config_template      },
+	{ "TEMP_openmandriva",        create_config_template      },
+	{ "TEMP_opensuse",            create_config_template      },
+	{ "TEMP_oracle",              create_config_template      },
+	{ "TEMP_plamo",               create_config_template      },
+	{ "TEMP_sshd",                create_config_template      },
+	{ "TEMP_ubuntu",              create_config_template      },
+	{ "TEMP_ubuntu_cloud",        create_config_template      },
+	{ "BS_NONE",                  create_config_backdev       },
+	{ "BS_dir",                   create_config_backdev       },
+	{ "BS_lvm",                   create_config_backdev       },
+	{ "BS_loop",                  create_config_backdev       },
+	{ "BS_btrfs",                 create_config_backdev       },
+	{ "BS_best",                  create_config_backdev       },
+	{ "BS_LVM_LVNAME",            create_config_backdev_lvm   },
+	{ "BS_LVM_VGNAME",            create_config_backdev_lvm   },
+	{ "BS_LVM_THINPOOL",          create_config_backdev_lvm   },
+	{ "BS_LVM_FSTYPE",            create_config_backdev_lvm   },
+	{ "BS_LVM_FSSIZE",            create_config_backdev_lvm   },
+	{ "LXC_PATH",                 create_config_lxc_path      },
+	{ "LOG_FILE",                 create_config_log_file      },
+	{ "LOG_PRIO_FATAL",           create_config_log_prio      },
+	{ "LOG_PRIO_CRIT",            create_config_log_prio      },
+	{ "LOG_PRIO_WARN",            create_config_log_prio      },
+	{ "LOG_PRIO_ERROR",           create_config_log_prio      },
+	{ "LOG_PRIO_NOTICE",          create_config_log_prio      },
+	{ "LOG_PRIO_INFO",            create_config_log_prio      },
+	{ "LOG_PRIO_DEBUG",           create_config_log_prio      },
+	{ "QUIET",                    create_config_quiet         }
+};
+static const size_t createconfig_size = sizeof(create_config)/sizeof(struct lxc_config_t);
+
 static uint64_t get_fssize(char *s)
 {
 	uint64_t ret;
@@ -68,6 +124,352 @@ static uint64_t get_fssize(char *s)
 	return ret;
 }
 
+static char* remove_left_right_quotation(char *buffer)
+{
+	if (*buffer == '"')
+		buffer++;
+	if (buffer[strlen(buffer)-1] == '"')
+		buffer[strlen(buffer)-1] = '\0';
+	return buffer;
+}
+
+static int create_config_file(const char *key, const char *value,
+			      struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+	int len = strlen(value);
+
+	if (len == 0) // must be empty value
+		return 0;
+
+	args->configfile = malloc(len + 1);
+	if (!args->configfile) {
+		SYSERROR("failed to allocate memory");
+		return -1;
+	}
+	strncpy(args->configfile, value, len);
+	args->configfile[len] = '\0';
+
+	return 0;
+}
+
+static int create_config_template(const char *key, const char *value,
+				  struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+
+	char *template = (char *) (key + 5); //skip the first 5 char 'TEMP_'
+	int len;
+
+	if (strncmp(value, "y", 1)) {
+		SYSERROR("unknown configure value '%s'", value);
+		return -1;
+	}
+
+	len = strlen(template);
+	args->template = malloc(len + 1);
+	if (!args->template) {
+		SYSERROR("failed to allocate memory");
+		return -1;
+	}
+	strncpy(args->template, template, len);
+	args->template[len] = '\0';
+
+	return 0;
+}
+
+static int create_config_backdev(const char *key, const char *value,
+				 struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+	char *bs = (char *) (key + 3); //skip the first 3 char 'BS_'
+	int len;
+
+	if (strncmp("y", value, 1)) {
+		SYSERROR("unknown configure value '%s'", value);
+		return -1;
+	}
+
+	if (!strncmp(bs, "NONE", 5)) {
+		return 0;
+	}
+
+	len = strlen(bs);
+	args->bdevtype = malloc(len + 1);
+	if (!args->bdevtype) {
+		SYSERROR("failed to allocate memory");
+		return -1;
+	}
+	strncpy(args->bdevtype, bs, len);
+	args->bdevtype[len] = '\0';
+
+	return 0;
+}
+
+static int create_config_backdev_lvm(const char *key, const char *value,
+				     struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+	char lvms[5][9] = {"LVNAME", "VGNAME", "THINPOOL", "FSTYPE", "FSSIZE"};
+	char *lvm = (char *) (key + 7); //skip the first 7 char 'BS_LVM_'
+	char *tmp;
+	int len, i;
+
+	for (i = 0; i < 5; i++) {
+		if (!strncmp(lvm, lvms[i], strlen(lvms[i])))
+			break;
+	}
+	if (i == 5) {
+		SYSERROR("unknown option '%s'", lvm);
+		return 0;
+	}
+
+	len = strlen(value);
+	if (len == 0) // must be empty value
+		return 0;
+
+	tmp = malloc(len + 1);
+	if (!tmp) {
+		SYSERROR("failed to allocate memory");
+		return -1;
+	}
+	strncpy(tmp, value, len);
+	tmp[len] = '\0';
+
+	switch(i) {
+	case 0: args->lvname = tmp; break;
+	case 1: args->vgname = tmp; break;
+	case 2: args->thinpool = tmp; break;
+	case 3: args->fstype = tmp; break;
+	case 4: args->fssize = get_fssize(tmp); break;
+	}
+
+	return 0;
+}
+
+static int create_config_lxc_path(const char *key, const char *value,
+				  struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+	char *path = strdup(value);
+
+	if (!path) {
+		SYSERROR("failed to allocate memory");
+		return -1;
+	}
+
+	remove_trailing_slashes(path);
+
+	args->lxcpath = realloc(args->lxcpath, (args->lxcpath_cnt + 1) *
+				 sizeof(args->lxcpath[0]));
+	if (args->lxcpath == NULL) {
+		SYSERROR("failed to allocate memory");
+		return -ENOMEM;
+	}
+	args->lxcpath[args->lxcpath_cnt++] = path;
+
+	return 0;
+}
+
+static int create_config_log_file(const char *key, const char *value,
+				  struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+	int len = strlen(value);
+
+	if (len == 0) // must be empty value
+		return 0;
+
+	args->log_file = malloc(len + 1);
+	if (!args->log_file) {
+		SYSERROR("failed to allocate memroy");
+		return -1;
+	}
+
+	strncpy(args->log_file, value, len);
+	args->log_file[len] = '\0';
+
+	return 0;
+}
+
+static int create_config_log_prio(const char *key, const char *value,
+				  struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+	char *prio = (char *) (key + 9);	// skip the first 9 char 'LOG_PRIO_'
+	int len;
+
+	if (strncmp(value, "y", 1)) {
+		SYSERROR("unknown configure value '%s'", value);
+		return -1;
+	}
+
+	if (!strncmp(prio, "ERROR", 6))
+		return 0;
+
+	len = strlen(prio);
+	args->log_priority = malloc(len + 1);
+	if (!args->log_priority) {
+		SYSERROR("failed to allocate memory");
+		return -1;
+	}
+
+	strncpy(args->log_priority, prio, len);
+	args->log_priority[len] = '\0';
+
+	return 0;
+}
+
+static int create_config_quiet(const char *key, const char *value,
+			       struct lxc_conf *lxc_conf)
+{
+	struct lxc_arguments *args = (struct lxc_arguments *) lxc_conf;
+
+	if (strncmp("y", value, 1)) {
+		SYSERROR("unknown configure value '%s'", value);
+		return -1;
+	}
+
+	args->quiet = 1;
+
+	return 0;
+}
+
+static bool menuconfig(struct lxc_arguments* args)
+{
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0) {
+		SYSERROR("failed to fork task for container creation menuconfig");
+		return false;
+	}
+
+	if (pid == 0) {
+		char **argv;
+		int len;
+
+		len = strlen(LXCSCRIPTDIR) + strlen("/create.conf") + 1;
+		argv = malloc(3 * sizeof(*argv));
+		if (!argv) {
+			return false;
+		}
+
+		len = strlen(LXCSCRIPTDIR) + strlen("/mconf") + 1;
+		argv[0] = malloc(len);
+		if (!argv[0]) {
+			free(argv);
+			return false;
+		}
+		sprintf(argv[0], "%s/mconf", LXCSCRIPTDIR);
+
+		argv[1] = malloc(len);
+		if (!argv[1]) {
+			free(argv[0]);
+			free(argv);
+			return false;
+		}
+		sprintf(argv[1], "%s/create.conf", LXCSCRIPTDIR);
+
+		argv[2] = NULL;
+
+		execv(argv[0], argv);
+		SYSERROR("failed to execute menuconfig %s %s", argv[0], argv[1]);
+		exit(1);
+	}
+
+	if (wait_for_pid(pid) != 0) {
+		ERROR("container container creation for %s failed\n", args->name);
+		return false;
+	}
+
+	return true;
+}
+
+static struct lxc_config_t *lxc_getcreateconfig(const char *key)
+{
+	int i;
+
+	for (i = 0; i < createconfig_size; i++)
+		if (!strncmp(create_config[i].name, key,
+			     strlen(create_config[i].name)))
+			return &create_config[i];
+	return NULL;
+}
+
+static int parse_config(char *buffer, void *data)
+{
+	struct lxc_config_t *create_config;
+	char *line, *linep, *key, *value;
+	int ret = 0;
+
+	if (lxc_is_line_empty(buffer))
+		return 0;
+
+	linep = line = strdup(buffer);
+	if (!line) {
+		SYSERROR("failed to allocate memory for '%s'", buffer);
+		return -1;
+	}
+
+	line += lxc_char_left_gc(line, strlen(line));
+
+	/* ignore this line if it is commented or not started with CONFIG_ */
+	if ((*line == '#') || strncmp(line, "CONFIG_", 7))
+		goto out;
+
+	line += 7;
+	key = line;
+	value = NULL;
+	while (*line != '\n') {
+		if ((*line >= 'A' && *line <= 'Z') ||
+		    (*line >= 'a' && *line <= 'z') ||
+		    (*line >= '0' && *line <= '9') ||
+		    (*line == '_' )) {
+			line++;
+			continue;
+		} else if (*line == ' ' || *line == '=') {
+			*line = '\0';
+			value = line + 1;
+			break;
+		}
+	}
+	if (!value) {
+		ERROR("invalid creation configuration line: %s", linep);
+		goto out;
+	}
+
+	value += lxc_char_left_gc(value, strlen(value));
+	value[lxc_char_right_gc(value, strlen(value))] = '\0';
+	value = remove_left_right_quotation(value);
+
+	create_config = lxc_getcreateconfig(key);
+	if (!create_config) {
+		ERROR("unknown key %s", key);
+		goto out;
+	}
+
+	ret = create_config->cb(key, value, data);
+
+out:
+	free(linep);
+	return ret;
+}
+
+static bool read_conf_set_args(struct lxc_arguments* args)
+{
+	char *def_conf = ".config";
+
+	if (access(def_conf, R_OK) < 0) {
+		return false;
+	}
+
+	if (!lxc_file_for_each_line(def_conf, parse_config, args))
+		return true;
+
+	return false;
+}
+
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
 	switch (c) {
@@ -81,6 +483,18 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 	case '4': args->fssize = get_fssize(arg); break;
 	case '5': args->zfsroot = arg; break;
 	case '6': args->dir = arg; break;
+	case 'm':
+		/* create menuconfig */
+		if (!menuconfig(args)) {
+			fprintf(stderr, "Create menuconfig failed!\n");
+			return 1;
+		}
+		/* read config file, and set args */
+		if (!read_conf_set_args(args)) {
+			fprintf(stderr, "Failed to read creation config file!\n");
+			return 1;
+		}
+		break;
 	}
 	return 0;
 }
@@ -96,6 +510,7 @@ static const struct option my_longopts[] = {
 	{"fssize", required_argument, 0, '4'},
 	{"zfsroot", required_argument, 0, '5'},
 	{"dir", required_argument, 0, '6'},
+	{"menuconfig", no_argument, 0, 'm'},
 	LXC_COMMON_OPTIONS
 };
 
@@ -138,6 +553,7 @@ lxc-create creates a container\n\
 \n\
 Options :\n\
   -n, --name=NAME    NAME for name of the container\n\
+  -m, --menuconfig   Interactive configuration\n\
   -f, --config=file  Initial configuration file\n\
   -t, --template=t   Template to use to setup container\n\
   -B, --bdev=BDEV    Backing store type to use\n\
-- 
1.9.1



More information about the lxc-devel mailing list