fcntl — Системные вызовы fcntl и ioctl


Этот модуль выполняет файловый контроль и контроль ввода-вывода для файловых дескрипторов. Это интерфейс для подпрограмм Unix fcntl() и ioctl(). Полное описание этих вызовов см. на страницах справочника fcntl(2) и ioctl(2) Unix.

Все функции в этом модуле принимают дескриптор файла fd в качестве первого аргумента. Это может быть целочисленный файловый дескриптор, например, возвращаемый sys.stdin.fileno(), или объект io.IOBase, например сам sys.stdin, который предоставляет fileno(), возвращающий подлинный файловый дескриптор.

Изменено в версии 3.3: Операции в данном модуле раньше вызывали IOError, а теперь — OSError.

Изменено в версии 3.8: Модуль fcntl теперь содержит константы F_ADD_SEALS, F_GET_SEALS и F_SEAL_* для уплотнения файловых дескрипторов os.memfd_create().

Модуль определяет следующие функции:

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

Выполнить операцию cmd над файловым дескриптором fd (также принимаются файловые объекты, предоставляющие метод fileno()). Значения, используемые для cmd, зависят от операционной системы и доступны как константы в модуле fcntl с теми же именами, что и в соответствующих заголовочных файлах C. Аргумент arg может быть целым числом или объектом bytes. При целочисленном значении возвращаемое значение этой функции — это целочисленное возвращаемое значение вызова C fcntl(). Когда аргумент — байты, он представляет двоичную структуру, например. созданный struct.pack(). Двоичные данные копируются в буфер, адрес которого передаётся вызову C fcntl(). Возвращаемое значение после успешного вызова — это содержимое буфера, преобразованное в объект bytes. Длина возвращаемого объекта будет такой же, как длина аргумента arg. Он ограничен 1024 байтами. Если информация, возвращаемая операционной системой в буфере, превышает 1024 байта, это, скорее всего, приведет к нарушению сегментации или более незаметному повреждению данных.

Если fcntl() выходит из строя, вызывается OSError.

Вызывает событие аудита fcntl.fcntl с аргументами fd, cmd, arg.

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

Функция идентична функции fcntl(), за исключением того, что обработка аргументов ещё более сложна.

Параметр request ограничен значениями, которые могут соответствовать 32-битным значениям. Дополнительные константы, представляющие интерес для использования в качестве аргумента request, можно найти в модуле termios под теми же именами, которые используются в соответствующих файлах заголовков C.

Параметр arg может быть целым числом, объектом, поддерживающим интерфейс буфера только для чтения (например, bytes), или объектом, поддерживающим интерфейс буфера чтения-записи (например, bytearray).

Во всех случаях, кроме последнего, поведение такое же, как для функции 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])

Вызывает событие аудита fcntl.ioctl с аргументами fd, request, arg.

fcntl.flock(fd, operation)

Выполнить операцию блокировки operation для дескриптора файла fd (также принимаются файловые объекты, обеспечивающие метод fileno()). Подробности см. в руководстве по Unix flock(2). (В некоторых системах функция эмулируется с помощью fcntl().)

В случае сбоя flock() возникает исключение OSError.

Вызывает событие аудита fcntl.flock с аргументами fd, operation.

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

По сути, это обёртка для вызовов блокировки fcntl(). fd — это дескриптор файла (также принимаются файловые объекты, реализующие метод fileno()) файла, который нужно заблокировать или разблокировать, а cmd — одно из следующих значений:

  • LOCK_UN — разблокировка
  • LOCK_SH — получить разделяемую блокировку
  • LOCK_EX — получить эксклюзивную блокировку

Когда cmd — это LOCK_SH или LOCK_EX, он также может быть побитовым ИЛИ с LOCK_NB, чтобы избежать блокировки при получении блокировки. Если используется LOCK_NB и блокировка не может быть получена, будет сгенерировано OSError, а для исключения будет установлено значение errno для атрибута EACCES или EAGAIN (в зависимости от операционной системы; для переносимости проверить оба значения). По крайней мере, в некоторых системах LOCK_EX можно использовать только в том случае, если файловый дескриптор ссылается на файл, открытый для записи.

len — это количество байтов для блокировки, start — это байтовое смещение, при котором начинается блокировка, относительно whence, а whence, в частности, соответствует io.IOBase.seek():

  • 0 — относительно начала файла (os.SEEK_SET)
  • 1 — относительно текущей позиции буфера (os.SEEK_CUR)
  • 2 — относительно конца файла (os.SEEK_END)

По умолчанию для start установлено значение 0, что означает запуск с начала файла. По умолчанию для len установлено значение 0, что означает блокировку до конца файла. Значение по умолчанию для whence также равно 0.

Вызывает событие аудита fcntl.lockf с аргументами 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
Если флаги блокировки O_SHLOCK и O_EXLOCK присутствует в модуле os (только на BSD), функция os.open() предоставляет альтернативу lockf() и flock() функций.