nsenter
のサブプロセスとして実行されるbash
は、setns
システムコールを使用して既存の名前空間に参加し、exec
を使用して指定されたプログラムを実行すると想定しています。
しかし、nsenter
がsetns
の前に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.
説明は man nsenter
の「PID名前空間」セクションに記載されています。
子には、
nsenter
プロセスとは別にマッピングを処理するための一連のPIDがあります。nsenter
は、PID名前空間を変更する場合、デフォルトでforkするため、新しいプログラムとその子は同じPID名前空間を共有し、お互いに表示されます。--no-fork
を使用すると、新しいプログラムはフォークせずに実行されます。
(マニュアルは少し混乱しています。上記の引用セクションをクリーンアップしました util-linux
の次のリリースには修正が含まれます 。)
PID名前空間を入力しても、現在のプロセスはその名前空間に移動されません。その名前空間に新しい子が作成されるだけです。その結果、現在のプロセス(setns
を呼び出すプロセス)は、新しい名前空間の子には見えません。これを回避するには、nsenter
が新しいネームスペースに入り、次にフォークして、新しいネームスペースに新しいnsenter
が生成され、exec
が呼び出されます。その結果、実行されたプログラムは新しい名前空間にあります。
man setns
のPID名前空間の説明も参照してください。
fdがPID名前空間を参照する場合、セマンティクスは他の名前空間タイプとは多少異なります。呼び出しスレッドをPID名前空間に再度関連付けると、変更されるPID名前空間のみが変更されますその後作成された呼び出し元の子プロセスが配置されます。呼び出し元自体のPID名前空間は変更されません。
これは/proc
名前空間エントリで実際に動作します。/proc/.../ns
にはpid
(プロセスの名前空間)とpid_for_children
(新しい子供たち)。
(exec
自体は新しいプロセスを作成しません。)