fcntlfcntlioctl 系統呼叫


此模組對檔案描述符執行檔案和 I/O 控制。 它是 fcntl()ioctl() Unix 例程的介面。 有關完整詳細資訊,請參閱 fcntl(2)ioctl(2) Unix 手冊頁。

可用性: Unix,而非 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)上進行重新連結來與其他檔案共享一個檔案的一些資料。 此行為通常被稱為“寫入時複製”。

在 3.13 版本中變更: 在 Linux >= 2.6.32 上,fcntl 模組公開了 F_GETOWN_EXF_SETOWN_EXF_OWNER_TIDF_OWNER_PIDF_OWNER_PGRP 常量,它們允許將 I/O 可用性訊號定向到特定執行緒、程序或程序組。 在 Linux >= 4.13 上,fcntl 模組公開了 F_GET_RW_HINTF_SET_RW_HINTF_GET_FILE_RW_HINTF_SET_FILE_RW_HINTRWH_WRITE_LIFE_* 常量,這些常量允許通知核心關於給定 inode 或透過特定開啟的檔案描述進行寫入的相對預期生命週期。 在 Linux >= 5.1 和 NetBSD 上,fcntl 模組公開了 F_SEAL_FUTURE_WRITE 常量,以用於 F_ADD_SEALSF_GET_SEALS 操作。 在 FreeBSD 上,fcntl 模組公開了 F_READAHEADF_ISUNIONSTACKF_KINFO 常量。 在 macOS 和 FreeBSD 上,fcntl 模組公開了 F_RDAHEAD 常量。 在 NetBSD 和 AIX 上,fcntl 模組公開了 F_CLOSEM 常量。 在 NetBSD 上,fcntl 模組公開了 F_MAXFD 常量。 在 macOS 和 NetBSD 上,fcntl 模組公開了 F_GETNOSIGPIPEF_SETNOSIGPIPE 常量。

該模組定義了以下函式

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 位以內。作為 request 引數使用的其他相關常量可以在 termios 模組中找到,名稱與相關 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_* 常量中的任何一個進行按位或運算,使請求成為非阻塞的。

如果使用 LOCK_NB 並且無法獲取鎖,則會引發 OSError,並且該異常將具有一個設定為 EACCESEAGAINerrno 屬性(取決於作業系統;為了保證可移植性,請檢查這兩個值)。至少在某些系統上,只有當檔案描述符引用為寫入開啟的檔案時,才能使用 LOCK_EX

len 是要鎖定的位元組數,start 是鎖定開始的位元組偏移量,相對於 whence,而 whenceio.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() 函式的替代方案。