EXECVEAT(2)

名前
execveat - ディレクトリファイルディスクリプターからの相対パスで指定されるプログラムを実行する

書式
#include <unistd.h>

int execveat(int dirfd, const char *pathname,
char *const argv[], char *const envp[],
int flags);

説明
execveat() システムコールは dirfd と pathname の組み合わせで参照されるプログラムを実行する。 execve(2) と全く同様に動作するが、 以下で説明する点が異なる。

pathname で指定されたパス名が相対パスの場合、このパス名はファイルディスクリプター dirfd が参照するディレクトリに対する相対パスと解釈される (execve(2) に相対パス名を渡した場合のように、呼び出したプロセスのカレントワーキングディレクトリに対する相対パスではない)。

pathname で指定されたパス名が相対パスで、 dirfd が特別な値 AT_FDCWD の場合、 (execve(2) と同様に) pathname は呼び出したプロセスのカレントワーキングディレクトリに対する相対パスと解釈される。

pathname で指定されたパス名が絶対パスの場合、 dirfd は無視される。

pathname が空文字列で、 AT_EMPTY_PATH フラグが指定されている場合、 ファイルディスクリプター dirfd は実行するファイルを指定する (すなわち dirfd はディレクトリではなく実行ファイルを参照する)。

flags 引数は、以下に示す値の 0 個以上を指定できるビットマスクである。

AT_EMPTY_PATH
    pathname が空文字列の場合、 dirfd が参照するファイルに対して動作を行う (dirfd は open(2() O_PATH フラグを使って取得できる)。

AT_SYMLINK_NOFOLLOW
    dirfd と NULL でない pathname で指定されたファイルがシンボリックリンクの場合、 呼び出しはエラー ELOOP で失敗する。

返り値
成功すると execveat() は返らない。エラーの場合は -1 を返し、 errno を適切に設定する。

エラー
execve() で発生するのと同じエラーが execveat() でも起こる。 execveat() では以下のエラーも発生する。

EBADF
    dirfd が適切なファイルディスクリプターでない。

EINVAL
    flags に無効なフラグが指定された。

ELOOP
    flags に AT_SYMLINK_NOFOLLOW が指定されていて、 dirfd と NULL でない pathname で指定されたファイルがシンボリックリンクである。

ENOENT
    dirfd と pathname で指定されるプログラムはインタープリタープログラムを使用する必要があるが (例えば "#!" で始まるスクリプト)、 ファイルディスクリプター dirfd が O_CLOEXEC フラグ付きでオープンされており、 その結果プログラムファイルは起動されたインタープリターにアクセスできないことになる。 「バグ」を参照。

ENOTDIR
    pathname が相対パスで、 dirfd がディレクトリ以外のファイルを参照しているファイルディスクリプターである。

バージョン
execveat() はバージョン 3.19 で Linux に追加された。 GNU C ライブラリによるサポートは検討中である。

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

注意
openat(2) で説明されている理由に加え、 execveat() システムコールは、 fexecve(3) を /proc ファイルシステムがマウントされていないシステムで実装するためにも必要である。

スクリプトファイルを実行するように要求された際、 スクリプトインタープリターに渡される argv[0] は、 /dev/fd/N 形式または /dev/fd/N/P 形式の文字列である。 ここで N は dirfd 引数で渡されたファイルディスクリプター数である。 最初の形式の文字列となるのは、 AT_EMPTY_PATH が使用された場合である。 2 番目の形式の文字列になるのは、 スクリプトが dirfd と pathname の両方を使って指定された場合である。 このとき P は pathname に指定された値である。

fexecve(3) で説明されているのと同じ理由で、 execveat() を使う際の理にかなった方法は dirfd に close-on-exec フラグをセットすることである (ただし「バグ」を参照のこと)。

バグ
上記で説明したエラー ENOENT は、 以下の形式の呼び出しに渡すファイルディスクリプターで close-on-exec フラグをセットできないことを意味している。

    execveat(fd, "", argv, envp, AT_EMPTY_PATH);

しかしながら、 close-on-exec フラグをセットできないということは、 スクリプトを参照するファイルディスクリプターはスクリプト自身に見えてしまうということである。 ファイルディスクリプターを無駄に使うだけでなく、 ファイルディスクリプターが見えてしまうことにより、 スクリプトが execveat() を再帰的に利用する状況ではファイルディスクリプターの枯渇につながる可能性がある。

関連項目
execve(2), openat(2), fexecve(3)

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