Выбрать главу

Большинство, но не все, системные вызовы объявлены в <unistd.h>. Фактически файл <unistd.h> представляет собой универсальное вместилище практически для всех системных вызовов. Чтобы определить, какие включаемые файлы нужно использовать, обычно нужно обратиться к системным man-страницам. Хотя описания функций на man-страницах зачастую весьма лаконичны, там можно найти точные указания о том, какой файл должен быть включен для использования функции.

Есть одна особенность, свойственная системам Unix. Системные вызовы документированы в отдельном разделе man-страниц для библиотечных функций, и вы будете использовать библиотечные функции для доступа к системным вызовам. Там, где библиотечные функции отличаются от системных вызовов, предусмотрены отдельные man- страницы. Это не вызывало бы проблем, однако практически всегда требуется читать страницу, описывающую библиотечную функцию, номер которой больше номера страницы с описанием соответствующего системного вызова. Ввиду того, что man-страницы выводятся, начиная с меньших номеров, приходится проделывать лишнюю работу.

Простого указания номера раздела недостаточно. Системные вызовы, которые помещены в минимальные функции-оболочки из библиотеки С, не документированы как часть библиотеки, следовательно команда man 3 функция не найдет их. Для того чтобы убедиться, что вы прочли всю необходимую для вас информацию, вначале взгляните на man-страницу, не указывая раздел. Если это раздел 2 на man-странице, посмотрите, есть ли там раздел 3 с таким же именем. Если открывается раздел 1 man-страницы, как это часто случается, внимательно просмотрите разделы 2 и 3.

К счастью, существует другой способ решения такой проблемы. Многие версии программы man, включая используемую в системах Linux, позволяют указывать альтернативный путь поиска man-страниц. Прочтите man-страницу о самой программе man, чтобы определить, поддерживается ли в вашей версии man переменная окружения MANSECT и аргумент -S. Если переменная поддерживается, можно установить MANSECT в что-нибудь вроде 3:2:1:4:5:6:7:8:tcclass="underline" n:class="underline" p:о. Просмотрите в файле конфигурации man (в большинстве систем Linux это /etc/man.config) текущую настройку MANSECT.

Большинство системных вызовов возвращает 0 при успешном выполнении. В случае возникновения ошибки они возвращают отрицательное значение. Вследствие этого, во многих случаях, подходит простейшая форма обработки ошибок.

if (ioctl(fd, FN, data)) {

 /* обработка ошибки на основе errno */

}

Часто встречается следующая форма:

if (ioctl(fd, FN, data) < 0) {

 /* обработка ошибки на основе errno */

}

Для системных вызовов, которые возвращают 0, обозначая успех, оба эти случая идентичны. В своем коде можете выбрать то, что вам больше подходит. Будьте готовы к тому, что столкнетесь с этими и другими способами обработки в чужих кодах.

9.2.4. Общие коды возврата ошибок

Существует множество общих кодов ошибок, для которых вы вполне могли наблюдать сообщения. Некоторые из этих сообщений могут сбивать с толку. Без знаний о том, что можно делать в Linux-системе, трудно понять ошибки, которые могут возникать в процессе работы. Внимательно прочитайте приведенный ниже список.

Для многих кодов возврата ошибок даны примеры одного или двух системных вызовов, которые обычно могут выдать то или иное сообщение об ошибке. Это не означает, что к таким ошибкам могут привести исключительно представленные системные вызовы.

Для определения того, какую ошибку можно ожидать от определенного системного вызова, обращайтесь к соответствующим man-страницам. В частности, с помощью команды man 3 errno можно получить список кодов ошибок, определенных POSIX. Тем не менее, ситуация часто изменяется, и man-страницы не всегда отвечают существующему состоянию дел. Если системный вызов возвращает неожиданный код ошибки, можно предположить, что скорее man-страница устарела, а не системный вызов дал сбой. Исходный код Linux поддерживается более тщательно, чем документация.

E2BIG Список аргументов слишком длинный. При запуске нового процесса с помощью exec() существует ограничение на длину задаваемого списка аргументов. См. главу 10.
EACCESS В доступе будет отказано. Эта ошибка возвращается системным вызовом access(), рассматриваемым в главе 11, и представляет собой более информативный код возврата, чем само состояние ошибки.
EAGAIN Возвращается при попытке выполнения неблокируемого ввода-вывода, если нет доступных данных. EWOULDBLOCK является синонимом EAGAIN. При блокируемом вводе-выводе системный вызов установил бы блокировку и ожидал бы данных.
EBADF Неправильный номер файла. Был передан номер файла, не ссылающийся на открытый файл, в функцию read(), close(), ioctl() или другой системный вызов, принимающий номер файла в качестве аргумента.
EBUSY Системный вызов mount() возвращает эту ошибку при попытке смонтировать файловую систему, которая уже смонтирована, или размонтировать файловую систему, которая в настоящий момент используется.
ECHILD Дочерние процессы отсутствуют. Возвращается семейством системных вызовов wait(). См. главу 10.
EDOM Это ошибка не системного вызова, а ошибка из библиотеки С системы. EDOM устанавливается математическими функциями, если аргумент выходит за пределы допустимого диапазона. (Это EINVAL для области функции.) Например, функция sqrt() не работает с комплексными числами и потому не принимает отрицательные аргументы.
EEXIST Возвращается creat(), mknod() или mkdir(), если файл уже существует, или функцией open() в том же случае, если указаны флаги O_CREAT и O_EXCL.
EFAULT Неверный указатель (указывающий на недоступную область памяти) был передан в качестве аргумента системному вызову. Обращение по этому указателю из пользовательской программы, которая произвела системный вызов, приведет к ошибке сегментации.
EFBIG Возвращается write() при попытке записи файла, который длиннее, чем может логически обработать файловая система (физические ограничения пространства во внимание не принимаются).