[lxc-devel] [PATCH 9/9] lxc-device: rewrite lxc-device.

Serge Hallyn serge.hallyn at ubuntu.com
Fri Sep 19 23:56:18 UTC 2014


Quoting Stéphane Graber (stgraber at ubuntu.com):
> On Fri, Sep 19, 2014 at 09:57:57PM +0000, Serge Hallyn wrote:
> > Quoting Dongsheng Yang (yangds.fnst at cn.fujitsu.com):
> > > As there is a function named attach_interface to pass
> > > a interface to container now, we do not need to relay on
> > > python impolementation for lxc-device any more.
> > 
> > Don't we still need it for non-network device node?
> 
> That new lxc_device does that too.

D'oh.

> > > Signed-off-by: Dongsheng Yang <yangds.fnst at cn.fujitsu.com>

Thanks, I added a few more notes below, but with all of those
fixed

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

> > > ---
> > >  src/lxc/Makefile.am  |   4 +-
> > >  src/lxc/lxc-device   |  97 ------------------------------
> > >  src/lxc/lxc_device.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 168 insertions(+), 99 deletions(-)
> > >  delete mode 100644 src/lxc/lxc-device
> > >  create mode 100644 src/lxc/lxc_device.c
> > > 
> > > diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
> > > index 8322e62..dab5350 100644
> > > --- a/src/lxc/Makefile.am
> > > +++ b/src/lxc/Makefile.am
> > > @@ -163,14 +163,12 @@ endif
> > >  bin_SCRIPTS = lxc-checkconfig
> > >  
> > >  EXTRA_DIST = \
> > > -	lxc-device \
> > >  	lxc-ls \
> > >  	lxc-top \
> > >  	lxc.net \
> > >  	lxc-restore-net
> > >  
> > >  if ENABLE_PYTHON
> > > -bin_SCRIPTS += lxc-device
> > >  bin_SCRIPTS += lxc-ls
> > >  bin_SCRIPTS += lxc-start-ephemeral
> > >  else
> > > @@ -191,6 +189,7 @@ bin_PROGRAMS = \
> > >  	lxc-console \
> > >  	lxc-create \
> > >  	lxc-destroy \
> > > +	lxc-device \
> > >  	lxc-execute \
> > >  	lxc-freeze \
> > >  	lxc-info \
> > > @@ -222,6 +221,7 @@ lxc_cgroup_SOURCES = lxc_cgroup.c
> > >  lxc_config_SOURCES = lxc_config.c
> > >  lxc_console_SOURCES = lxc_console.c
> > >  lxc_destroy_SOURCES = lxc_destroy.c
> > > +lxc_device_SOURCES = lxc_device.c
> > >  lxc_execute_SOURCES = lxc_execute.c
> > >  lxc_freeze_SOURCES = lxc_freeze.c
> > >  lxc_info_SOURCES = lxc_info.c
> > > diff --git a/src/lxc/lxc-device b/src/lxc/lxc-device
> > > deleted file mode 100644
> > > index dca161e..0000000
> > > --- a/src/lxc/lxc-device
> > > +++ /dev/null
> > > @@ -1,97 +0,0 @@
> > > -#!/usr/bin/python3
> > > -#
> > > -# lxc-device: Add devices to a running container
> > > -#
> > > -# This python implementation is based on the work done in the original
> > > -# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
> > > -#
> > > -# (C) Copyright Canonical Ltd. 2012
> > > -#
> > > -# Authors:
> > > -# Stéphane Graber <stgraber at ubuntu.com>
> > > -#
> > > -# This library is free software; you can redistribute it and/or
> > > -# modify it under the terms of the GNU Lesser General Public
> > > -# License as published by the Free Software Foundation; either
> > > -# version 2.1 of the License, or (at your option) any later version.
> > > -#
> > > -# This library is distributed in the hope that it will be useful,
> > > -# but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > > -# Lesser General Public License for more details.
> > > -#
> > > -# You should have received a copy of the GNU Lesser General Public
> > > -# License along with this library; if not, write to the Free Software
> > > -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> > > -#
> > > -
> > > -import argparse
> > > -import gettext
> > > -import lxc
> > > -import os
> > > -
> > > -_ = gettext.gettext
> > > -gettext.textdomain("lxc-device")
> > > -
> > > -# Begin parsing the command line
> > > -parser = argparse.ArgumentParser(description=_("LXC: Manage devices"),
> > > -                                 formatter_class=argparse.RawTextHelpFormatter)
> > > -
> > > -# Global arguments
> > > -parser.add_argument("-n", dest="container", metavar="CONTAINER",
> > > -                    help=_("Name of the container to add the device to"),
> > > -                    required=True)
> > > -
> > > -parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH",
> > > -                    help=_("Use specified container path"), default=None)
> > > -
> > > -parser.add_argument("--version", action="version", version=lxc.version)
> > > -
> > > -# Commands
> > > -subparsers = parser.add_subparsers()
> > > -subparser_add = subparsers.add_parser('add', help=_('Add a device'))
> > > -subparser_add.set_defaults(action="add")
> > > -
> > > -subparser_add.add_argument(dest="device", metavar="DEVICE",
> > > -                           help=_("Add a device "
> > > -                                  "(path to a node or interface name)"))
> > > -
> > > -subparser_add.add_argument(dest="name", metavar="NAME", nargs="?",
> > > -                           help=_("Use an alternative path or name "
> > > -                                  "in the container"))
> > > -
> > > -args = parser.parse_args()
> > > -
> > > -# Some basic checks
> > > -## Check for valid action
> > > -if not hasattr(args, "action"):
> > > -    parser.error(_("You must specify an action."))
> > > -
> > > -## Don't rename if no alternative name
> > > -if not args.name:
> > > -    args.name = args.device
> > > -
> > > -## Check that the container is ready
> > > -container = lxc.Container(args.container, args.lxcpath)
> > > -
> > > -## Check that we have control over the container
> > > -if not container.controllable:
> > > -    parser.error("Insufficent privileges to control: %s" % container.name)
> > > -
> > > -## Check that the container is running
> > > -if not container.running:
> > > -    parser.error("The container must be running.")
> > > -
> > > -# Do the work
> > > -if args.action == "add":
> > > -    if os.path.exists("/sys/class/net/%s/" % args.device):
> > > -        ret = container.add_device_net(args.device, args.name)
> > > -    else:
> > > -        ret = container.add_device_node(args.device, args.name)
> > > -
> > > -    if ret:
> > > -        print("Added '%s' to '%s' as '%s'." %
> > > -              (args.device, container.name, args.name))
> > > -    else:
> > > -        print("Failed to add '%s' to '%s' as '%s'." %
> > > -              (args.device, container.name, args.name))
> > > diff --git a/src/lxc/lxc_device.c b/src/lxc/lxc_device.c
> > > new file mode 100644
> > > index 0000000..963f934
> > > --- /dev/null
> > > +++ b/src/lxc/lxc_device.c
> > > @@ -0,0 +1,166 @@
> > > +/*
> > > + * lxc: linux Container library
> > > + *
> > > + * Authors:
> > > + * Dongsheng Yang <yangds.fnst at cn.fujitsu.com>
> > > + *
> > > + * This library is free software; you can redistribute it and/or
> > > + * modify it under the terms of the GNU Lesser General Public
> > > + * License as published by the Free Software Foundation; either
> > > + * version 2.1 of the License, or (at your option) any later version.
> > > + *
> > > + * This library is distributed in the hope that it will be useful,
> > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > > + * Lesser General Public License for more details.
> > > + *
> > > + * You should have received a copy of the GNU Lesser General Public
> > > + * License along with this library; if not, write to the Free Software
> > > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> > > + */
> > > +#include <stdio.h>
> > > +#include <unistd.h>
> > > +#include <sys/types.h>
> > > +#include <libgen.h>
> > > +#include <string.h>
> > > +#include <limits.h>
> > > +
> > > +#include <lxc/lxccontainer.h>
> > > +
> > > +#include "utils.h"
> > > +#include "lxc.h"
> > > +#include "log.h"
> > > +
> > > +#include "arguments.h"
> > > +
> > > +#if HAVE_IFADDRS_H
> > > +#include <ifaddrs.h>
> > > +#else
> > > +#include <../include/ifaddrs.h>
> > > +#endif
> > > +
> > > +lxc_log_define(lxc_device, lxc);
> > > +
> > > +static const struct option my_longopts[] = {
> > > +	LXC_COMMON_OPTIONS
> > > +};
> > > +
> > > +static struct lxc_arguments my_args = {
> > > +	.progname = "lxc-devicee",
> 
> Type above.
> 
> > > +	.help     = "\
> > > +--name=NAME -- COMMAND\n\
> > > +\n\
> > > +lxc-device attach or detach device to container.\n\
> > > +lxc-device -n name add|del ifname.\n\
> > > +\n\
> > > +Options :\n\
> > > +  -n, --name=NAME      NAME for name of the container",
> 
> Could be updated to ressemble the output from the other C programs a bit more.
> 
> > > +	.options  = my_longopts,
> > > +	.parser   = NULL,
> > > +	.checker  = NULL,
> > > +};
> > > +
> > > +static bool is_interface(const char* dev_name, pid_t pid)
> > > +{
> > > +	pid_t p = fork();

Please do check for fork failure.

> > > +	if (p == 0) {
> > > +		struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
> > > +
> > > +		switch_to_newnet(pid);

Check for failure.

> > > +		/* Grab the list of interfaces */
> > > +		if (getifaddrs(&interfaceArray)) {
> > > +			ERROR("failed to get interfaces list");
> > > +			exit(-1);
> > > +		}
> > > +
> > > +		/* Iterate through the interfaces */
> > > +		for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
> > > +			if (strcmp(tempIfAddr->ifa_name, dev_name) == 0) {
> > > +				exit(0);
> > > +			}
> > > +		}
> > > +		exit(1);
> > > +	}
> > > +
> > > +	if (wait_for_pid(p) == 0) {
> > > +		return true;
> > > +	}
> > > +	return false;
> > > +}
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +	struct lxc_container *c;
> > > +	char *cmd, *dev_name, *dst_name;
> > > +	int ret = 1;
> > > +
> > > +	if (lxc_arguments_parse(&my_args, argc, argv))
> > > +		goto err;
> > > +
> > > +	if (!my_args.log_file)
> > > +		my_args.log_file = "none";
> > > +
> > > +	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
> > > +			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
> > > +		goto err;
> > > +	lxc_log_options_no_override();
> > > +
> > > +	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
> > > +	if (!c) {
> > > +		ERROR("No such container: %s:%s", my_args.lxcpath[0], my_args.name);
> 
> The standard error message for that is "%s doesn't exist", my_args.name
> 
> > > +		goto err;
> > > +	}
> > > +
> > > +	if (!c->is_running(c)) {
> > > +		ERROR("Container %s is not running.", c->name);
> > > +		goto err1;
> > > +	}
> > > +
> > > +	if (my_args.argc < 2) {
> > > +		ERROR(my_args.help);
> > > +		goto err1;
> > > +	}
> > > +
> > > +	cmd = my_args.argv[0];
> > > +	dev_name = my_args.argv[1];
> > > +	if (my_args.argc < 3)
> > > +		dst_name = dev_name;
> > > +	else
> > > +		dst_name = my_args.argv[2];
> > > +
> > > +	if (strcmp(cmd, "add") == 0) {
> > > +		if (is_interface(dev_name, 1)) {
> > > +			ret = c->attach_interface(c, dev_name, dst_name);
> > > +		} else {
> > > +			ret = c->add_device_node(c, dev_name, dst_name);
> > > +		}
> > > +		if (ret != true) {
> > > +			ERROR("Failed to add %s to %s.", dev_name, c->name);
> > > +			ret = 1;
> > > +			goto err1;
> > > +		}
> > > +		INFO("Added %s to %s.", dev_name, c->name);
> > > +	} else if (strcmp(cmd, "del") == 0) {
> > > +		if (is_interface(dev_name, c->init_pid(c))) {
> > > +			ret = c->detach_interface(c, dev_name, dst_name);
> > > +		} else {
> > > +			ret = c->remove_device_node(c, dev_name, dst_name);
> > > +		}
> > > +		if (ret != true) {
> > > +			ERROR("Failed to del %s from %s.", dev_name, c->name);
> > > +			ret = 1;
> > > +			goto err1;
> > > +		}
> > > +		INFO("Deled %s from %s.", dev_name, c->name);
> 
> Typo
> 
> > > +	} else {
> > > +		ERROR(my_args.help);
> > > +		goto err1;
> > > +	}
> > > +	exit(0);
> > > +err1:
> > > +	lxc_container_put(c);
> > > +err:
> > > +	exit(ret);
> > > +}
> > > -- 
> > > 1.8.4.2
> > > 
> 
> -- 
> Stéphane Graber
> Ubuntu developer
> http://www.ubuntu.com




More information about the lxc-devel mailing list