[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