fcntlfcntlioctl 系统调用


此模块对文件描述符执行文件和 I/O 控制。它是 fcntl()ioctl() Unix 例程的接口。有关完整详细信息,请参阅 fcntl(2)ioctl(2) Unix 手册页。

可用性: Unix,不适用于 Emscripten,不适用于 WASI。

此模块中的所有函数都将文件描述符 fd 作为其第一个参数。这可以是整数文件描述符,例如 sys.stdin.fileno() 返回的文件描述符,也可以是 io.IOBase 对象,例如 sys.stdin 本身,它提供一个返回真实文件描述符的 fileno()

3.3 版中的更改: 此模块中的操作过去会引发 IOError,而现在它们会引发 OSError

3.8 版中的更改: fcntl 模块现在包含 F_ADD_SEALSF_GET_SEALSF_SEAL_* 常量,用于密封 os.memfd_create() 文件描述符。

版本 3.9 中已更改:在 macOS 上,fcntl 模块公开了 F_GETPATH 常量,该常量从文件描述符获取文件路径。在 Linux(>=3.15) 上,fcntl 模块公开了 F_OFD_GETLKF_OFD_SETLKF_OFD_SETLKW 常量,这些常量在使用打开的文件描述符锁时使用。

版本 3.10 中已更改:在 Linux >= 2.6.11 上,fcntl 模块公开了 F_GETPIPE_SZF_SETPIPE_SZ 常量,这些常量分别允许检查和修改管道的长度。

版本 3.11 中已更改:在 FreeBSD 上,fcntl 模块公开了 F_DUP2FDF_DUP2FD_CLOEXEC 常量,这些常量允许复制文件描述符,后者会另外设置 FD_CLOEXEC 标志。

版本 3.12 中已更改:在 Linux >= 4.5 上,fcntl 模块公开了 FICLONEFICLONERANGE 常量,这些常量允许通过在某些文件系统(例如 btrfs、OCFS2 和 XFS)上重新链接来共享一个文件的部分数据与另一个文件。此行为通常称为“写时复制”。

该模块定义了以下函数

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

对文件描述符 fd 执行操作 cmd(也接受提供 fileno() 方法的文件对象)。用于 cmd 的值因操作系统而异,并且在 fcntl 模块中作为常量提供,使用与相关 C 头文件中相同的名称。参数 arg 可以是整数值或 bytes 对象。对于整数值,此函数的返回值是 C fcntl() 调用的整型返回值。当参数是字节时,它表示二进制结构,例如由 struct.pack() 创建。二进制数据将复制到一个缓冲区,其地址传递给 C fcntl() 调用。成功调用后的返回值是缓冲区的内容,已转换为 bytes 对象。返回对象的长度将与 arg 参数的长度相同。这限制为 1024 字节。如果操作系统在缓冲区中返回的信息大于 1024 字节,则很可能导致段错误或更微妙的数据损坏。

如果 fcntl() 调用失败,则会引发 OSError

引发 审核事件 fcntl.fcntl,带有参数 fdcmdarg

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

此函数与 fcntl() 函数相同,只是参数处理更加复杂。

request 参数仅限于可以放入 32 位的值。可在 termios 模块中找到更多可用于作为 request 参数的常量,名称与相关 C 头文件中使用的相同。

参数arg可以是整数、支持只读缓冲区接口的对象(如 bytes)或支持读写缓冲区接口的对象(如 bytearray)。

除了最后一种情况,行为与 fcntl() 函数相同。

如果传递了可变缓冲区,则行为由mutate_flag参数的值决定。

如果为 false,则忽略缓冲区的可变性,并且行为与只读缓冲区相同,但避免了上面提到的 1024 字节限制——只要您传递的缓冲区至少与操作系统想要放置的内容一样长,事情应该可以正常进行。

如果mutate_flag为 true(默认值),则缓冲区(实际上)会传递给底层 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])

引发 审计事件 fcntl.ioctl,其中参数为 fdrequestarg

fcntl.flock(fd, operation)

对文件描述符fd执行锁定操作operation(提供 fileno() 方法的文件对象也可以接受)。有关详细信息,请参阅 Unix 手册 flock(2)。(在某些系统上,此函数使用 fcntl() 进行模拟。)

如果 flock() 调用失败,则会引发 OSError 异常。

引发 审计事件 fcntl.flock,其中参数为 fdoperation

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

这基本上是 fcntl() 锁定调用的一个包装器。fd 是要锁定或解锁的文件的文件描述符(提供 fileno() 方法的文件对象也可以接受),cmd 是以下值之一

fcntl.LOCK_UN

释放现有锁。

fcntl.LOCK_SH

获取共享锁。

fcntl.LOCK_EX

获取独占锁。

fcntl.LOCK_NB

与任何其他三个 LOCK_* 常量进行按位 OR 运算,以使请求变为非阻塞。

如果使用了 LOCK_NB 且无法获取锁,则会引发 OSError,并且异常将具有设置为 EACCESEAGAINerrno 属性(具体取决于操作系统;为了便于移植,请检查这两个值)。在至少一些系统上,仅当文件描述符引用为写入而打开的文件时,才能使用 LOCK_EX

len 是要锁定的字节数,start 是锁定的字节偏移量,相对于 whencewhenceio.IOBase.seek() 相同,具体如下

start 的默认值为 0,表示从文件开头开始。len 的默认值为 0,表示锁定到文件末尾。whence 的默认值也是 0。

引发 审计事件 fcntl.lockf,其参数为 fdcmdlenstartwhence

示例(均在 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

如果锁定标志 O_SHLOCKO_EXLOCK 存在于 os 模块中(仅在 BSD 上),os.open() 函数提供了一个替代 lockf()flock() 函数的方法。