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>
This commit is contained in:
parent
c9678832b1
commit
5088ec338f
|
@ -56,13 +56,17 @@ Unshare the mount namespace.
|
|||
Unshare the network namespace.
|
||||
.TP
|
||||
.BR \-p , " \-\-pid"
|
||||
Unshare the pid namespace.
|
||||
Unshare the pid namespace. See also \fB--fork\fP option.
|
||||
.TP
|
||||
.BR \-u , " \-\-uts"
|
||||
Unshare the UTS namespace.
|
||||
.TP
|
||||
.BR \-U , " \-\-user"
|
||||
Unshare the user namespace.
|
||||
.TP
|
||||
.BR \-f , " \-\-fork"
|
||||
Fork the specified process as a child of unshare rather than running it
|
||||
directly. This is useful when creating a new pid namespace.
|
||||
.SH SEE ALSO
|
||||
.BR unshare (2),
|
||||
.BR clone (2)
|
||||
|
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in New Issue