407 lines
12 KiB
Diff
407 lines
12 KiB
Diff
From b4e5d9e162a17f50367aad1ea92df7dc09fa34e9 Mon Sep 17 00:00:00 2001
|
|
From: LiFeng <lifeng68@huawei.com>
|
|
Date: Fri, 11 Jan 2019 01:51:25 -0500
|
|
Subject: [PATCH 003/140] confile: add lxc.isulad.populate.device interface
|
|
|
|
Signed-off-by: LiFeng <lifeng68@huawei.com>
|
|
---
|
|
src/lxc/conf.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
src/lxc/conf.h | 28 +++++++++++-
|
|
src/lxc/confile.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
3 files changed, 269 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
|
|
index f20d629..20b7aba 100644
|
|
--- a/src/lxc/conf.c
|
|
+++ b/src/lxc/conf.c
|
|
@@ -2745,6 +2745,10 @@ struct lxc_conf *lxc_conf_init(void)
|
|
memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
|
|
memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX);
|
|
|
|
+ /* isulad add begin */
|
|
+ lxc_list_init(&new->populate_devs);
|
|
+ /* isulad add end */
|
|
+
|
|
return new;
|
|
}
|
|
|
|
@@ -3487,6 +3491,85 @@ static bool execveat_supported(void)
|
|
return true;
|
|
}
|
|
|
|
+/* isulad: setup devices which will be populated in the container.*/
|
|
+static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list *devs)
|
|
+{
|
|
+ int ret;
|
|
+ char *pathdirname;
|
|
+ char path[MAXPATHLEN];
|
|
+ mode_t cmask;
|
|
+ mode_t file_mode = 0;
|
|
+ struct lxc_populate_devs *dev_elem;
|
|
+ struct lxc_list *it;
|
|
+
|
|
+ INFO("Populating devices into container");
|
|
+ cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
|
|
+ lxc_list_for_each(it, devs) {
|
|
+ dev_elem = it->elem;
|
|
+
|
|
+ ret = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->path ? rootfs->mount : "", dev_elem->name);
|
|
+ if (ret < 0 || ret >= MAXPATHLEN)
|
|
+ return -1;
|
|
+
|
|
+ /* create any missing directories */
|
|
+ pathdirname = strdup(path);
|
|
+ pathdirname = dirname(pathdirname);
|
|
+ ret = mkdir_p(pathdirname, 0750);
|
|
+ free(pathdirname);
|
|
+ if (ret < 0) {
|
|
+ WARN("Failed to create target directory");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(dev_elem->type, "c")) {
|
|
+ file_mode = dev_elem->file_mode | S_IFCHR;
|
|
+ } else if (!strcmp(dev_elem->type, "b")) {
|
|
+ file_mode = dev_elem->file_mode | S_IFBLK;
|
|
+ } else {
|
|
+ ERROR("Failed to parse devices type '%s'", dev_elem->type);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ DEBUG("Try to mknod '%s':'%d':'%d':'%d'\n", path,
|
|
+ file_mode, dev_elem->maj, dev_elem->min);
|
|
+
|
|
+ ret = mknod(path, file_mode, makedev(dev_elem->maj, dev_elem->min));
|
|
+ if (ret && errno != EEXIST) {
|
|
+ SYSERROR("Failed to mknod '%s':'%d':'%d':'%d'", dev_elem->name,
|
|
+ file_mode, dev_elem->maj, dev_elem->min);
|
|
+
|
|
+ char hostpath[MAXPATHLEN];
|
|
+ FILE *pathfile;
|
|
+
|
|
+ // Unprivileged containers cannot create devices, so
|
|
+ // try to bind mount the device from the host
|
|
+ ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", dev_elem->name);
|
|
+ if (ret < 0 || ret >= MAXPATHLEN)
|
|
+ return -1;
|
|
+ pathfile = fopen(path, "wb");
|
|
+ if (!pathfile) {
|
|
+ SYSERROR("Failed to create device mount target '%s'", path);
|
|
+ return -1;
|
|
+ }
|
|
+ fclose(pathfile);
|
|
+ if (safe_mount(hostpath, path, 0, MS_BIND, NULL,
|
|
+ rootfs->path ? rootfs->mount : NULL) != 0) {
|
|
+ SYSERROR("Failed bind mounting device %s from host into container",
|
|
+ dev_elem->name);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ if (chown(path, dev_elem->uid, dev_elem->gid) < 0) {
|
|
+ ERROR("Error chowning %s", path);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ umask(cmask);
|
|
+
|
|
+ INFO("Populated devices into container /dev");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int lxc_setup(struct lxc_handler *handler)
|
|
{
|
|
int ret;
|
|
@@ -3584,6 +3667,16 @@ int lxc_setup(struct lxc_handler *handler)
|
|
return -1;
|
|
}
|
|
|
|
+ /*isulad: move mount entrues here, before we do lxc_fill_autodev and populate devices */
|
|
+ if (!lxc_list_empty(&lxc_conf->mount_list)) {
|
|
+ ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
|
|
+ &lxc_conf->mount_list, name, lxcpath);
|
|
+ if (ret < 0) {
|
|
+ ERROR("Failed to setup mount entries");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
ret = run_lxc_hooks(name, "mount", lxc_conf, NULL);
|
|
if (ret < 0) {
|
|
ERROR("Failed to run mount hooks");
|
|
@@ -3604,12 +3697,11 @@ int lxc_setup(struct lxc_handler *handler)
|
|
}
|
|
}
|
|
|
|
- if (!lxc_list_empty(&lxc_conf->mount_list)) {
|
|
- ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
|
|
- &lxc_conf->mount_list, name, lxcpath);
|
|
- if (ret < 0) {
|
|
- ERROR("Failed to setup mount entries");
|
|
- return -1;
|
|
+ /* isulad: setup devices which will be populated in the container. */
|
|
+ if (!lxc_list_empty(&lxc_conf->populate_devs)) {
|
|
+ if (setup_populate_devs(&lxc_conf->rootfs, &lxc_conf->populate_devs)) {
|
|
+ ERROR("Failed to setup devices in the container");
|
|
+ return -1;;
|
|
}
|
|
}
|
|
|
|
@@ -4026,6 +4118,22 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf)
|
|
return 0;
|
|
}
|
|
|
|
+/*isulad: clear populate devices*/
|
|
+int lxc_clear_populate_devices(struct lxc_conf *c)
|
|
+{
|
|
+ struct lxc_list *it,*next;
|
|
+
|
|
+ lxc_list_for_each_safe(it, &c->populate_devs, next) {
|
|
+ struct lxc_populate_devs *dev_elem = it->elem;
|
|
+ lxc_list_del(it);
|
|
+ free(dev_elem->name);
|
|
+ free(dev_elem->type);
|
|
+ free(dev_elem);
|
|
+ free(it);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
void lxc_conf_free(struct lxc_conf *conf)
|
|
{
|
|
if (!conf)
|
|
@@ -4069,9 +4177,12 @@ void lxc_conf_free(struct lxc_conf *conf)
|
|
lxc_clear_limits(conf, "lxc.prlimit");
|
|
lxc_clear_sysctls(conf, "lxc.sysctl");
|
|
lxc_clear_procs(conf, "lxc.proc");
|
|
- lxc_clear_init_args(conf);
|
|
free(conf->cgroup_meta.dir);
|
|
free(conf->cgroup_meta.controllers);
|
|
+ /* isulad add begin */
|
|
+ lxc_clear_init_args(conf);
|
|
+ lxc_clear_populate_devices(conf);
|
|
+ /* isulad add end */
|
|
free(conf);
|
|
}
|
|
|
|
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
|
|
index 95c3027..cced868 100644
|
|
--- a/src/lxc/conf.h
|
|
+++ b/src/lxc/conf.h
|
|
@@ -171,6 +171,26 @@ struct lxc_rootfs {
|
|
};
|
|
|
|
/*
|
|
+ * iSulad: Defines a structure to store the devices which will
|
|
+ * be attached in container
|
|
+ * @name : the target device name in container
|
|
+ * @type : the type of target device "c" or "b"
|
|
+ * @mode : file mode for the device
|
|
+ * @maj : major number for the device
|
|
+ * @min : minor number for the device
|
|
+ */
|
|
+struct lxc_populate_devs {
|
|
+ char *name;
|
|
+ char *type;
|
|
+ mode_t file_mode;
|
|
+ int maj;
|
|
+ int min;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+};
|
|
+
|
|
+
|
|
+/*
|
|
* Automatic mounts for LXC to perform inside the container
|
|
*/
|
|
enum {
|
|
@@ -377,9 +397,13 @@ struct lxc_conf {
|
|
/* procs */
|
|
struct lxc_list procs;
|
|
|
|
- /* isulad add: init args used to repalce init_cmd*/
|
|
+ /* isulad add begin */
|
|
+ /* init args used to repalce init_cmd*/
|
|
char **init_argv;
|
|
size_t init_argc;
|
|
+ /* populate devices*/
|
|
+ struct lxc_list populate_devs;
|
|
+ /* isulad add end */
|
|
};
|
|
|
|
extern int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
|
|
@@ -448,6 +472,8 @@ extern int lxc_clear_procs(struct lxc_conf *c, const char *key);
|
|
|
|
/* isulad add begin */
|
|
int lxc_clear_init_args(struct lxc_conf *lxc_conf);
|
|
+int lxc_clear_populate_devices(struct lxc_conf *c);
|
|
+
|
|
/* isulad add end */
|
|
|
|
#endif /* __LXC_CONF_H */
|
|
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
|
|
index 7297b35..e3212d3 100644
|
|
--- a/src/lxc/confile.c
|
|
+++ b/src/lxc/confile.c
|
|
@@ -152,6 +152,7 @@ lxc_config_define(sysctl);
|
|
lxc_config_define(proc);
|
|
/*isulad add begin*/
|
|
lxc_config_define(init_args);
|
|
+lxc_config_define(populate_device);
|
|
/*isulad add end*/
|
|
|
|
|
|
@@ -241,6 +242,7 @@ static struct lxc_config_t config_jump_table[] = {
|
|
|
|
/*isulad add begin*/
|
|
{ "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, },
|
|
+ { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, },
|
|
/*isulad add end*/
|
|
};
|
|
|
|
@@ -2219,6 +2221,93 @@ static int set_config_init_args(const char *key, const char *value,
|
|
return 0;
|
|
}
|
|
|
|
+/* isulad: set config for init args */
|
|
+static int set_config_populate_device(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ int ret = 0, major = 0, minor = 0;
|
|
+ uid_t uid = (uid_t)-1;
|
|
+ gid_t gid = (gid_t)-1;
|
|
+ char name[PATH_MAX] = {0};
|
|
+ char type[3] = {0};
|
|
+ char *replace_value = NULL;
|
|
+ mode_t filemode = 0;
|
|
+ struct lxc_list *iter;
|
|
+ struct lxc_list *dev_list = NULL;
|
|
+ struct lxc_populate_devs *dev_elem = NULL;
|
|
+
|
|
+ if (lxc_config_value_empty(value))
|
|
+ return lxc_clear_populate_devices(lxc_conf);
|
|
+
|
|
+ /* lxc.populate.device = PATH_IN_CONTAINER:DEVICETYPE:MAJOR:MINOR:MODE:UID:GID
|
|
+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0
|
|
+ */
|
|
+ ret = sscanf(value, "%[^:]:%2[^:]:%i:%i:%i:%u:%u", name, type, &major, &minor, &filemode, &uid, &gid);
|
|
+ if (ret != 7)
|
|
+ return -1;
|
|
+
|
|
+ /* find existing list element */
|
|
+ lxc_list_for_each(iter, &lxc_conf->populate_devs) {
|
|
+ dev_elem = iter->elem;
|
|
+
|
|
+ if (strcmp(name, dev_elem->name) != 0)
|
|
+ continue;
|
|
+
|
|
+ replace_value = strdup(type);
|
|
+ if (!replace_value)
|
|
+ return -1;
|
|
+
|
|
+ free(dev_elem->type);
|
|
+ dev_elem->type = replace_value;
|
|
+ dev_elem->file_mode = filemode;
|
|
+ dev_elem->maj = major;
|
|
+ dev_elem->min = minor;
|
|
+ dev_elem->uid = (uid_t)uid;
|
|
+ dev_elem->gid = (gid_t)gid;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* allocate list element */
|
|
+ dev_list = malloc(sizeof(*dev_list));
|
|
+ if (!dev_list)
|
|
+ goto on_error;
|
|
+
|
|
+ lxc_list_init(dev_list);
|
|
+
|
|
+ dev_elem = malloc(sizeof(*dev_elem));
|
|
+ if (!dev_elem)
|
|
+ goto on_error;
|
|
+ memset(dev_elem, 0, sizeof(*dev_elem));
|
|
+
|
|
+ dev_elem->name = strdup(name);
|
|
+ if (!dev_elem->name)
|
|
+ goto on_error;
|
|
+
|
|
+ dev_elem->type = strdup(type);
|
|
+ if (!dev_elem->type)
|
|
+ goto on_error;
|
|
+
|
|
+ dev_elem->file_mode = filemode;
|
|
+ dev_elem->maj = major;
|
|
+ dev_elem->min = minor;
|
|
+
|
|
+ lxc_list_add_elem(dev_list, dev_elem);
|
|
+
|
|
+ lxc_list_add_tail(&lxc_conf->populate_devs, dev_list);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+on_error:
|
|
+ free(dev_list);
|
|
+ if (dev_elem) {
|
|
+ free(dev_elem->name);
|
|
+ free(dev_elem->type);
|
|
+ free(dev_elem);
|
|
+ }
|
|
+ return -1;
|
|
+
|
|
+}
|
|
+
|
|
struct parse_line_conf {
|
|
struct lxc_conf *conf;
|
|
bool from_include;
|
|
@@ -3770,6 +3859,34 @@ static int get_config_init_args(const char *key, char *retv, int inlen,
|
|
return fulllen;
|
|
}
|
|
|
|
+/* isulad: get config populate device
|
|
+ * If you ask for 'lxc.populate.device', then all populate device
|
|
+ * entries will be printed, in 'lxc.populate.device = path_in_container:type:major:minor:mode:uid:gid' format.
|
|
+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0
|
|
+ */
|
|
+static int get_config_populate_device(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ int len;
|
|
+ struct lxc_list *it;
|
|
+ int fulllen = 0;
|
|
+
|
|
+ if (!retv)
|
|
+ inlen = 0;
|
|
+ else
|
|
+ memset(retv, 0, inlen);
|
|
+
|
|
+ lxc_list_for_each(it, &c->populate_devs) {
|
|
+ struct lxc_populate_devs *elem = it->elem;
|
|
+ strprint(retv, inlen, "lxc.populate.device = %s:%s:%d:%d:%o:%u:%u\n",
|
|
+ elem->name, elem->type, elem->maj,
|
|
+ elem->min, elem->file_mode, elem->uid, elem->gid);
|
|
+ }
|
|
+
|
|
+ return fulllen;
|
|
+}
|
|
+
|
|
+
|
|
/* Callbacks to clear config items. */
|
|
static inline int clr_config_personality(const char *key, struct lxc_conf *c,
|
|
void *data)
|
|
@@ -4581,6 +4698,13 @@ static inline int clr_config_init_args(const char *key, struct lxc_conf *c,
|
|
return lxc_clear_init_args(c);
|
|
}
|
|
|
|
+/* isulad: clr config populate devices*/
|
|
+static inline int clr_config_populate_device(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ return lxc_clear_populate_devices(c);
|
|
+}
|
|
+
|
|
static int get_config_net_nic(const char *key, char *retv, int inlen,
|
|
struct lxc_conf *c, void *data)
|
|
{
|
|
--
|
|
1.8.3.1
|
|
|