Операционная система UNIX
Шрифт:
Помимо системных вызовов программисту предлагается большой набор функций общего назначения. Эти функции не являются точками входа в ядро операционной системы, хотя в процессе выполнения многие из них выполняют системные вызовы. Например, функция printf(3S) использует системный вызов write(2) для записи данных в файл, в то время как функции strcpy(3C) (копирование строки) или atoi(3C) (преобразование символа в его числовое значение) вообще не прибегают к услугам операционной системы. Функции, о которых идет речь, хранятся в стандартных библиотеках С и наряду с системными вызовами составляют основу среды программирования в UNIX. Подробное описание этих функций приведено в разделе 3 электронного справочника.
Таким образом, часть библиотечных функций является "надстройкой" над системными вызовами, обеспечивающей более удобный способ получения системных услуг. В качестве примера рассмотрим процесс получения текущей даты и времени. Соответствующий системный вызов time(2) возвращает время в секундах, прошедшее с момента Epoch: 1 января 1970 года. Дополнительная интерпретация этого значения, такая как преобразование в вид, удобный для восприятия (дата и время) с учетом временной зоны, осуществляется библиотечными
На рис. 2.1 показана схема взаимодействия приложения с ядром операционной системы при использовании системных вызовов и библиотечных функций.
Рис. 2.1. Системные вызовы и библиотечные функции
Обработка ошибок
В предыдущем разделе мы обсудили разницу между системными вызовами и библиотечными функциями. Они также различаются по способу передачи процессу информации об ошибке, произошедшей во время выполнения системного вызова или функции библиотеки.
Обычно в случае возникновения ошибки системные вызовы возвращают и устанавливают значение переменной errno, указывающее причину возникновения ошибки. Так, например, существует более десятка причин завершения вызова open(2) с ошибкой, и все они могут быть определены с помощью переменной errno. Файл заголовков <errno.h> содержит коды ошибок, значения которых может принимать переменная errno, с краткими комментариями.
Библиотечные функции, как правило, не устанавливают значение переменной errno, а код возврата различен для разных функций. Для уточнения возвращаемого значения библиотечной функции необходимо обратиться к электронному справочнику man(1).
Поскольку базовым способом получения услуг ядра являются системные вызовы, рассмотрим более подробно обработку ошибок в этом случае.
Переменная errno определена следующим образом:
Следует обратить внимание, что значение errno не обнуляется следующим нормально завершившимся системным вызовом. Таким образом, значение errno имеет смысл только после системного вызова, который завершился с ошибкой.
Стандарт ANSI С определяет две функции, помогающие сообщить причину ошибочной ситуации: strerror(3C) и perror(3C).
Функция strerror(3C) имеет вид:
Функция принимает в качестве аргумента errnum номер ошибки и возвращает указатель на строку, содержащую сообщение о причине ошибочной ситуации.
Функция perror(3C) объявлена следующим образом:
Функция выводит в стандартный поток сообщений об ошибках информацию об ошибочной ситуации, основываясь на значении переменной errno. Строка s, передаваемая функции, предваряет это сообщение и может служить дополнительной информацией, например содержа название функции или программы, в которой произошла ошибка.
Следующий пример иллюстрирует использование этих двух функций:
Запустив программу, мы получим следующий результат на экране:
Эти функции используются, в частности, командным интерпретатором и большинством стандартных утилит UNIX. Например:
В табл. 2.1 приведены наиболее общие ошибки системных вызовов, включая сообщения, которые обычно выводят функции strerror(3C) и perror(3C), а также их краткое описание.
Таблица 2.1. Некоторые ошибки системных вызовов
Код ошибки и сообщение | Описание |
---|---|
E2BIG Arg list too long | Размер списка аргументов, переданных системному вызову exec(2), плюс размер экспортируемых переменных окружения превышает ARG_MAX байт |
EACCESS Permission denied | Попытка доступа к файлу с недостаточными правами для данного класса (определяемого эффективным UID и GID процесса и соответствующими идентификаторами файла) |
EAGAIN Resource temporarily unavailable | Превышен предел использования некоторого ресурса, например, переполнена таблица процессов или пользователь превысил ограничение по количеству процессов с одинаковым UID. Причиной также может являться недостаток памяти или превышение соответствующего ограничения (см. раздел "Ограничения" далее в этой главе) |
EALREADY Operation already in progress | Попытка операции с неблокируемым объектом, уже обслуживающим некоторую операцию |
EBADF Bad file number | Попытка операции с файловым дескриптором, не адресующим никакой файл; также попытка операции чтения или записи с файловым дескриптором, полученным при открытии файла на запись или чтение, соответственно |
EBADFD File descriptor in bad state | Файловый дескриптор
|
EBUSY Device busy | Попытка монтирования устройства (файловой системы), которое уже примонтировано; попытка размонтировать файловую систему, имеющую открытые файлы; попытка обращения к недоступным ресурсам (семафоры, блокираторы и т.п.) |
ECHILD No child processes | Вызов функции wait(2) процессом, не имеющим дочерних процессов или процессов, для которых уже был сделан вызов wait(2) |
EDQUOT Disk quota exceeded | Попытка записи в файл, создание каталога или файла при превышении квоты пользователя на дисковые блоки, попытка создания файла при превышении пользовательской квоты на число inode |
EEXIST File exists | Имя существующего файла использовано в недопустимом контексте, например, сделана попытка создания символической связи с именем уже существующего файла |
EFAULT Bad address | Аппаратная ошибка при попытке использования системой аргумента функции, например, в качестве указателя передан недопустимый адрес |
EFBIG File too large | Размер файла превысил установленное ограничение RLIMIT_FSIZE или максимально допустимый размер для данной файловой системы (см. раздел "Ограничения" далее в этой главе) |
EINPROGRESS Operation now in progress | Попытка длительной операции (например, установление сетевого соединения) для неблокируемого объекта |
EINTR Interrupted system call | Получение асинхронного сигнала, например, сигнала SIGINT или SIGQUIT, во время обработки системного вызова. Если выполнение процесса будет продолжено после обработки сигнала, прерванный системный вызов завершится с этой ошибкой |
EINVAL Invalid argument | Передача неверного аргумента системному вызову. Например, размонтирование устройства (файловой системы), которое не было примонтировано. Другой пример — передача номера несуществующего сигнала системному вызову kill(2) |
EIO I/O error | Ошибка ввода/вывода физического устройства |
EISDIR Is a directory | Попытка операции, недопустимой для каталога, например, запись в каталог с помощью вызова write(2) |
ELOOP Number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS | При попытке трансляции имени файла было обнаружено недопустимо большое число символических связей, превышающее значение MAXSYMLINKS |
EMFILE Too many open files | Число открытых файлов для процесса превысило максимальное значение OPEN_MAX |
ENAMETOOLONG File name too long | Длина полного имени файла (включая путь) превысила максимальное значение PATH_MAX |
ENFILE File table overflow | Переполнение файловой таблицы |
ENODEV No such device | Попытка недопустимой операции для устройства. Например, попытка чтения устройства только для записи или операция для несуществующего устройства |
ENOENT No such file or directory | Файл с указанным именем не существует или отсутствует каталог, указанный в полном имени файла |
ENOEXEC Exec format error | Попытка запуска на выполнение файла, который имеет права на выполнение, но не является файлом допустимого исполняемого формата |
ENOMEM Not enough space | При попытке запуска программы (exec(2)) или размещения памяти (brk(2)) размер запрашиваемой памяти превысил максимально возможный в системе |
ENOMSG No message of desired type | Попытка получения сообщения определенного типа, которого не существует в очереди (см. раздел "Сообщения" в главе 3) |
ENOSPC No space left on device | Попытка записи в файл или создания нового каталога при отсутствии свободного места на устройстве (в файловой системе) |
ENOSR Out of stream resources | Отсутствие очередей или головных модулей при попытке открытия устройства STREAMS. Это состояние является временным. После освобождения соответствующих ресурсов другими процессами операция может пройти успешно |
ENOSTR Not a stream device | Попытка применения операции, определенной для устройств типа STREAMS (например системного вызова putmsg(2) или getmsg(2)), для устройства другого типа |
ENOTDIR Not a directory | В операции, предусматривающей в качестве аргумента имя каталога, было указано имя файла другого типа (например, в пути для полного имени файла) |
ENOTTY Inappropriate ioctl for device | Попытка системного вызова ioctl(2) для устройства, которое не является символьным |
EPERM Not owner | Попытка модификации файла, способом, разрешенным только владельцу и суперпользователю и запрещенным остальным пользователям. Попытка операции, разрешенной только суперпользователю |
EPIPE Broken pipe | Попытка записи в канал (pipe), для которого не существует процесса, принимающего данные. В этой ситуации процессу обычно отправляется соответствующий сигнал. Ошибка возвращается при игнорировании сигнала |
EROFS Read-only file system | Попытка модификации файла или каталога для устройства (файловой системы), примонтированного только на чтение |
ESRCH No such process | Процесс с указанным PID не существует в системе |