summaryrefslogtreecommitdiffstats
path: root/sys-utils/unshare.c
diff options
context:
space:
mode:
authorMike Frysinger2013-06-28 02:04:58 +0200
committerKarel Zak2013-07-09 11:02:16 +0200
commit5088ec338fe5dcd7e9a2d8daf7e7fa7dd6f87c27 (patch)
tree7dc914c23a62e7ffd07444db02474f1e58c6bb39 /sys-utils/unshare.c
parentinclude/xalloc: add warn_unused_result to allocation functions (diff)
downloadkernel-qcow2-util-linux-5088ec338fe5dcd7e9a2d8daf7e7fa7dd6f87c27.tar.gz
kernel-qcow2-util-linux-5088ec338fe5dcd7e9a2d8daf7e7fa7dd6f87c27.tar.xz
kernel-qcow2-util-linux-5088ec338fe5dcd7e9a2d8daf7e7fa7dd6f87c27.zip
unshare: add --fork options for pid namespaces
The ability of unshare to launch a new pid namespace is a bit limited. The first process in the namespace is expected to be the "init" for it. When it's not, you get bad behavior. For example, trying to launch a shell in a new pid namespace fails very quickly: $ sudo unshare -p dash # uname -r 3.8.3 # uname -m dash: 2: Cannot fork # ls -ld / dash: 3: Cannot fork # echo $$ 1324 For this to work smoothly, we need an init process to actively watch over things. But forcing people to re-use an existing init or write their own mini init is a bit overkill. So let's add a --fork option to unshare to do this common bit of book keeping. Now we can do: $ sudo unshare -p --fork dash # uname -r 3.8.3 # uname -m x86_64 # ls -ld / drwxr-xr-x 22 root root 4096 May 4 14:01 / # echo $$ 1 Thanks to Michael Kerrisk for his namespace articles on lwn.net [kzak@redhat.com: - fix "forkif logic, remove --mount-proc] Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/unshare.c')
-rw-r--r--sys-utils/unshare.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 8cc9c46c8..a889eee9f 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <sys/wait.h>
#include "nls.h"
#include "c.h"
@@ -46,6 +47,7 @@ static void usage(int status)
fputs(_(" -n, --net unshare network namespace\n"), out);
fputs(_(" -p, --pid unshare pid namespace\n"), out);
fputs(_(" -U, --user unshare user namespace\n"), out);
+ fputs(_(" -f, --fork fork before launching <program>\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
@@ -66,20 +68,23 @@ int main(int argc, char *argv[])
{ "net", no_argument, 0, 'n' },
{ "pid", no_argument, 0, 'p' },
{ "user", no_argument, 0, 'U' },
+ { "fork", no_argument, 0, 'f' },
{ NULL, 0, 0, 0 }
};
int unshare_flags = 0;
-
- int c;
+ int c, forkit = 0;
setlocale(LC_MESSAGES, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
- while ((c = getopt_long(argc, argv, "hVmuinpU", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "fhVmuinpU", longopts, NULL)) != -1) {
switch (c) {
+ case 'f':
+ forkit = 1;
+ break;
case 'h':
usage(EXIT_SUCCESS);
case 'V':
@@ -111,6 +116,26 @@ int main(int argc, char *argv[])
if (-1 == unshare(unshare_flags))
err(EXIT_FAILURE, _("unshare failed"));
+ if (forkit) {
+ int status;
+ pid_t pid = fork();
+
+ switch(pid) {
+ case -1:
+ err(EXIT_FAILURE, _("fork failed"));
+ case 0: /* child */
+ break;
+ default: /* parent */
+ if (waitpid(pid, &status, 0) == -1)
+ err(EXIT_FAILURE, _("waitpid failed"));
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ kill(getpid(), WTERMSIG(status));
+ err(EXIT_FAILURE, _("child exit failed"));
+ }
+ }
+
if (optind < argc) {
execvp(argv[optind], argv + optind);
err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);