]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Teach lxc_unshare about interfaces, mounts, hostname, daemonize
authorSeth Robertson <srobertson@appcomsci.com>
Wed, 4 Dec 2013 05:28:56 +0000 (00:28 -0500)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 15 Jan 2014 21:42:36 +0000 (15:42 -0600)
lxc_unshare now takes one or more '-i interfacename' arguments which
will move the named interfaces into the created container.

lxc_unshare now takes -M argument which will cause the standard mounts
(/proc /dev/shm /dev/mqueue) to be auto-mounted inside container.

lxc_unshare now takes '-H hostname' argument to automatically set
the hostname in the container.

lxc_unshare now takes -D argument to automatically daemonize and detach
from the created container, instead of waiting for the container to exit

Signed-off-by: Seth Robertson <srobertson@appcomsci.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
doc/lxc-unshare.sgml.in
src/lxc/lxc_unshare.c

index 9d3be22edfa0058daf19453dc30f7d32ff4125e7..678ae9e8e29e7326808311a02afe3c63f3b435ad 100644 (file)
@@ -52,6 +52,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <command>lxc-unshare</command>
       <arg choice="req">-s <replaceable>namespaces</replaceable></arg>
       <arg choice="opt">-u <replaceable>user</replaceable></arg>
+      <arg choice="opt">-H <replaceable>hostname</replaceable></arg>
+      <arg choice="opt">-i <replaceable>ifname</replaceable></arg>
+      <arg choice="opt">-d</arg>
+      <arg choice="opt">-M</arg>
       <arg choice="req">command</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -105,6 +109,55 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term>
+         <option>-H <replaceable>hostname</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+           Set the hostname in the new container.  Only allowed if
+           the UTSNAME namespace is set.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-i <replaceable>interfacename</replaceable></option>
+       </term>
+       <listitem>
+         <para>
+           Move the named interface into the container.  Only allowed
+           if the NETWORK namespace is set.  You may specify this
+           argument multiple times to move multiple interfaces into
+           container.
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-d</option>
+       </term>
+       <listitem>
+         <para>
+           Daemonize (do not wait for the container to exit before exiting)
+         </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>
+         <option>-M</option>
+       </term>
+       <listitem>
+         <para>
+           Mount default filesystems (/proc /dev/shm and /dev/mqueue)
+           in the container.  Only allowed if MOUNT namespace is set.
+         </para>
+       </listitem>
+      </varlistentry>
+
     </variablelist>
 
   </refsect1>
@@ -131,6 +184,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
         </programlisting>
        ps output will show there are no other processes in the namespace.
       </para>
+      <para>
+        To spawn a shell in a new network, pid, mount, and hostname
+        namespace.
+        <programlisting>
+          lxc-unshare -s "NETWORK|PID|MOUNT|UTSNAME" -M -H slave -i veth1 /bin/bash
+        </programlisting>
+
+       The resulting shell will have pid 1 and will see two network
+       interfaces (lo and veth1).  The hostname will be "slave" and
+       /proc will have been remounted.  ps output will show there are
+       no other processes in the namespace.
+      </para>
   </refsect1>
 
   &seealso;
index 4c82e9e8d740eacf5272e70e3fd983096035de10..ed3bf478a7232f7aa96f52681d85dca628c0b828 100644 (file)
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <pwd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
 
 #include "caps.h"
 #include "log.h"
 #include "namespace.h"
+#include "network.h"
+#include "utils.h"
 #include "cgroup.h"
 #include "error.h"
 
 lxc_log_define(lxc_unshare_ui, lxc);
 
+struct my_iflist
+{
+       char *mi_ifname;
+       struct my_iflist *mi_next;
+};
+
 static void usage(char *cmd)
 {
        fprintf(stderr, "%s <options> command [command_arguments]\n", basename(cmd));
        fprintf(stderr, "Options are:\n");
-       fprintf(stderr, "\t -s flags: ORed list of flags to unshare:\n" \
+       fprintf(stderr, "\t -s flags   : ORed list of flags to unshare:\n" \
                        "\t           MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
-       fprintf(stderr, "\t -u <id> : new id to be set if -s USER is specified\n");
+       fprintf(stderr, "\t -u <id>      : new id to be set if -s USER is specified\n");
+       fprintf(stderr, "\t -i <iface>   : Interface name to be moved into container (presumably with NETWORK unsharing set)\n");
+       fprintf(stderr, "\t -H <hostname>: Set the hostname in the container\n");
+       fprintf(stderr, "\t -d           : Daemonize (do not wait for container to exit)\n");
+       fprintf(stderr, "\t -M           : reMount default fs inside container (/proc /dev/shm /dev/mqueue)\n");
        _exit(1);
 }
 
@@ -88,6 +102,8 @@ struct start_arg {
        char ***args;
        int *flags;
        uid_t *uid;
+        int want_default_mounts;
+        const char *want_hostname;
 };
 
 static int do_start(void *arg)
@@ -96,6 +112,17 @@ static int do_start(void *arg)
        char **args = *start_arg->args;
        int flags = *start_arg->flags;
        uid_t uid = *start_arg->uid;
+       int want_default_mounts = start_arg->want_default_mounts;
+       const char *want_hostname = start_arg->want_hostname;
+
+       if ((flags & CLONE_NEWNS) && want_default_mounts)
+               lxc_setup_fs();
+
+       if ((flags & CLONE_NEWUTS) && want_hostname)
+               if (sethostname(want_hostname, strlen(want_hostname)) < 0) {
+                       ERROR("failed to set hostname %s: %s", want_hostname, strerror(errno));
+                       exit(1);
+               }
 
        // Setuid is useful even without a new user id space
        if ( uid >= 0 && setuid(uid)) {
@@ -116,22 +143,44 @@ int main(int argc, char *argv[])
        char *namespaces = NULL;
        char **args;
        int flags = 0;
+       int daemonize = 0;
        uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
        pid_t pid;
-
+       struct my_iflist *tmpif, *my_iflist = NULL;
        struct start_arg start_arg = {
                .args = &args,
                .uid = &uid,
                .flags = &flags,
+               .want_hostname = NULL,
+               .want_default_mounts = 0,
        };
 
-       while ((opt = getopt(argc, argv, "s:u:h")) != -1) {
+       while ((opt = getopt(argc, argv, "s:u:hH:i:dM")) != -1) {
                switch (opt) {
                case 's':
                        namespaces = optarg;
                        break;
+               case 'i':
+                       if (!(tmpif = malloc(sizeof(*tmpif)))) {
+                               perror("malloc");
+                               exit(1);
+                       }
+                       tmpif->mi_ifname = optarg;
+                       tmpif->mi_next = my_iflist;
+                       my_iflist = tmpif;
+                       break;
+               case 'd':
+                       daemonize = 1;
+                       break;
+               case 'M':
+                       start_arg.want_default_mounts = 1;
+                       break;
+               case 'H':
+                       start_arg.want_hostname = optarg;
+                       break;
                case 'h':
                        usage(argv[0]);
+                       break;
                case 'u':
                        uid = lookup_user(optarg);
                        if (uid == -1)
@@ -154,6 +203,18 @@ int main(int argc, char *argv[])
        if (ret)
                usage(argv[0]);
 
+       if (!(flags & CLONE_NEWNET) && my_iflist) {
+               ERROR("-i <interfacename> needs -s NETWORK option");
+               return 1;
+       }
+
+       if (!(flags & CLONE_NEWUTS) && start_arg.want_hostname) {
+               ERROR("-H <hostname> needs -s UTSNAME option");
+               return 1;
+       }
+
+       if (!(flags & CLONE_NEWNS) && start_arg.want_default_mounts) {
+               ERROR("-M needs -s MOUNT option");
                return 1;
        }
 
@@ -163,6 +224,16 @@ int main(int argc, char *argv[])
                return -1;
        }
 
+       if (my_iflist) {
+               for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) {
+                       if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid) < 0)
+                               fprintf(stderr,"Could not move interface %s into container %d: %s\n", tmpif->mi_ifname, pid, strerror(errno));
+               }
+       }
+
+       if (daemonize)
+               exit(0);
+
        if (waitpid(pid, &status, 0) < 0) {
                ERROR("failed to wait for '%d'", pid);
                return -1;