summaryrefslogtreecommitdiffstats
path: root/sys-utils/unshare.c
diff options
context:
space:
mode:
authorNeil Horman2012-12-28 17:22:18 +0100
committerKarel Zak2013-01-07 14:56:32 +0100
commit4bbe8099390d528018890efa914e268de3c4b44b (patch)
tree79201355c9ad29ff76cf5aa8ba11423bf1a76c78 /sys-utils/unshare.c
parentagetty: replace perms 660 to 620 (diff)
downloadkernel-qcow2-util-linux-4bbe8099390d528018890efa914e268de3c4b44b.tar.gz
kernel-qcow2-util-linux-4bbe8099390d528018890efa914e268de3c4b44b.tar.xz
kernel-qcow2-util-linux-4bbe8099390d528018890efa914e268de3c4b44b.zip
unshare: support the switching of namespaces
In addition to the unshare syscall, there exists the setns syscall, which allows processes to migrate to the namepsaces of other processes. Add this functionality into the unshare command, as they operate in a fairly simmilar fashion. Note: There was discussion of adding a path based namespace argument to unshare in the origional discussion thread, but I opted to leave that out as it didn't seem to fit in nicely with the current argument pattern. I figure we can always add that in later if we need to [kzak@redhat.com: - fix optional arguments - do not call unshare if no flag specified - use O_CLOEXEC - codding style cleanup] Signed-off-by: Neil Horman <nhorman@tuxdriver.com> CC: Karel Zak <kzak@redhat.com> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/unshare.c')
-rw-r--r--sys-utils/unshare.c75
1 files changed, 58 insertions, 17 deletions
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 9de997bdc..64ea3766f 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -24,10 +24,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <getopt.h>
#include "nls.h"
#include "c.h"
#include "closestream.h"
+#include "strutils.h"
#ifndef CLONE_NEWSNS
# define CLONE_NEWNS 0x00020000
@@ -60,10 +62,10 @@ static void usage(int status)
_(" %s [options] <program> [args...]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out);
- fputs(_(" -m, --mount unshare mounts namespace\n"
- " -u, --uts unshare UTS namespace (hostname etc)\n"
- " -i, --ipc unshare System V IPC namespace\n"
- " -n, --net unshare network namespace\n"), out);
+ fputs(_(" -m, --mount [=<pid>] unshare or migrate mounts namespace\n"
+ " -u, --uts [=<pid>] unshare or migrate UTS namespace (hostname etc)\n"
+ " -i, --ipc [=<pid>] unshare or migrate System V IPC namespace\n"
+ " -n, --net [=<pid>] unshare or migrate network namespace\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
@@ -76,17 +78,18 @@ static void usage(int status)
int main(int argc, char *argv[])
{
static const struct option longopts[] = {
- { "help", no_argument, 0, 'h' },
+ { "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V'},
- { "mount", no_argument, 0, 'm' },
- { "uts", no_argument, 0, 'u' },
- { "ipc", no_argument, 0, 'i' },
- { "net", no_argument, 0, 'n' },
+ { "mount", optional_argument, 0, 'm' },
+ { "uts", optional_argument, 0, 'u' },
+ { "ipc", optional_argument, 0, 'i' },
+ { "net", optional_argument, 0, 'n' },
{ NULL, 0, 0, 0 }
};
+ int namespaces[128]; /* /proc/#/ns/<name> file descriptors */
+ size_t i, nscount = 0; /* number of used namespaces[] */
int unshare_flags = 0;
-
int c;
setlocale(LC_MESSAGES, "");
@@ -94,7 +97,13 @@ int main(int argc, char *argv[])
textdomain(PACKAGE);
atexit(close_stdout);
- while((c = getopt_long(argc, argv, "hVmuin", longopts, NULL)) != -1) {
+ memset(namespaces, 0, sizeof(namespaces));
+
+ while((c = getopt_long(argc, argv,
+ "hVm::u::i::n::", longopts, NULL)) != -1) {
+
+ const char *ns = NULL;
+
switch(c) {
case 'h':
usage(EXIT_SUCCESS);
@@ -102,26 +111,58 @@ int main(int argc, char *argv[])
printf(UTIL_LINUX_VERSION);
return EXIT_SUCCESS;
case 'm':
- unshare_flags |= CLONE_NEWNS;
+ ns = "mnt";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWNS;
break;
case 'u':
- unshare_flags |= CLONE_NEWUTS;
+ ns = "uts";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWUTS;
break;
case 'i':
- unshare_flags |= CLONE_NEWIPC;
+ ns = "ipc";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWIPC;
break;
case 'n':
- unshare_flags |= CLONE_NEWNET;
+ ns = "net";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWNET;
break;
default:
usage(EXIT_FAILURE);
}
+
+ if (ns && optarg) {
+ pid_t pid;
+ char path[512];
+
+ if (nscount >= ARRAY_SIZE(namespaces))
+ err(EXIT_FAILURE, _("too many new namespaces specified"));
+
+ if (*optarg == '=')
+ optarg++;
+
+ pid = strtoul_or_err(optarg, _("failed to parse pid argument"));
+
+ sprintf(path, "/proc/%lu/ns/%s", (unsigned long) pid, ns);
+ namespaces[nscount] = open(path, O_RDONLY | O_CLOEXEC);
+ if (namespaces[nscount] < 0)
+ err(EXIT_FAILURE, _("cannot open %s"), path);
+ nscount++;
+ }
}
- if(optind >= argc)
+ if (optind >= argc)
usage(EXIT_FAILURE);
- if(-1 == unshare(unshare_flags))
+ for (i = 0; i < nscount; i++) {
+ if (setns(namespaces[i], 0) != 0)
+ err(EXIT_FAILURE, _("setns failed"));
+ }
+
+ if (unshare_flags && unshare(unshare_flags) != 0)
err(EXIT_FAILURE, _("unshare failed"));
/* drop potential root euid/egid if we had been setuid'd */