fcntl --- fcntl および ioctl システムコール


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

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

バージョン 3.3 で変更: 以前は IOError を送出していたこのモジュールの操作が、 OSError を送出するようになりました。

バージョン 3.8 で変更: The fcntl module now contains F_ADD_SEALS, F_GET_SEALS, and F_SEAL_* constants for sealing of os.memfd_create() file descriptors.

このモジュールには、以下の関数が定義されています:

fcntl.fcntl(fd, cmd, arg=0)

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

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

Raises an auditing event fcntl.fcntl with arguments fd, cmd, arg.

fcntl.ioctl(fd, request, arg=0, mutate_flag=True)

この関数は fcntl() 関数と同じですが、引数の扱いがより複雑であるところが異なります。

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

パラメタ arg は、整数、 (bytes のような) 読み出し専用のバッファインタフェースをサポートするオブジェクト、読み書きバッファインタフェースをサポートするオブジェクトのどれかです。

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

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

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

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

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

以下に例を示します:

>>> 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])

Raises an auditing event fcntl.ioctl with arguments fd, request, arg.

fcntl.flock(fd, operation)

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

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

Raises an auditing event fcntl.flock with arguments fd, operation.

fcntl.lockf(fd, cmd, len=0, start=0, whence=0)

This is essentially a wrapper around the fcntl() locking calls. fd is the file descriptor (file objects providing a fileno() method are accepted as well) of the file to lock or unlock, and cmd is one of the following values:

  • LOCK_UN -- アンロック

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

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

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

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

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

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

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

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

Raises an auditing event fcntl.lockf with arguments fd, cmd, len, start, whence.

以下に (全ての 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 は整数値を保持しています; 二つ目の例では bytes オブジェクトを保持しています。 lockdata 変数の構造体レイアウトはシステム依存です --- 従って flock() を呼ぶ方が良いでしょう。

参考

os モジュール

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