我假设nsenter
作为 的子进程运行的bash
,利用setns
系统调用来加入现有的命名空间,然后使用 执行指定的程序exec
。
但是,如果nsenter
已经在 'ingsetns
之前调用exec
,为什么fork
需要系统调用来确保子进程也位于输入的命名空间中?
setns(2)
The setns(2) system call allows the calling process to join an
existing namespace. The namespace to join is specified via a
file descriptor that refers to one of the /proc/[pid]/ns files
described below.
...
-F, --no-fork
Do not fork before exec'ing the specified program. By
default, when entering a PID namespace, nsenter calls fork
before calling exec so that any children will also be in the
newly entered PID namespace.
答案1
解释在“PID命名空间”部分给出man nsenter
:
子进程将有一组 PID 来与
nsenter
进程分开进行进程映射。nsenter
如果更改 PID 命名空间,则默认会分叉,以便新程序及其子程序共享相同的 PID 命名空间并且彼此可见。如果--no-fork
使用,新程序将在不分叉的情况下执行。
(手册有些混乱;我已经清理了上面引用的部分,并且的下一个版本util-linux
将包含修复程序.)
输入 PID 命名空间不会将当前进程移动到该命名空间,它只会导致在该命名空间中创建新的子进程。因此,当前进程(调用的进程setns
)对于新命名空间中的子进程不可见。为了避免这种情况,nsenter
输入新的命名空间,然后分叉,这会nsenter
在新的命名空间中产生一个新的,然后调用exec
;结果,执行的程序位于新的命名空间中。
另请参阅 PID 命名空间的描述man setns
:
如果FD指的是 PID 命名空间,其语义与其他命名空间类型有些不同:将调用线程与 PID 命名空间重新关联仅更改随后创建的调用者子进程将放置的 PID 命名空间;它不会更改调用者本身的 PID 命名空间。
您将在命名空间条目中看到这一点/proc
:/proc/.../ns
有两个 PID 条目,pid
(进程的命名空间)和pid_for_children
(用于新子进程的命名空间)。
(exec
它本身不会创建新的进程。)