Системный вызов ioctl() — механизм общего назначения для выполнения операций в отношении файлов и устройств, выходящих за пределы универсальной модели ввода-вывода, рассмотренной ранее в данной главе.
#include
int ioctl(int
Возвращаемое при успешном завершении значение зависит от request или при ошибке равно –1
Аргумент fd содержит дескриптор открываемого файла, представленного устройством или файлом, в отношении которого выполняется управляющая операция (указана в аргументе request). Как показывает стандартная для языка C запись в виде многоточия (…), третий аргумент для ioctl(), обозначенный как argp, может быть любого типа. Аргумент request позволяет ioctl() определить, какого типа значение следует ожидать в argp. Обычно argp представляет собой указатель либо на целое число, либо на структуру. В некоторых случаях этот аргумент не применяется.
Использование ioctl() будет показано в следующих главах (к примеру, в разделе 15.5).
Единственная спецификация, имеющаяся в SUSv3 для ioctl(), регламентирует операции по управлению STREAMS-устройствами. (Среда STREAMS относится к особенностям System V, не поддерживаемым основной ветвью ядра Linux, хотя было разработано несколько реализаций в виде дополнений.) Ни одна из других рассматриваемых в книге операций ioctl() в SUSv3 не регламентирована. Но вызов ioctl() был частью системы UNIX с самых ранних версий, вследствие чего несколько операций ioctl() предоставляются во многих других реализациях UNIX. По мере рассмотрения каждой операции ioctl() будут обсуждаться и вопросы портируемости.
Чтобы выполнить ввод/вывод в отношении обычного файла, сначала нужно получить его дескриптор, воспользовавшись системным вызовом open(). Затем ввод/вывод выполняется с помощью системных вызовов read() и write(). После завершения всех операций ввода-вывода следует высвободить дескриптор файла и связанные с ним ресурсы, воспользовавшись системным вызовом close(). Эти системные вызовы могут применяться для выполнения ввода-вывода в отношении всех типов файлов.
Поскольку для всех типов файлов и драйверов устройств реализован один и тот же интерфейс ввода-вывода, позволяющий получить универсальный ввод/вывод, то программа, как правило, может быть использована с любым типом файла, без использования кода, специфичного для типа файла.
Для каждого открытого файла ядро хранит файловое смещение, определяющее место, с которого будут осуществляться следующие чтение или запись. Файловое смещение косвенным образом обновляется при чтении и записи. Используя вызов lseek(), можно явным образом установить позицию файлового смещения в любое место файла или даже за его конец. Запись данных в позицию, находящуюся дальше предыдущего конца файла, приводит к созданию дыры в файле. Чтение из файловой дыры возвращает байты, содержащие нули.
Системный вызов ioctl() предлагает для устройства и файла разнообразные операции, которые не вписываются в стандартную модель файлового ввода-вывода.
4.1. Команда tee считывает свой стандартный ввод, пока ей не встретится символ конца файла, записывает копию своего ввода на стандартное устройство вывода и в файл, указанный в аргументе ее командной строки. (Пример использования этой команды будет показан при рассмотрении FIFO-устройств в разделе 44.7.) Реализуйте tee, используя системные вызовы ввода-вывода. По умолчанию tee перезаписывает любой существующий файл с заданным именем. Укажите ключ командной строки — a (tee — a file), который заставит tee добавлять текст к концу уже существующего файла.
4.2. Напишите программу, похожую на cp, которая при использовании для копирования обычного файла, содержащего дыры (последовательности нулевых байтов), будет также создавать соответствующие дыры в целевом файле.
5 Только если файла с таким именем еще не было в текущем каталоге. Иначе эта команда лишь обновит время последнего обращения к файлу. —
5. Файловый ввод-вывод: дополнительные сведения
В этой главе мы продолжим рассматривать файловый ввод-вывод. Возвращаясь к системному вызову open(), мы познакомимся с концепцией
Будет представлен еще один многоцелевой системный вызов, имеющий отношение к файлам, — fcntl(). Мы рассмотрим один из примеров его использования: извлечение и установку флагов состояния открытого файла.