mirror of
git://github.com/lxc/lxc
synced 2025-08-31 05:19:37 +00:00
Teach lxc_unshare about interfaces, mounts, hostname, daemonize
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>
This commit is contained in:
committed by
Serge Hallyn
parent
13d8bde96f
commit
c1bb25a831
@@ -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;
|
||||
|
@@ -33,22 +33,36 @@
|
||||
#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;
|
||||
|
Reference in New Issue
Block a user