setns(2) スレッドに名前空間を関連付けしなおす

書式

#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <sched.h>


int setns(int fd, int nstype);

説明

名前空間を参照するファイルディスクリプタを指定すると、 呼び出したスレッドにその名前空間を関連付けしなおす。

fd 引き数は、 /proc/[pid]/ns/ ディレクトリ内の名前空間エントリ のいずれかを参照するファイルディスクリプタである。 /proc/[pid]/ns/ の詳細は proc(5) を参照。 nstype 引き数で指定された制限の範囲内で、 呼び出したスレッドに fd に対応する名前空間を関連付けしなおす。

nstype 引き数は、呼び出したスレッドがどのタイプの名前空間を 関連付けしなおすことができるかを指定する。 この引き数には以下のいずれかの値を指定できる。

0
どのタイプの名前空間も関連付けることができる。
CLONE_NEWIPC
fd は IPC 名前空間を参照していなければならない。
CLONE_NEWNET
fd はネットワーク名前空間を参照していなければならない。
CLONE_NEWUTS
fd は UTS 名前空間を参照していなければならない。

呼び出し側が fd がどのタイプの名前空間を参照しているかを知っている (もしくは気にする必要がない) 場合には、 nstype に 0 を指定すれば十分 である。呼び出し側が fd がどのタイプの名前空間を参照しているかを 知っておらず、かつ、特定のタイプの名前空間であることを保証したい場合、 nstype に 0 以外の値を指定するとよい。 (ファイルディスクリプタが別の プロセスによりオープンされ、例えば、UNIX ドメインソケット経由で呼び出し 側に渡された場合などでは、呼び出し側が fd がどのタイプの名前空間を 参照しているかを知らない可能性がある。)

返り値

成功すると setns() は 0 を返す。 失敗すると、 -1 が返され、 errno にエラーを示す値が設定される。

エラー

EBADF
fd が有効なファイルディスクリプタではない。
EINVAL
fdnstype で指定されたタイプと一致しない名前空間を参照している。 または、指定された名前空間をそのスレッドに関連付けし直す際に問題 があった。
ENOMEM
指定された名前空間に変更するのに必要なメモリが割り当てられない。
EPERM
呼び出したスレッドがこの操作を行うのに必要な特権 (CAP_SYS_ADMIN) を 持っていなかった。

バージョン

setns() システムコールはカーネル 3.0 で Linux に初めて登場した。 ライブラリによるサポートは glibc バージョン 2.14 を追加された。

準拠

setns() システムコールは Linux 固有である。

注意

新しいスレッドが clone(2) を使って作成された際に共有できる全ての属性を、 setns() を使って変更できるわけではない。

以下のプログラムは 2 つ以上の引き数を取る。 最初の引き数には、 既存の /proc/[pid]/ns/ ディレクトリの名前空間ファイルのパス名を指定する。 残りの引き数は、コマンドとその引き数を指定する。 このプログラムは名前空間ファイルをオープンし、 setns() を使って名前空間に参加し、 指定されたコマンドをその名前空間内で実行する。

以下のシェルセッションでは、 このプログラム (ns_exec という名前のバイナリとしてコンパイルされている)を、 clone(2) のマニュアルページの CLONE_NEWUTS のサンプルプログラムと組み合わせて使っている。

まず、 clone(2) のサンプルプログラムをバックグラウンドで実行する。 このプログラムは、 別の UTS 名前空間で子プロセスを作成する。 子プロセスは自分の名前空間内でホスト名を変更する。 それから、 親プロセスと子プロセスの両方でそれぞれの UTS 名前空間のホスト名を表示し、 2 つのホスト名が違うことが確認できる。

$ su                   # 名前空間の操作には特権が必要
Password:
# ./newuts bizarro &
[1] 3549
clone() returned 3550
uts.nodename in child:  bizarro
uts.nodename in parent: antero
# uname -n             # シェルでホスト名を確認
antero

次に、以下のプログラムを使ってシェルを実行する。 このシェルの中では、ホスト名が最初のプログラムで作成された子プロセスが設定したホスト名になっていることを確認できる。

# ./ns_exec /proc/3550/ns/uts /bin/bash
# uname -n             #  ns_exec で起動されたシェル内で実行
bizarro

プログラムのソース

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)
int
main(int argc, char *argv[])
{
    int fd;
    if (argc < 3) {
        fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    fd = open(argv[1], O_RDONLY);   /* 名前空間のディスクリプタを取得 */
    if (fd == -1)
        errExit("open");
    if (setns(fd, 0) == -1)         /* 名前空間に参加 */
        errExit("setns");
    execvp(argv[2], &argv[2]);      /* 名前空間内でコマンドを実行 */
    errExit("execvp");
}

この文書について

この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。