diff options
author | Mike Frysinger | 2013-06-28 02:04:58 +0200 |
---|---|---|
committer | Karel Zak | 2013-07-09 11:02:16 +0200 |
commit | 5088ec338fe5dcd7e9a2d8daf7e7fa7dd6f87c27 (patch) | |
tree | 7dc914c23a62e7ffd07444db02474f1e58c6bb39 /sys-utils/unshare.c | |
parent | include/xalloc: add warn_unused_result to allocation functions (diff) | |
download | kernel-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.c | 31 |
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]); |