[lxc-devel] [PATCH] introduce lxcapi_add_device_node and lxcapi_remove_device_node to API (v3)

Stéphane Graber stgraber at ubuntu.com
Wed Nov 13 14:59:25 UTC 2013


On Wed, Nov 13, 2013 at 12:39:00AM -0500, S.Çağlar Onur wrote:
> 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 <caglar at 10ur.org>

Hi,

So at first glance the reason why the remove function also take both src
and dest path wasn't very obvious though after thinking about it some
more, I guess it makes sense to always look for type/major/minor of the
source device, so passing only the dest path wouldn't work. And it's
possible that at some point we may want to do something again the dest
path (like removing it) so it doesn't hurt to have it passed too (though
at this point, passing it or not shouldn't make any difference).


Acked-by: Stéphane Graber <stgraber at ubuntu.com>

Note that Serge pushed v0 by accident but he then reverted it, so I'll
push v3 now.

> ---
>  src/lxc/lxccontainer.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/lxc/lxccontainer.h |  19 ++++++++++
>  2 files changed, 119 insertions(+)
> 
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 05ca643..2a70bc7 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -49,6 +49,7 @@
>  #include <lxc/namespace.h>
>  #include <sched.h>
>  #include <arpa/inet.h>
> +#include <libgen.h>
>  
>  #if HAVE_IFADDRS_H
>  #include <ifaddrs.h>
> @@ -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 486035a..3a12372 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 {
> -- 
> 1.8.3.2
> 
> 
> ------------------------------------------------------------------------------
> DreamFactory - Open Source REST & JSON Services for HTML5 & Native Apps
> OAuth, Users, Roles, SQL, NoSQL, BLOB Storage and External API Access
> Free app hosting. Or install the open source package on any LAMP server.
> Sign up and see examples for AngularJS, jQuery, Sencha Touch and Native!
> http://pubads.g.doubleclick.net/gampad/clk?id=63469471&iu=/4140/ostg.clktrk
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20131113/3d78d254/attachment.pgp>


More information about the lxc-devel mailing list