From: S.Çağlar Onur Date: Wed, 13 Nov 2013 05:39:00 +0000 (-0500) Subject: introduce lxcapi_add_device_node and lxcapi_remove_device_node to API (v3) X-Git-Tag: lxc-1.0.0.alpha3~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9a0ed90dd1cdadd412576a45af16419efc0e939;p=thirdparty%2Flxc.git introduce lxcapi_add_device_node and lxcapi_remove_device_node to API (v3) Adding block/char devices to running container is a common operation so provide a common implementation for users to consume. changes since v2; * lets the user set an alternate path inside the container as Stéphane suggested changes since v1; * removed duplicated code Signed-off-by: S.Çağlar Onur Acked-by: Stéphane Graber --- diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 05ca643ec..2a70bc7fd 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -49,6 +49,7 @@ #include #include #include +#include #if HAVE_IFADDRS_H #include @@ -62,6 +63,8 @@ #endif #endif +#define MAX_BUFFER 4096 + lxc_log_define(lxc_container, lxc); static bool file_exists(char *f) @@ -2920,6 +2923,101 @@ static bool lxcapi_may_control(struct lxc_container *c) return lxc_try_cmd(c->name, c->config_path) == 0; } +static bool add_remove_device_node(struct lxc_container *c, char *src_path, char *dest_path, bool add) +{ + int ret; + struct stat st; + char path[MAXPATHLEN]; + char value[MAX_BUFFER]; + char *directory_path = NULL, *p; + + /* make sure container is running */ + if (!c->is_running(c)) { + ERROR("container is not running"); + goto out; + } + + /* use src_path if dest_path is NULL otherwise use dest_path */ + p = dest_path ? dest_path : src_path; + + /* prepare the path */ + ret = snprintf(path, MAXPATHLEN, "/proc/%d/root/%s", c->init_pid(c), p); + if (ret < 0 || ret >= MAXPATHLEN) + goto out; + remove_trailing_slashes(path); + + p = add ? src_path : path; + /* make sure we can access p */ + if(access(p, F_OK) < 0 || stat(p, &st) < 0) + goto out; + + /* continue if path is character device or block device */ + if S_ISCHR(st.st_mode) + ret = snprintf(value, MAX_BUFFER, "c %d:%d rwm", major(st.st_rdev), minor(st.st_rdev)); + else if S_ISBLK(st.st_mode) + ret = snprintf(value, MAX_BUFFER, "b %d:%d rwm", major(st.st_rdev), minor(st.st_rdev)); + else + goto out; + + /* check snprintf return code */ + if (ret < 0 || ret >= MAX_BUFFER) + goto out; + + directory_path = dirname(strdup(path)); + /* remove path and directory_path (if empty) */ + if(access(path, F_OK) == 0) { + if (unlink(path) < 0) { + ERROR("unlink failed"); + goto out; + } + if (rmdir(directory_path) < 0 && errno != ENOTEMPTY) { + ERROR("rmdir failed"); + goto out; + } + } + + if (add) { + /* create the missing directories */ + if (mkdir_p(directory_path, 0755) < 0) { + ERROR("failed to create directory"); + goto out; + } + + /* create the device node */ + if (mknod(path, st.st_mode, st.st_rdev) < 0) { + ERROR("mknod failed"); + goto out; + } + + /* add device node to device list */ + if (!c->set_cgroup_item(c, "devices.allow", value)) { + ERROR("set_cgroup_item failed while adding the device node"); + goto out; + } + } else { + /* remove device node from device list */ + if (!c->set_cgroup_item(c, "devices.deny", value)) { + ERROR("set_cgroup_item failed while removing the device node"); + goto out; + } + } + return true; +out: + if (directory_path) + free(directory_path); + return false; +} + +static bool lxcapi_add_device_node(struct lxc_container *c, char *src_path, char *dest_path) +{ + return add_remove_device_node(c, src_path, dest_path, true); +} + +static bool lxcapi_remove_device_node(struct lxc_container *c, char *src_path, char *dest_path) +{ + return add_remove_device_node(c, src_path, dest_path, false); +} + static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...) { va_list ap; @@ -3041,6 +3139,8 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->snapshot_restore = lxcapi_snapshot_restore; c->snapshot_destroy = lxcapi_snapshot_destroy; c->may_control = lxcapi_may_control; + c->add_device_node = lxcapi_add_device_node; + c->remove_device_node = lxcapi_remove_device_node; /* we'll allow the caller to update these later */ if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) { diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 486035a26..3a1237248 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -236,6 +236,25 @@ struct lxc_container { * and the caller may not access it. Return true otherwise. */ bool (*may_control)(struct lxc_container *c); + + /* + * add_device_node: + * @c : the running container + * @src_path : the path of the device + * @dest_path: the alternate path in the container. If NULL, the src_path is used + * + * Returns true if given device succesfully added to container + */ + bool (*add_device_node)(struct lxc_container *c, char *src_path, char *dest_path); + /* + * remove_device_node: + * @c : the running container + * @src_path : the path of the device + * @dest_path: the alternate path in the container. If NULL, the src_path is used + * + * Returns true if given device succesfully removed from container + */ + bool (*remove_device_node)(struct lxc_container *c, char *src_path, char *dest_path); }; struct lxc_snapshot {