UNSHARE(2)

名前
unshare - プロセス実行コンテキストの一部を分離する

書式
#include <sched.h>

int unshare(int flags);

glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):

unshare():
    glibc 2.14 以降:
        _GNU_SOURCE
    glibc 2.14 より前:
        _BSD_SOURCE || _SVID_SOURCE
            /* _GNU_SOURCE も定義される */

説明
unshare() を使うと、プロセスは他のプロセスと現在共有している 実行コンテキストの一部を分離することができる。 実行コンテキストの一部、たとえばマウント名前空間 (mount namespace) などは、新しいプロセスを fork(2) または vfork(2) を使って生成したときに、暗黙のうちに共有される。 一方、仮想メモリーなどは、 clone(2) を使ってプロセスを生成するときに、明示的に共有することを要求できる。 unshare() の主な利用法は、プロセスが新しいプロセスを生成することなく、 共有実行コンテキストを制御することである。 flags 引き数はビットマスクであり、 実行コンテキストのどの部分の共有を解除するかを表す。 この引き数は、以下の定数の 0 個以上の OR で指定する:

CLONE_FILES
    clone(2) CLONE_FILES フラグの効果を取り消す。 ファイルディスクリプターテーブルを共有させず、 呼び出し元プロセスは他のプロセスとファイルディスクリプターを共有しなくなる。

CLONE_FS
    clone(2) CLONE_FS フラグの効果を取り消す。ファイルシステム属性を共有させず、呼び出し元プロセスは、ルートディレクトリ (chroot(2))、カレントディレクトリ (chdir(2))、 umask (umask(2)) を他のプロセスと共有しなくなる。

CLONE_NEWIPC (Linux 2.6.19 以降)
    このフラグは clone(2) CLONE_NEWIPC フラグと同じ効果を持つ。 System V IPC 名前空間を共有せず、呼び出し元プロセスは 他のプロセスとは 共有しない固有の System V IPC 名前空間のコピーを持つ。 このフラグを指定 すると、 CLONE_SYSVSEM も暗黙のうちに指定される。 CLONE_NEWIPC を 使用するには CAP_SYS_ADMIN ケーパビリティが必要である。

CLONE_NEWNET (Linux 2.6.24 以降)
    このフラグは clone(2) CLONE_NEWNET フラグと同じ効果を持つ。ネット ワーク名前空間を共有せず、呼び出し元プロセスは他のプロセスとは共有しな い固有のネットワーク名前空間のコピーを持つ。CLONE_NEWNET を使用する には CAP_SYS_ADMIN ケーパビリティが必要である。

CLONE_NEWNS
    このフラグは clone(2) CLONE_NEWNS フラグと同じ効果を持つ。 マウン ト名前空間を共有せず、呼び出し元プロセスは 他のプロセスとは共有しない固 有の名前空間のコピーを持つ。 このフラグを指定すると、 CLONE_FS も暗 黙のうちに指定される。 CLONE_NEWNS を使用するには CAP_SYS_ADMIN ケーパビリティが必要である。

CLONE_NEWPID (Linux 3.8 以降)
    このフラグは clone(2) CLONE_NEWPID フラグと同じ効果を持つ。 PID 名前空間を共有しない。 呼び出し元プロセスは、 すでに存在するどのプロセスとも共有されない新しい PID 名前空間を、 自身の子プロセス用に持つことになる。 このプロセスにより作成される最初の子プロセスはプロセス ID 1 を持ち、 この新しい名前空間において init(1) の役割を持つとみなされる。 CLONE_NEWPID を指定すると、自動的に CLONE_THREAD も指定されたものとみなされる。 CLONE_NEWPID を使用するには CAP_SYS_ADMIN ケーパビリティが必要である。 詳細な情報は pid_namespaces(7) を参照。

CLONE_NEWUSER (Linux 3.8 以降)
    このフラグは clone(2) CLONE_NEWUSER フラグと同じ効果を持つ。 ユーザー名前空間を共有せず、 呼び出し元プロセスはすでに存在するどのプロセスとも共有されない新しいユーザー名前空間に移動される。 CLONE_NEWUSER フラグを指定して clone(2) で作成された子プロセスと同様に、 呼び出し元は新しい名前空間ですべてのケーパビリティを獲得する。

    CLONE_NEWUSER を使うには、呼び出し元プロセスがスレッド化されていないことが必要である。 CLONE_NEWUSER を指定すると、自動的に CLONE_THREAD が指定されたものとみなされる。 Linux 3.9 以降では、 CLONE_NEWUSER が指定された場合 CLONE_FS も指定されたとみなされる。 CLONE_NEWUSER を使うには、呼び出し元プロセスのユーザー ID とグループ ID が、 呼び出した時点で、 呼び出し元プロセスのユーザー名前空間のユーザー ID とグループ ID にマッピングされている必要がある。 ユーザー名前空間の詳細は user_namespaces(7) を参照。

CLONE_NEWUTS (Linux 2.6.19 以降)
    このフラグは clone(2) CLONE_NEWUTS フラグと同じ効果を持つ。 UTS IPC 名前空間を共有せず、呼び出し元プロセスは他のプロセスとは共有しない 固有の UTS IPC 名前空間のコピーを持つ。 このフラグを指定すると、 CLONE_FS も暗黙のうちに指定される。CLONE_NEWUTS を使用するには CAP_SYS_ADMIN ケーパビリティが必要である。

CLONE_SYSVSEM (Linux 2.6.26 以降)
    このフラグは clone(2) CLONE_SYSVSEM フラグの効果を逆転させる。 System V セマフォの調整値 (semadj) を共有せず、 呼び出し元プロセスは他のプロセスとは共有されない新しい空の semadj リストを持つ。 そのプロセスが、自分の現在の semadj リストへの参照を持つ最後のプロセスであれば、 このリストの調整値は対応するセマフォに適用される (semop(2) に説明がある通り)。

上記に加えて、 呼び出し元がシングルスレッドの場合 (すなわち別のプロセスやスレッドとアドレス空間を共有していない場合)、 CLONE_THREAD, CLONE_SIGHAND, CLONE_VM を指定することができる。 この場合、 これらのフラグは効果を持たない。 (CLONE_THREAD を指定すると自動的に CLONE_VM が指定されたとみなされ、 CLONE_VM を指定すると自動的に CLONE_SIGHAND が指定されたとみなされる点に注意してほしい。) プロセスがマルチスレッドの場合、 これらのフラグを使用するとエラーとなる。

flags に 0 が指定された場合、 unshare() は何も行わないので、 呼び出し元プロセスの実行コンテキストは、何も変更されない。

返り値
成功した場合は 0 が返される。 失敗した場合は -1 が返されて、 errno にはエラーを示す値が設定される。

エラー

EINVAL
    flags に不正なビットが指定された。

EINVAL
    CLONE_THREAD, CLONE_SIGHAND, CLONE_VM が flags に指定されたが、 呼び出したプロセスはマルチスレッドである。

ENOMEM
    呼び出し元のコンテキストのうち共有を解除する必要がある部分をコピーするために、 十分なメモリーが確保できなかった。

EPERM
    呼び出し元プロセスはこの操作を行うのに必要な特権を持っていなかった。

EPERM
    CLONE_NEWUSER が flags に指定されたが、 呼び出し元の実効ユーザー ID もしくは実効グループ ID が親名前空間にマッピングがない (user_namespaces(7) 参照)。

EPERM (Linux 3.9 以降)
    CLONE_NEWUSER が flags に指定され、 呼び出し元が chroot された環境にいる (すなわち、呼び出し元の root ディレクトリが呼び出し元が属するマウント名前空間の root ディレクトリに一致しない)。

EUSERS (Linux 3.11 以降)
    CLONE_NEWUSER が flags に指定されており、 この呼び出しによりネストされたユーザー名前空間数の上限を超えてしまう。 user_namespaces(7) を参照。

バージョン
unshare() システムコールは Linux カーネル 2.6.16 で追加された。

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

注意
clone(2) で新しいプロセスを生成したときに共有される全てのプロセス属性を、 unshare() によって共有の解除ができるわけではない。 特に、カーネル 3.8 時点では、 unshare() に CLONE_SIGHAND, CLONE_THREAD, CLONE_VM の効果を取り消すためのフラグが実装されていない。 これらの機能は、必要であれば将来追加されるかもしれない。

例
以下のプログラムは unshare(1) コマンドの簡単な実装である。 このコマンドは、1 つ以上の名前空間の unshare を行ってから、 コマンドライン引き数で指定されたコマンドを実行する。 以下はこのプログラムの使用例である。 新しいマウント名前空間でシェルを実行し、 元のシェルと新しいシェルが別のマウント名前空間にいることを確認している。
$ readlink /proc/$$/ns/mnt
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash
[sudo] password for cecilia:
# readlink /proc/$$/ns/mnt
mnt:[4026532325]
2 つの readlink(1) コマンドの出力が違うことから、 2 つのシェルは異なるマウント名前空間にいることが分かる。

  プログラムのソース
/* unshare.c
   A simple implementation of the unshare(1) command: unshare
   namespaces and execute a command.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
/* A simple error-handling function: print an error message based
   on the value in 'errno' and terminate the calling process */
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)
static void
usage(char *pname)
{
    fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname);
    fprintf(stderr, "Options can be:\n");
    fprintf(stderr, "    -i   unshare IPC namespace\n");
    fprintf(stderr, "    -m   unshare mount namespace\n");
    fprintf(stderr, "    -n   unshare network namespace\n");
    fprintf(stderr, "    -p   unshare PID namespace\n");
    fprintf(stderr, "    -u   unshare UTS namespace\n");
    fprintf(stderr, "    -U   unshare user namespace\n");
    exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
    int flags, opt;
    flags = 0;
    while ((opt = getopt(argc, argv, "imnpuU")) != -1) {
        switch (opt) {
        case 'i': flags |= CLONE_NEWIPC;        break;
        case 'm': flags |= CLONE_NEWNS;         break;
        case 'n': flags |= CLONE_NEWNET;        break;
        case 'p': flags |= CLONE_NEWPID;        break;
        case 'u': flags |= CLONE_NEWUTS;        break;
        case 'U': flags |= CLONE_NEWUSER;       break;
        default:  usage(argv[0]);
        }
    }
    if (optind >= argc)
        usage(argv[0]);
    if (unshare(flags) == -1)
        errExit("unshare");
    execvp(argv[optind], &argv[optind]);
    errExit("execvp");
}

関連項目
unshare(1), clone(2), fork(2), kcmp(2), setns(2), vfork(2), namespaces(7) Linux カーネルソース内の Documentation/unshare.txt

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