]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxc-device: rewrite lxc-device.
authorDongsheng Yang <yangds.fnst@cn.fujitsu.com>
Tue, 16 Sep 2014 09:12:00 +0000 (17:12 +0800)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 15 Oct 2014 10:47:09 +0000 (12:47 +0200)
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 <yangds.fnst@cn.fujitsu.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
src/lxc/Makefile.am
src/lxc/lxc-device [deleted file]
src/lxc/lxc_device.c [new file with mode: 0644]

index da3f78e1f64f9d44446f2f35f00ceb8a0820505d..840e1c7c5df9fe2dc81ae83fea373bfbbb91363b 100644 (file)
@@ -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 (file)
index dca161e..0000000
+++ /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@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 (file)
index 0000000..6d715d3
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * lxc: linux Container library
+ *
+ * Authors:
+ * Dongsheng Yang <yangds.fnst@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-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);
+}