diff --git a/doc/lxc-unshare.sgml.in b/doc/lxc-unshare.sgml.in
index 9d3be22edf..678ae9e8e2 100644
--- a/doc/lxc-unshare.sgml.in
+++ b/doc/lxc-unshare.sgml.in
@@ -52,6 +52,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
lxc-unshare-s namespaces-u user
+ -H hostname
+ -i ifname
+ -d
+ -Mcommand
@@ -105,6 +109,55 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+
+
+
+
+ Set the hostname in the new container. Only allowed if
+ the UTSNAME namespace is set.
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+ Daemonize (do not wait for the container to exit before exiting)
+
+
+
+
+
+
+
+
+
+
+ Mount default filesystems (/proc /dev/shm and /dev/mqueue)
+ in the container. Only allowed if MOUNT namespace is set.
+
+
+
+
@@ -131,6 +184,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ps output will show there are no other processes in the namespace.
+
+ To spawn a shell in a new network, pid, mount, and hostname
+ namespace.
+
+ lxc-unshare -s "NETWORK|PID|MOUNT|UTSNAME" -M -H slave -i veth1 /bin/bash
+
+
+ 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.
+
&seealso;
diff --git a/src/lxc/lxc_unshare.c b/src/lxc/lxc_unshare.c
index 4c82e9e8d7..ed3bf478a7 100644
--- a/src/lxc/lxc_unshare.c
+++ b/src/lxc/lxc_unshare.c
@@ -33,22 +33,36 @@
#include
#include
#include
+#include
+#include
#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 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 : new id to be set if -s USER is specified\n");
+ fprintf(stderr, "\t -u : new id to be set if -s USER is specified\n");
+ fprintf(stderr, "\t -i : Interface name to be moved into container (presumably with NETWORK unsharing set)\n");
+ fprintf(stderr, "\t -H : 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 needs -s NETWORK option");
+ return 1;
+ }
+
+ if (!(flags & CLONE_NEWUTS) && start_arg.want_hostname) {
+ ERROR("-H 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;