0 | совпадение было найдено |
1 | совпадений найдено не было |
2 | синтаксическая ошибка или недоступны файлы поиска |
Наличие кода возврата позволяет программам взаимодействовать друг с другом. Например, следующая программа (назовем ее fail) может являться условием неудачи и использоваться в соответствующих синтаксических конструкциях shell:
main() {
exit(1);
}
$ <b>fail</b>
$ <b>echo $? </b>
Выведем код возврата программы fail
1
$ <b>fail || echo fail</b>
Конструкция shell, использующая условие неудачи fail
fail
Помимо передачи кода возврата, функция exit(2) производит ряд действий, в частности выводит буферизованные данные и закрывает потоки ввода/вывода. Альтернативой ей является функция _exit(2), которая не производит вызовов библиотеки ввода/вывода, а сразу вызывает системную функцию завершения ядра. Более подробно о процедурах завершения процесса см. раздел "Создание и управление процессами".
Задача может зарегистрировать обработчики выхода (exit handler), — функции, которые вызываются после вызова exit(2), но до окончательного завершения процесса. Эти обработчики, вызываемые по принципу LIFO (последний зарегистрированный обработчик будет вызван первым), запускаются только при "добровольном" завершении процесса. Например, при получении процессом сигнала обработчики выхода вызываться не будут. Для обработки таких ситуаций следует использовать специальные функции — обработчики сигналов (см. раздел "Сигналы" далее в этой главе).
Обработчики выхода регистрируются с помощью функции atexit(3C):
#include <stdlib.h>
int atexit(void(*func)(void));
Функцией atexit(1) может быть зарегистрировано до 32 обработчиков.
На рис. 2.7 проиллюстрированы возможные варианты запуска и завершения программы, написанной на языке С.
Рис. 2.7. Запуск и завершение C-программы
Работа с файлами
В среде программирования UNIX существуют два основных интерфейса для файлового ввода/вывода:
1. Интерфейс системных вызовов, предлагающий системные функции низкого уровня, непосредственно взаимодействующие с ядром операционной системы.
2. Стандартная библиотека ввода/вывода, предлагающая функции буферизованного ввода/вывода.
Второй интерфейс является "надстройкой" над интерфейсом системных вызовов, предлагающей более удобный способ работы с файлами.
В следующих разделах будут рассмотрены:
□ оба интерфейса, и особенно первый, поскольку именно он представляет набор базовых услуг ядра;
□ программный интерфейс управления жесткими и символическими связями файла;
□ функции изменения владельцев файла и прав доступа;
□ метаданные файла;
□ пример программы, выводящей на экран наиболее существенную информацию о файле, подобно тому, как это делает утилита ls(1).
Основные системные функции для работы с файлами
В табл. 2.7 приведены основные системные функции работы с файлами, являющиеся образами системных вызовов в программе С.
Функции более высокого уровня, предлагаемые стандартной библиотекой ввода/вывода, которые в конечном счете используют описанные здесь системные вызовы, рассматриваются в следующем разделе.
Таблица 2.7. Основные системные функции работы с файлами
Системная функция | Описание |
open(2) | Служит для получения доступа на чтение и/или запись к указанному файлу. Если файл существует, он открывается, и процессу возвращается файловый дескриптор, адресующий дальнейшие операции с файлом. Если файл не существует, он может быть создан |
creat(2) | Служит для создания файла |
close(2) | Закрывает файловый дескриптор, связанный с предварительно открытым файлом |
dup(2) | Возвращает дубликат файлового дескриптора |
dup2(2) | Возвращает дубликат файлового дескриптора, но позволяет явно указать его значение |
lseek(2) | Устанавливает файловый указатель на определенное место файла. Дальнейшие операции чтения/записи будут производиться, начиная с этого смещения |
read (2) | Производит чтение указанного количества байтов из файла |
readv(2) | Производит несколько операций чтения указанного количества байтов из файла |
write(2) | Производит запись указанного количества байтов в файл |
writev(2) | Производит несколько операций записи указанного количества байтов в файл |
pipe(2) | Создает коммуникационный канал, возвращая два файловых дескриптора |
fcntl(2) | Обеспечивает интерфейс управления открытым файлом |
Кратко рассмотрим каждую из этих функций.
Функция open(2)
Открывает указанный файл для чтения или записи и имеет следующий вид:
#include <fcntl.h>
int open(const char *path, int oflag, mode_t mode);
Первый аргумент (
path
) является указателем на имя файла. Это имя может быть как абсолютным (начинающимся с корневого каталога /), так и относительным (указанным относительно текущего каталога). Аргумент
oflag
указывает на режим открытия файла и представляет собой побитное объединение флагов, приведенных в табл. 2.8, с помощью операции ИЛИ. Напомним, что если права доступа к файлу не разрешают указанного режима работы с файлом, операция открытия файла будет запрещена, и функция
open(2) завершится с ошибкой (
errno=EACCESS
). Аргумент mode, определяющий права доступа к файлу, используется только при создании файла (как показано в табл. 2,8, функция
open(2) может использоваться и для создания файла) и рассматривается при описании функции
creat(2) в разделе "Права доступа" этой главы.