From ea467969450684c268a5a3abff36b8ec36557080 Mon Sep 17 00:00:00 2001 From: Dongsheng Yang Date: Tue, 16 Sep 2014 17:12:00 +0800 Subject: [PATCH] lxc-device: rewrite lxc-device. 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. changelog: 10/15/2014: serge: fail immediately if run as non-root. changelog: 10/15/2014: serge: add explicit error message on bad usage (fix build failure) Signed-off-by: Dongsheng Yang Acked-by: Serge E. Hallyn --- src/lxc/Makefile.am | 4 +- src/lxc/lxc-device | 97 ----------------------- src/lxc/lxc_device.c | 178 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 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 da3f78e1f6..840e1c7c5d 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -163,13 +163,11 @@ endif bin_SCRIPTS = lxc-checkconfig EXTRA_DIST = \ - lxc-device \ lxc-ls \ lxc-restore-net \ lxc-top.lua if ENABLE_PYTHON -bin_SCRIPTS += lxc-device bin_SCRIPTS += lxc-ls bin_SCRIPTS += lxc-start-ephemeral else @@ -186,6 +184,7 @@ bin_PROGRAMS = \ lxc-console \ lxc-create \ lxc-destroy \ + lxc-device \ lxc-execute \ lxc-freeze \ lxc-info \ @@ -218,6 +217,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 dca161e008..0000000000 --- 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 -# -# 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 0000000000..6d715d36c3 --- /dev/null +++ b/src/lxc/lxc_device.c @@ -0,0 +1,178 @@ +/* + * lxc: linux Container library + * + * Authors: + * Dongsheng Yang + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "lxc.h" +#include "log.h" + +#include "arguments.h" + +#if HAVE_IFADDRS_H +#include +#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-device", + .help = "\ +--name=NAME -- add|del DEV\n\ +\n\ +lxc-device attach or detach DEV to or from container.\n\ +\n\ +Options :\n\ + -n, --name=NAME NAME for name of the container", + .options = my_longopts, + .parser = NULL, + .checker = NULL, +}; + +static bool is_interface(const char* dev_name, pid_t pid) +{ + pid_t p = fork(); + + if (p < 0) { + SYSERROR("failed to fork task."); + exit(1); + } + + if (p == 0) { + struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; + + if (!switch_to_ns(pid, "net")) { + ERROR("failed to enter netns of container."); + exit(-1); + } + + /* 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 (geteuid() != 0) { + ERROR("%s must be run as root", argv[0]); + exit(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("%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("Error: no command given (Please see --help output)"); + 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("Add %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("Delete %s from %s.", dev_name, c->name); + } else { + ERROR("Error: Please use add or del (Please see --help output)"); + goto err1; + } + exit(0); +err1: + lxc_container_put(c); +err: + exit(ret); +}