FCNTL(2) — UNIX Programmer’s Manual
名称
fcntl − ファイルの制御
形式
#include <fcntl.h>
res = fcntl(fd, cmd, arg)
int res;
int fd, cmd, arg;
解説
fcntl は、 オープンされているディスクリプタに対して種々な機能を 行います。 引数 fd はオープンされているディスクリプタで、 以下の cmd を 用いて操作されます。
F_DUPFD 次のような性質を 持つ新しいディスクリプタを 返します。
arg と等しいか、 またはそれより大きい割り当て可能な最小番号のディスクリプタ。
元のディスクリプタと同じオブジェクトを 指すもの。
オブジェクトがファイルである場合には、 同じファイルポインタを 共有する新しいディスクリプタ。
同じアクセスモード(読み取り、 書き込み、 または読み取り/書き込み)。
同じファイルステータスフラグ(すなわち、 両方のディスクリプタが同じファイルステータスフラグを 共有します)。
新しいディスクリプタに関する exec 時クローズフラグは、 execve(2) システムコールの実行後にもオープンされたままになるようにセットされます。
F_GETFD ディスクリプタ fd に関する exec 時クローズフラグを 取り出します。 下位のビットが 0 である場合には、 そのファイルは exec の実行後もオープンされたままになり、 そうでない場合には、 そのファイルは exec が実行されるとクローズされます。
F_SETFD fd に関する、 exec 時クローズフラグを、 arg の下位のビットの値(前述のように、 0 または 1)にセットします。
F_GETFL ディスクリプタのステータスフラグを 取り出します。
F_SETFL ディスクリプタのステータスフラグを セットします。
F_GETLK arg によって指し示される flock 構造体の中で指定されている ロックをブロックする、最初のロックに関する記述を 取り出します。 取り出された情報は、 flock 構造体の中にある情報にオーバーライトされます。 このロックが作成されるのを 妨げるロックが見つからない場合には、 構造体のロックタイプが、 F_UNLCKにセットされる以外は変更されずに戻されます。
F_SETLK arg によって指し示される flock 構造体に従って、 アドバイザリレコードロックを セットまたはクリアします。 F_SETLK は、 共有ロックと排他的ロックを 確立する(F_RDLCKとF_WRLCK)ため、 または、 いずれかのタイプのロックを 取り除く(F_UNLCK)ために使用されます。 指定されたロックが適用できない場合には、 fcntl はエラー値−1でリターンします。
F_SETLKW この cmd は、 共有または排他的ロックが他のロックによってブロックされている場合に ロックが適用できるようになるまで待つことを 除けば、 F_SETLK と同じです。
F_GETOWN 現在 SIGIO および SIGURG シグナルを 受け取っているプロセスIDまたはプロセスグループを 取り出します。 プロセスグループは負の値として返されます。
F_SETOWN プロセスまたはプロセスグループを、 SIGIO および SIGURG シグナルを 受け取るようにセットします。 プロセスグループは、 arg を 負の値として与えることによって指定されます。 そうでない場合には、 arg はプロセスIDとして解釈されます。 SIGIO 機能は、 F_SETFL を 用いて FASYNC フラグを セットすることによってオンにされます。
注意事項
アドバイザリロックを 使用することによって、 協調して稼働する複数のプロセスが、 いくつかのファイルに対して矛盾のないオペレーションを 実行することができます。 しかし、 アドバイザリロックは一貫性は保証してはいません。 (つまり、 それらのプロセスはアドバイザリロックを 使用していないファイルにもアクセスすることができ、 その結果矛盾が生じる可能性があるということです。) レコードロックメカニズムでは 2つのタイプのロックが可能です。 それらは、 共有ロック(F_RDLCK)と排他的ロック(F_WRLCK)です。 複数のプロセスは、 いつでも、 1個のファイルの特定のセグメントに対して1つの共有ロックを 保持することができますが、 複数の排他的ロック、 または共有ロックと排他的ロックの両方が、 あるセグメントに同時に存在することはできません。 共有ロックを 獲得するためには、 ディスクリプタが読み取り可能でオープンされていなければなりません。 排他的ロックの置かれるディスクリプタは、 書き込み可能でオープンされていなければなりません。
cmd に F_SETLK または F_SETLKW を 用いて適切なロックタイプを 指定するだけで、 共有ロックを 排他的ロックへグレードアップすることができ、 その逆も可能です。 以前のロックが解除されて新しいロックが適用されます(普通、 これは他のプロセスがそのロックを 獲得して解放した後に行われます)。 cmd が F_SETLKW であり、 かつ、 要求されたロックがすぐにはセットできない場合(例えば、 別のプロセスが現在の要求に部分的にまたは完全にオーバーラップしている 排他的ロックを 保持しているような場合)には、 呼び出し元プロセスは、 そのロックを 得ることができるようになるまでブロックします。 ロックを 待ってブロックされているプロセスは、 シグナルによって 再開します。 複数のプロセスが1組の共通のレコードに対してロックのブロッキングを 行うアプリケーションでは、 デッドロックが発生しないように注意してください。 ロックまたはロック解除されるレコードは、 flock 構造体によって記述され、 それは <fcntl.h> 内で次のように定義されています。
struct flock {
shortl_type;/∗ F_RDLCK または F_WRLCK、F_UNLCK ∗/
shortl_whence;/∗ オフセットのスタート位置のフラグ∗/
longl_start;/∗ バイト単位のオフセット∗/
longl_len;/∗ バイト単位の長さ 0 は EOF を示す∗/
shortl_pid;/∗ F_GETLKで返される値 ∗/
};
flock 構造体は、 影響が及ぼされるファイルのセグメントのタイプ(l_type)、 開始オフセット(l_whence)、 相対オフセット(l_start)、 およびサイズ(l_len)を 記述します。 l_whence は、 相対オフセットがファイルの先頭、 現ポジション、 または end-of-file のいずれからのものであるかを 示すために、 それぞれ 0、 1、 または 2 にセットしなければなりません。 プロセスIDフィールド(l_pid)は、 別のプロセスによって保持されているロックの記述を 返すために、 F_GETLK cmd と共にだけ使用されます。 ロックは、 現在の end-of-file より先から始まったり、 そこまで範囲が及んでも構いませんが、 ファイルの先頭に対して相対的に負であってはなりません。 ロックは、 l_len を ゼロ(0)にセットすることによって常にファイルの終りまでを 範囲にするようにセットすることができます。 そのようなロックが l_whence と l_start も ゼロ(0)にセットされた場合には、 ファイル全体がロックされます。 ファイルの途中から、以前よりも大きなセグメントを変更したり、 そこをロック解除したりすると、 両端に 2つの小さなセグメントが残されます。 呼び出し元プロセスによって既にロックされているセグメントを ロックすると、 古いロックタイプが取り除かれ、 新しいタイプのロックがセットされます。 あるプロセスのためのファイルに関するすべてのロックは、 そのファイルがクローズされたとき、 またはそのプロセスが終了したときに、 解除されます。 ロックは、 fork(2) システムコールでは、 子プロセスに受け継がれません。 ネットワークの場合に一貫性を 維持するためには、 データがクラアントマシンでキャッシュ されてはいけません。 この理由から、 NFS のファイルバッファリングは、 そのファイルに対して最初のロックが試みられたときにオフになります。 バッファリングは、 そのファイルがオープンされている間はオフのままになっています。 しかし、 ユーザアドレススペース内で入出力バッファリングを 行うプログラムは、 矛盾した結果を 得ることもあります(例えば、 標準入出力パッケージは、 思いがけないバッファリングの一般的な原因となります)。 fcntl のアドバイザリレコードロック機能は、 ネットワークロックデーモン(lockd(8C)参照)によってネットワーク内全域で実現されます。 ファイルサーバがクラッシュし、 リブートされると、 ロックデーモンはそのサーバに関するすべてのロックを 回復しようとします。 あるロックが回復できない場合には、 そのロックを 保持していたプロセスに SIGLOST シグナルが発せられます。
リターン値
正常終了時に返される値は、 次のように cmd によって違います。
F_DUPFD新しいディスクリプタ。
F_GETFDフラグの値(下位ビットだけが定義される)。
F_GETFLフラグの値。
F_GETOWN ディスクリプタの所有者の値。
other−1 以外の値。
fcntl が失敗した場合には、 値 −1 が返され、 エラーを 示すように errno がセットされます。
エラー
以下に示されている項目のうち、1つ以上が真である場合には、 fcntl は失敗します。
EBADF fd がオープンされている有効なディスクリプタではない。
EMFILE cmd は F_DUPFD であり、 最大許容数のディスクリプタが現在オープンされている。
EINVAL cmd は F_DUPFD であり、 arg が負であるか、 または最大許容値 (getdtablesize(2) 参照)より大きい。
EFAULT cmd は F_GETLK、 F_SETLK、 または F_SETLKW であり、 arg が無効なアドレスを 指している。
EINVAL cmd は F_GETLK、 F_SETLK、 または F_SETLKW であり、 arg が指しているデータは無効である。
EBADF cmd は F_SETLK または F_SETLKW であり、 プロセスがファイルに対して適切な読み取りまたは書き込みパーミッションを 持っていない。
EAGAIN cmd はF_SETLK、 ロックタイプ(l_type) は F_RDLCK(共有ロック) であり、 ロックするファイルのセグメントに、 別のプロセスによって保持されている排他的ロックが既に存在している。 このエラーは、 ロックタイプが F_WRLCK(排他的ロック) である場合にも返され、 別のプロセスが既に共有または排他的ロックを 用いてセグメントを ロックしている。
EINTR cmd は F_SETLKW であり、 プロセスがロックの許されるのを 待っている間に、 そのプロセスにシグナルが割り込んだ。
ENOLCK cmd は F_SETLK または F_SETLKW であり、 使用可能なファイルロックエントリがもうない。
関連事項
close(2), execve(2), getdtablesize(2), open(2V), sigvec(2), lockf(3), lockd(8C)
バグ
fcntl メカニズムを 介して得られたファイルロックは、 flock(2) を 使用して得られたものとは、 いかようにも互いに作用し合うことはありません。 しかし、 lockf(3) によってセットされた排他的ロックとは正しく働きます。 要求したプロセスが指定されたロックを 保持している場合、 F_GETLK は F_UNLCK を 返します。 したがって、 プロセスが SIGLOST シグナルを キャッチしたあとに、 まだ特定のロックを 保持しているかどうかを プロセスが判定する方法はありません。 ネットワーク環境では、 F_GETLK によって返される l_pid の値は、 ほとんど無意味です。
NEWS-OSRelease 3.3