Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

Большинство, но не все, системные вызовы объявлены в

<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:tcl:n:l: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
при попытке записи файла, который длиннее, чем может логически обработать файловая система (физические ограничения пространства во внимание не принимаются).
EINTR
Системный вызов был прерван. Прерываемые системные вызовы рассматриваются в главе 12.
EINVAL
Возвращается, если системный вызов получил недопустимый аргумент.
EIO
Ошибка ввода-вывода. Обычно генерируется драйвером устройства для обозначения ошибки в оборудовании или неисправимой ошибку взаимодействия с устройством.
EISDIR
Возвращается системными вызовами, требующими имя файла, например
unlink
, если последний компонент в имени пути является каталогом, а не файлом, а данная операция не может быть применена к каталогу.
ELOOP
Возвращается системными вызовами, которые принимают путь, если при разборе пути встречается слишком много символических ссылок в строке (то есть символические ссылки, указывающие на символические ссылки, которые, в свою очередь, указывают на символические ссылки и так далее). Текущее ограничение — 16 символических ссылок на строку.
EMFILE
Возвращается, если для вызываемого процесса нельзя открыть больше файлов.
EMLINK
Возвращается
link
, если в компонуемом файле уже содержится максимальное количество ссылок
для файловой системы (в стандартной файловой системе Linux этот максимум составляет 32 000).
ENAMETOOLONG
Имя пути слишком длинное либо для системы, либо для файловой системы, к которой вы пытаетесь получить доступ.
ENFILE
Возвращается, если ни один процесс системы не может открыть больше ни одного файла.
ENODEV
Возвращается
mount
, если запрошенный тип файловой системы не доступен. Возвращается
open
при попытке открыть специальный файл для устройства, для которого нет ассоциированного драйвера в ядре.
ENOENT
Файл или каталог не существует. Возвращается при попытке получить доступ к несуществующему файлу или каталогу.
ENOEXEC
Ошибка исполняемого формата. Может появиться при попытке запустить (устаревший)
а.out
в системе, в которой отсутствует поддержка бинарных файлов
а.out
. Может также встречаться при попытке запуска бинарного файла формата ELF, собранного для другой архитектуры центрального процессора.
ENOMEM
Не хватает памяти. Возвращается функциями
brk
и
mmap
при неудачной попытке распределения памяти.
ENOSPC
Возвращается
write
при попытке записать файл длиннее, чем объем свободного пространства в файловой системе.
NOSYS
Системный вызов не реализован. Обычно происходит при запуске нового исполняемого файла на старом ядре, которое не поддерживает системный вызов.
ENOTBLK
Системный вызов
mount
возвращает эту ошибку при попытке смонтировать в качестве файловой системы файл, не являющийся специальным файлом блочного устройства.
ENOTDIR
Промежуточный компонент пути существует, но не является каталогом. Возвращается любым системным вызовом, принимающим имя файла.
ENOTEMPTY
Возвращается
rmdir
, если удаляемый каталог не пуст.
ENOTTY
Обычно встречается, когда приложение, которое пытается обратиться к терминалу, запущено с перенаправлением ввода или вывода в канал. Но также может встречаться при попытке совершить операцию ввода-вывода на неправильном типе устройства. Стандартное сообщение об ошибке в этом случае, "not a typewriter", может сбить с толку.
ENXIO
Нет такого устройства или адреса. Обычно генерируется при попытке открыть специальный файл устройства, который ассоциируется с частью не установленного или не настроенного оборудования.
EPERM
У процесса недостаточно полномочий для завершения операции. Эта ошибка обычно встречается в файловых операциях. См. главу 11.
EPIPE
Возвращается
write
, если читающая сторона канала или сокета закрыта и захвачен или проигнорирован сигнал
SIGPIPE
. См. главу 12.
ERANGE
Не являясь ошибкой системного вызова,
ERANGE
устанавливается математическими функциями, если результат невозможно представить возвращаемым типом. Эта ошибка может также возникать в других функциях, если им передается слишком короткий буфер для возвращаемой строки. (Для диапазона этой ошибке соответствует
EINVAL
.)
EROFS
Возвращается
write
при попытке записать в файловую систему, доступную только для чтения.
ESPIPE
Возвращается
lseek
при навигации по файлу, дескриптор которого не поддерживает навигацию (включая файловые дескрипторы для каналов, именованных каналов и сокетов). См. главы 11 и 17.
ESRCH
Нет такого процесса. См. главу 10.
ETXTBSY
Возвращается
open
при попытке открыть на запись запущенный исполняемый файл или совместно используемую библиотеку или любой другой файл, отображенный на память с установленным флажком
MAP_DENYWRITE
(см. главу 13). Чтобы избежать такого поведения, необходимо переименовать файл, сделать новую копию с таким же именем, как у старого файла, и работать с этой новой копией. См. главу 11 с обсуждением того, почему так происходит.
EXDEV
Возвращается
link
, если исходные и целевые файлы находятся в разных файловых системах.

Распространены и некоторые другие коды возврата ошибок, которые относятся только к сетевым функциям. Более подробную информацию можно найти в главе 17.

9.3. Поиск заголовочных и библиотечных файлов

Заголовочные файлы в системе Linux хранятся в иерархии каталогов

/usr/include
. Именно там по умолчанию компилятор ищет включаемые файлы. (Заголовочные файлы могут храниться за пределами
/usr/include
, но тогда на них имеются ссылки внутри
/usr/include
. Например, на момент написания книги включаемые файлы системы X были расположены в
/usr/X11R6/include/X11
, но благодаря символической ссылке компилятор мог найти их через
/usr/include/X11
.)

С библиотеками дело обстоит практически так же, правда, с некоторыми нюансами. Библиотеки, которые считаются важными для загрузки системы (и ее отладки в случае необходимости), расположены в

/lib
. Другие системные библиотеки находятся в
/usr/lib
, кроме библиотек X11R6, которые хранятся в
/usr/X11R6/lib
. Компилятор по умолчанию будет искать стандартные системные библиотеки.

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

pkg-config
обеспечивает эту информацию для каждой версии каждой библиотеки, разработанной для его поддержки.

Часть III

Системное программирование

Глава 10

Модель процессов

Модель процессов — один из "фирменных знаков" Unix. Это — ключ к пониманию прав доступа, отношений между открытыми файлами, сигналов, управления заданиями и большинства других низкоуровневых понятий, описанных в этой книге. Linux адаптирует большую часть модели процессов Unix и добавляет собственные новые идеи, касающиеся реализации облегченных потоков.

10.1. Определение процесса

Что такое процесс? В исходной реализации Unix процессом была любая выполняющаяся программа. Для каждой программы ядро системы отслеживает перечисленные ниже аспекты.

• Текущая точка выполнения (такая как ожидание возврата системного вызова из ядра), часто называемая программным контекстом.

• К каким файлам имеет доступ программа.

• Сертификаты (credentials) программы (например, какой пользователь и группа владеют процессом).

Поделиться с друзьями: