# 36.10. `fcntl` --- `fcntl` および `ioctl` システムコール

このモジュールでは、ファイル記述子 (file descriptor) に基づいたファイル制御および I/O 制御を実現します。 このモジュールは、 Unix のルーチンである `fcntl()` および `ioctl()` へのインタフェースです。 これらのシステムコールの完全な説明は、 fcntl(2) と ioctl(2) のUnix マニュアルページを参照してください。

このモジュール内の全ての関数はファイル記述子 fd を最初の引数に取ります。 この値は `sys.stdin.fileno()` が返すような整数のファイル記述子でも、 `sys.stdin` 自体のような、純粋にファイル記述子だけを返す `fileno()` メソッドを提供しているファイルオブジェクトでもかまいません。

このモジュールでは以下の関数を定義しています:

`fcntl.``fcntl`(fd, op[, arg])

  操作 op をファイル記述子 fd (または `fileno()` メソッドを提供しているファイルオブジェクト) に対して実行します。 op として用いられる値はオペレーティングシステム依存で、 `fcntl` モジュール内に関連する C ヘッダファイルと同じ名前が使われている定数の形で利用出来ます。引数 arg はオプションで、標準では整数値 `0` です。この引数を与える場合、整数か文字列の値をとります。引数が無いか整数値の場合、この関数の戻り値は C 言語の `fcntl()` を呼び出した際の整数の戻り値になります。引数が文字列の場合には、 `struct.pack()` で作られるようなバイナリの構造体を表します。バイナリデータはバッファにコピーされ、そのアドレスが C 言語の `fcntl()` 呼び出しに渡されます。 呼び出しが成功した後に戻される値はバッファの内容で、文字列オブジェクトに変換されています。 返される文字列は arg 引数と同じ長さになます。 この値は 1024 バイトに制限されています。 オペレーティングシステムからバッファに返される情報の長さが 1024 バイトよりも大きい場合、大抵はセグメンテーション違反となるか、より不可思議なデータの破損を引き起こします。

  `fcntl()` が失敗した場合、 `IOError` が送出されます。

`fcntl.``ioctl`(fd, op[, arg[, mutate_flag]])

  この関数は `fcntl()` 関数と同じですが、操作が通常ライブラリモジュール `termios` で定義されており、引数の扱いがより複雑であるところが異なります。

  パラメータ op は32ビットに収まる値に制限されます。 op 引数として使うのに関係のある追加の定数は `termios` モジュールにあって、関連する C ヘッダファイルで使われているのと同じ名前が付けられています。

  パラメータ arg は整数か、存在しない (整数 `0` と等価なものとして扱われます) か、(通常の Python 文字列のような) 読み出し専用のバッファインタフェースをサポートするオブジェクトか、読み書きバッファインタフェースをサポートするオブジェクトです。

  最後の型のオブジェクトを除き、動作は `fcntl()` 関数と同じです。

  可変なバッファが渡された場合、動作は mutate_flag 引数の値で決定されます。

  この値が偽の場合、バッファの可変性は無視され、動作は読み出しバッファの場合と同じになりますが、上で述べた 1024 バイトの制限は回避されます -- 従って、オペレーティングシステムが希望するバッファ長までであれば正しく動作します。

  mutate_flag が真の場合、バッファは (実際には) 根底にある `ioctl()` システムコールに渡され、後者の戻り値が呼び出し側の Python に引き渡され、バッファの新たな内容は `ioctl()` の動作を反映します。 この説明はやや単純化されています。 というのは、与えられたバッファが 1024 バイト長よりも短い場合、バッファはまず 1024 バイト長の静的なバッファにコピーされてから `ioctl()` に渡され、その後引数で与えたバッファに戻しコピーされるからです。

  mutate_flag が与えられなかった場合、2.3 ではこの値は偽となります。 この仕様は今後のいくつかのバージョンを経た Python で変更される予定です: 2.4 では、 mutate_flag を提供し忘れると警告が出されますが同じ動作を行い、2.5 ではデフォルトの値が真となるはずです。

  `ioctl()` が失敗すると、 `IOError` 例外が送出されます。

  以下に例を示します:

      >>> import array, fcntl, struct, termios, os
      >>> os.getpgrp()
      13341
      >>> struct.unpack('h', fcntl.ioctl(0, termios.TIOCGPGRP, "  "))[0]
      13341
      >>> buf = array.array('h', [0])
      >>> fcntl.ioctl(0, termios.TIOCGPGRP, buf, 1)
      0
      >>> buf
      array('h', [13341])

`fcntl.``flock`(fd, op)

  ファイル記述子 fd (`fileno()` メソッドを提供しているファイルオブジェクトも含む) に対してロック操作 op を実行します。 詳細は Unix マニュアルの flock(2) を参照してください (システムによっては、この関数は `fcntl()` を使ってエミュレーションされています)。

  `flock()` が失敗すると、 `IOError` 例外が送出されます。

`fcntl.``lockf`(fd, operation[, length[, start[, whence]]])

  本質的に `fcntl()` によるロッキングの呼び出しをラップしたものです。 fd はロックまたはアンロックするファイルのファイル記述子で、 operation は以下の値のうちいずれかになります:

  - `LOCK_UN` -- アンロック

  - `LOCK_SH` -- 共有ロックを取得

  - `LOCK_EX` -- 排他的ロックを取得

  operation が `LOCK_SH` または `LOCK_EX` の場合、 `LOCK_NB` とビット OR にすることでロック取得時にブロックしないようにすることができます。 `LOCK_NB` が 使われ、ロックが取得できなかった場合、 `IOError` が送出され、例外は errno 属性を持ち、その値は `EACCESS` または `EAGAIN` になります (オペレーティングシステムに依存します; 可搬性のため、両方の値をチェックしてください)。 少なくともいくつかのシステムでは、 ファイル記述子が参照しているファイルが書き込みのために開かれている場合、 `LOCK_EX` だけしか使うことができません。

  length はロックを行いたいバイト数、 start はロック領域先頭の whence からの相対的なバイトオフセット、 whence は `io.IOBase.seek()` と同じで、具体的には:

  - `0` -- ファイル先頭からの相対位置 (`os.SEEK_SET`)

  - `1` -- 現在のバッファ位置からの相対位置 (`os.SEEK_CUR`)

  - `2` -- ファイルの末尾からの相対位置 (`os.SEEK_END`)

  start の標準の値は 0 で、ファイルの先頭から開始することを意味します。 whence の標準の値も 0 です。

以下に (全ての SVR4 互換システムでの) 例を示します:

    import struct, fcntl, os

    f = open(...)
    rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY)

    lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
    rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)

最初の例では、戻り値 rv は整数値を保持しています; 二つ目の例では文字列値を保持しています。 lockdata 変数の構造体レイアウトはシステム依存です --- 従って `flock()` を呼ぶ方がベターです。

参考

`os` モジュール

  もし `os` モジュールに `os.O_SHLOCK` と `os.O_EXLOCK` が 存在する場合 (BSD のみ)、 `os.open()` 関数は `lockf()` や `flock()` 関数を代替できます。