FCNTL(2)

名称
fcntl - ファイル制御

ライブラリ
libc

書式
<fcntl.h> int fcntl(int fd, int cmd, ...)

解説
fcntl() システムコールは、記述子の制御機能を提供します。 引数 fd は、後述する cmd によって操作される記述子です。 cmd の値によっては、 fcntl() は 3 つめの引数 int arg を取ることができます。

F_DUPFD
    次のような新しい記述子を返します:

    •   arg 以上で最小番号をもつ利用可能な記述子
    •   オリジナルの記述子と同じオブジェクトを参照
    •   オブジェクトがファイルだった場合、 同じファイルオフセットを共有
    •   同じアクセスモード (読取り、書込み、または読取りと書込み)
    •   同じファイル状態フラグ (すなわち、 両方のファイル記述子が同じファイル状態フラグを共有)
    •   close-on-exec フラグは、 execve(2) システムコールの後でも 記述子をオープンしたままでいるように設定

F_GETFD
    ファイル記述子 fd に結び付けられた close-on-exec フラグを、 FD_CLOEXEC として取得します。 返された値と FD_CLOEXEC の論理積が 0 の場合、ファイルは exec() を実行してもオープンされたままになります。 そうでない場合、ファイルは exec() の実行でクローズされます (arg は無視されます)。

F_SETFD
    fd に結び付けられた close-on-exec フラグを arg に設定します。 arg は 0 または前述の FD_CLOEXEC です。

F_GETFL
    後述するように記述子の状態フラグを取得します (arg は無視されます)。

F_SETFL
    記述子状態フラグを arg で指定される値に設定します。

F_GETOWN
    現時点で SIGIO シグナルと SIGURG シグナルを受信しているプロセス ID またはプロセスグループを取得 します。 プロセスグループは負の値として返されます (arg は無視されます)。

F_SETOWN
    プロセスまたはプロセスグループが SIGIO シグナルおよび SIGURG シグナルを受信するように設定します。 プロセスグループは arg を負数にして与えることによって指定されます。 そうでない場合、 arg はプロセス ID として解釈されます。

F_GETFL および F_SETFL 用のフラグは次のとおりです:

O_NONBLOCK
    非ブロッキング入出力。 read(2) システムコールで読み取るべきデータが無い場合、または write(2) 操作がブロックするであろう場合に、読取り呼び出しまたは書込み呼び出しはエラー EAGAIN で -1 を返します。

O_APPEND
    各書込みがファイルの末尾に追加されるようにします。 open(2) の O_APPEND フラグに対応します。

O_DIRECT
    読み書きにおけるキャッシュ効果を最小化または無くします。 システムは、読み書きするデータのキャッシングを避けようとします。 データのキャッシングが避けられない場合、 データのキャッシュに対する影響を最小化します。 注意せずに使用すると、本フラグは劇的に性能を劣化させます。

O_ASYNC
    たとえば、読み取るべきデータが用意できたときなど、 入出力が可能になったときに SIGIO シグナルがプロセスグループに送信されるようにします。

問合せ型ファイルロックを行うためにいくつかのコマンドが利用できます。 これらのコマンドはすべて次の構造体で操作します:

    struct flock {
    	off_t	l_start;	/* 開始位置のオフセット */
    	off_t	l_len;		/* len = 0 はファイル末尾までという意味 */
    	pid_t	l_pid;		/* ロック所有者 */
    	short	l_type;		/* ロックタイプ: 読取り / 書込みなど */
    	short	l_whence;	/* l_start のタイプ */
    };

問合せ型レコードロックに利用できるコマンドは次のとおりです:

F_GETLK
    3 番めの引数 arg を struct flock (前記を参照) へのポインタと解釈して、それによって指定される ロック記述をブロックする最初のロックを取得します。 取り出された情報は、 fcntl() に渡された flock 構造体内の情報に上書きされます。 このロックが作成されるのを妨げるロックが見つからない場合は、 構造体はこのシステムコール呼び出しによっても変更されません。 ただし、ロックタイプが F_UNLCK に設定されている場合は除きます。

F_SETLK
    3 番めの引数 arg を struct flock (前記を参照) へのポインタと解釈して、それによって指定される ロック記述に従ってファイルセグメントロックを設定またはクリアします。 F_SETLK は、共有 (または読取り) ロック (F_RDLCK) または排他的 (または書込み) ロック (F_WRLCK) を確立、ならびにいずれかのタイプのロックを解除 (F_UNLCK) するのに使用されます。 共有ロックまたは排他的ロックが設定できない場合、 fcntl() は EAGAIN でただちに戻ります。

F_SETLKW
    このコマンドは F_SETLK と同じですが、共有ロックまたは排他的ロックが他のロックによって ブロックされる場合に、 要求が満たされるまでプロセスが待機する点が異なります。 fcntl() がある領域を確保するために待機している間に 捕捉されるべきシグナルを受信して、シグナルハンドラが SA_RESTART (sigaction(2) を参照) を 指定していない場合、 fcntl() は中断されます。

共有ロックがファイルのあるセグメントに設定されている場合、 他のプロセスはそのセグメントまたはその 一部に共有ロックを設定できます。 共有ロックは、保護しているどの領域にも、 他のプロセスが排他的ロックを設定するのを防止します。 ファイル記述子が読取りアクセスで開かれていない場合、 共有ロックの要求は処理を失敗します。

排他的ロックは、保護している領域に他のプロセスが 共有ロックまたは排他的ロックを設定するのを防止します。 ファイルが書込みアクセスで開かれていない場合、 排他的ロックの要求は失敗します。

l_whence の値は SEEK_SET, SEEK_CUR または SEEK_END で、これらは相対オフセット l_start バイトが、それぞれファイルの先頭、現在位置、 またはファイルの末尾から測定されることを指示します。 l_len の値はロックされる連続領域のバイト数です。 l_len が負の場合、 l_start は領域の終端を表しています。 l_pid フィールドは、 ブロックするロックを保持しているプロセスのプロセス ID を返すために F_GETLK でのみ使用されます。 F_GETLK 要求が正常に完了すると l_whence の値は SEEK_SET になります。

ロックは現在のファイル末尾以降で開始したり、 ファイル末尾を越えて延長することはできますが、 ファイルの先頭より前で開始したり、 ファイルの先頭を越えて延長することはできません。 l_len が 0 に設定されている場合、ロックはそのファイルの ファイルオフセットの可能な最大の値まで延長されます。 l_whence と l_start がファイルの先頭を指しており、しかも l_len が 0 の場合はファイル全体がロックされます。 アプリケーションがファイル全体をロックしようとしているだけなら、 flock(2) システムコールの方がはるかに効率的です。

ファイル内の各バイトについて最大で 1 つのタイプのロックが設定されます。 呼び出しプロセスが F_SETLK 要求、または F_SETLKW 要求で指定した領域内に既存のロックを保持しているとき、 要求から正常に戻る前に、 指定の領域内の各バイトについて以前の ロックタイプが新しいロックタイプで置き換えられます。 共有ロックと 排他的ロックのところで前述したように、 別のプロセスが指定の領域内にロックを保持しており、しかもそれらのロック のタイプが要求で指定されたタイプと競合するとき、 F_SETLK 要求は失敗し、 F_SETLKW 要求はブロックします。

このインタフェースは、System V と p1003.1-88 が要求する不毛なセマンティクスに完全に従っています。 つまり、あるプロセスが保持している、 あるファイルと結び付けられたすべてのロックは、 そのファイルの記述子の いずれか がそのプロセスによって クローズされたときに解除されます。 これは、サブルーチンライブラリがアクセスする可能性のあるファイル全てを アプリケーションが認識している必要があることを意味します。 たとえば、パスワードファイルを更新するアプリケーションが、 更新を行うためにパスワードファイルデータベースをロックし、 レコードを取り出すために getpwnam(3) を呼び出したとしましょう。 getpwnam(3) はパスワードデータベースをオープンし、読み取り、 そしてクローズするので、ロックは失われます。 データベースをクローズすると、ライブラリルーチン がデータベースへのロックを要求したことがない場合でさえ、 プロセスがデータベースに結び付けたすべての ロックが解放されてしまうのです。 このインタフェースの別のさほど重要でないセマンティクス上の問題は、 ロックが fork(2) システムコールを使用して作成された子プロセスによって継承されないことです。 flock(2) インタフェースは、はるかに合理的な last close セマンティクスを採用し、 ロックが子プロセスによって継承されるようになっています。 ライブラリを使用するときにロックの整合性を確実にする、 またはロックを子プロセスに渡したいアプリケーションについては flock(2) システムコールをお勧めします。

fcntl(), flock(2) および lockf(3) のロックは互換性があります。 異なったロックのインタフェースを使用するプロセスは、 同じファイルを安全に使用することができます。 しかしながら、同じプロセスの内部では これらのインタフェースのうちの 1 つのみが使用されるべきです。 fcntl() を介してあるプロセスによってあるファイルがロックされている場合、 flock(2) または lockf(3) を使用している他のプロセスの視点からは、 そのファイルの中のあらゆるレコードはロックされているかのように見えます。 また、その逆も同様です。 ブロックするロックを保持しているプロセスがファイル記述子を以前に flock(2) でロックしていた場合、 fcntl(F_GETLK) は l_pid に -1 を入れて戻ります。

プロセスの、あるファイルに結び付けられたすべてのロックは そのプロセスが終了するときに解除されます。

execve(2) の呼び出し前に取得されたすべてのロックは、 新規プログラムがそれらを解放するまで有効なままです。 新規プログラムがロックについて知らないならば、 プログラム終了まで解放されません。

あるロックした領域を制御しているプロセスが、 別のプロセスがロックした領域をロックしようとして 休眠状態にされる場合に、デッドロックが発生する可能性があります。 この実装では、ロックされた領域がアンロックされるまでの休眠が デッドロックを引き起こす可能性を検出すると、 EDEADLK エラーで失敗します。

戻り値
処理が正常に完了した場合、返される値は cmd に応じて次のようになります:

F_DUPFD
    新しいファイル記述子

F_GETFD
    フラグの値 (下位ビットだけが定義されます)

F_GETFL
    フラグの値

F_GETOWN
    ファイル記述子所有者の値

その他 -1 以外の値

そうでない場合は -1 が返され、エラーを示すために errno が設定されます。

エラー
fcntl() システムコールは、次の場合に失敗します:

[EAGAIN]
    引数 cmd は F_SETLK であり、ロックのタイプ (l_type) は共有ロック (F_RDLCK) 、または 排他的ロック (F_WRLCK) で、ロックされるはずのファイルの セグメントは既に別のプロセスによって排他的に ロックされています。 または、タイプが排他的なロックで、ロックされるファイルのセグメントの一部が 既に別のプロセスによって共有ロックまたは排他的ロックされています。

[EBADF]
    fd 引数が有効なオープンファイル記述子ではありません。

    引数 cmd が F_SETLK または F_SETLKW で、かつロックタイプ (l_type) が共有ロック (F_RDLCK) のとき、 fd は読取り用に開かれた有効なファイル記述子ではありません。

    引数 cmd が F_SETLK または F_SETLKW で、かつロックタイプ (l_type) が排他的ロック (F_WRLCK) のとき、 fd は書込み用に開かれた有効なファイル記述子ではありません。

[EDEADLK]
    引数 cmd が F_SETLKW であり、デッドロック条件が検出されました。

[EINTR]
    引数 cmd が F_SETLKW であり、このシステムコールがシグナルによって割り込まれました。

[EINVAL]
    cmd が F_DUPFD で、 arg が負であるかまたは許容される最大値より大きくなっています (getdtablesize(2) を参照)。

    引数 cmd が F_GETLK, F_SETLK または F_SETLKW で、 arg が指すデータが有効でありません。

[EMFILE]
    引数 cmd が F_DUPFD であり、プロセスについて許容される最大数までファイル記述子が 既に使用されています。 arg で指定された以上のファイル記述子は利用できません。

[ENOLCK]
    引数 cmd が F_SETLK または F_SETLKW であり、ロック要求またはアンロック要求を満たすことによって、 システムが課した限界を越える数のロックされた領域がシステム内に できてしまいます。

[EOPNOTSUPP]
    引数 cmd に F_GETLK, F_SETLK または F_SETLKW が指定されましたが、 fd はロックをサポートしていないファイルを参照しています。

[EOVERFLOW]
    引数 cmd に F_GETLK, F_SETLK または F_SETLKW が指定されましたが、 off_t の計算がオーバフローしました。

[EPERM]
    cmd 引数は、 F_SETOWN であり、引数として指定されたプロセス ID またはプロセスグループ は、呼び出し側と異なるセッション内にあります。

[ESRCH]
    cmd 引数は F_SETOWN であり、引数として指定されたプロセス ID が使用されていません。

さらに、 fd が (ソケット上で開いている記述子とは反対に) 端末デバイス上で開いている記述子を参照する場合、 cmd で F_SETOWN を指定すると tcsetpgrp(3) と同じ理由で処理を失敗する可能性があり、 tcgetpgrp(3) で述べたような 理由で cmd で F_GETOWN を指定した場合に処理に失敗する可能性があります。

関連項目
close(2), execve(2), flock(2), getdtablesize(2), open(2), sigvec(2), lockf(3), tcgetpgrp(3), tcsetpgrp(3)

歴史
fcntl() システムコールは 4.2BSD で登場しました。