- •Введение
- •Глава 1. Фундаментальные концепции unix Систем
- •Программы, процессы и потоки
- •Сигналы
- •Идентификаторы процессов, группы процессов и сеансы
- •Система прав
- •Другие атрибуты процесса
- •Межпроцессное взаимодействие
- •Использование системных вызовов
- •Краткие описания функций и обработка ошибок
- •Контрольные вопросы
- •Литература
- •Глава 2. Базовые операции ввода-вывода
- •Файловые операции ввода - вывода
- •Стандартные дескрипторы
- •Системные вызовы open и creat
- •Системный вызов umask
- •Системный вызов unlink
- •Текущая позиция в файле
- •Системный вызов write
- •2.8. Системный вызов read
- •2.9. Системный вызов close
- •2.10. Системный вызов lseek
- •2.11. Системные вызовы pread и pwrite
- •2.12. Системные вызовы truncate и ftruncate
- •Контрольные вопросы
- •Литература
- •Глава 3. Дополнительные операции файлового ввода_вывода
- •Низкоуровневый доступ к файловой системе
- •Жесткие и символические ссылки
- •Системный вызов getcwd
- •Отображение метаданных файла
- •Системные вызовы getpwuid, getgrgid и getlogin
- •Каталоги
- •Системные вызовы chdir и fchdir
- •Системные вызовы mkdir и rmdir
- •Контрольные вопросы
- •Литература
- •Глава 4. Процессы и потоки
- •4.1. Среда окружения
- •Системный вызов exec
- •Системный вызов fork
- •Завершение процесса и системные вызовы exit
- •Системные вызовы wait, waitpid и waitid
- •Получение и изменение идентификаторов пользователя и группы
- •Получение и изменение приоритета
- •Контрольные вопросы
- •Литература
- •Глава 5. Механизмы межпроцессного взаимодействия
- •5.1. Каналы
- •5.2. Системные вызовы dup и dup2
- •5.3. Двунаправленное взаимодействие с использованием однонаправленных каналов
- •Контрольные вопросы
- •Литература
- •Глава 6.Механизмы взаимодействия процессов
- •Именованные каналы (fifo)
- •Системные вызовы для работы с очередями сообщений posix
- •Семафоры
- •Системные вызовы для работы с общей памятью posix
- •Контрольные вопросы
- •Литература
- •Глава 7.Сетевое взаимодействие и сокеты
- •Основные системные вызовы для работы с сокетами, образующими логические соединения
- •Обслуживание нескольких клиентов
- •Адресация сокетов
- •In_port_t sin_port; /* номер порта (uint16_t) */
- •In_addr_t s_addr; /* адрес iPv4 (uint32_t) */
- •Домен адресов af_inet6
- •In_port_t sin6_port; /* номер порта (uint16_t) */
- •Доменная система именования
- •Параметры сокетов
- •Контрольные вопросы
- •Литература
- •Глава 8.Сигналы и таймеры
- •Введение в сигналы
- •Жизненный цикл сигналов
- •Типы сигналов
- •Системный вызов sigaction
- •Контрольные вопросы
- •Литература
- •Заключение
- •Список литературы
- •Глава 2. Базовые операции ввода-вывода 14
- •Глава 3. Дополнительные операции файлового ввода_вывода 25
- •Глава 6. Механизмы взаимодействия процессов 58
Системные вызовы open и creat
Системный вызов open – открывает или создает файл:
#include <sys/stat.h>
#include <fcntl.h>
int open(
const char *path, /* полное имя файла*/
int flags, /* флаги */
mode_t perms /* права доступа (если создается новый файл) */
);
/* Возвращает дескриптор файла или -1 в случае ошибки (код ошибки находится в глобальной переменной errno) */
Вызов open открывает существующий файл или создает новый, но в данном случае это может быть только обычный файл. Специальные файлы создаются вызовом mknod, а именованные каналы – вызовом mkfifo. После того, как файл будет открыт, можно использовать полученный дескриптор в вызовах read, write, lseek, close и многих других.
Рассмотрим открытие существующего файла, имя которого задается аргументом path. Если через аргумент flags передается значение O_RDONLY, то файл открывается только для чтения, O_WRONLY – только для записи, O_RDWR - как для записи, так и для чтения. Например, если эффективный идентификатор пользователя у процесса совпадает с идентификатором владельца файла, то для него должны быть установлены права доступа на чтение и/или на запись. В случае открытия существующего файла, аргумент perms игнорируется и в текстах программ, как правило, вообще опускается. Таким образом, функция open вызывается всего с двумя аргументами. Ниже приводится пример кода, который открывает существующий файл:
int fd;
fd = open(“/home/marc/oldfile”, O_RDONLY);
Вызов open присваивает файловому дескриптору наименьший из доступных номеров. Знание этого обстоятельства может порой сослужить неплохую службу. Например, когда необходимо перенаправить один из стандартных дескрипторов - 0, 1 или 2, нужно просто закрыть этот дескриптор и открыть файл, который получит номер только что закрытого дескриптора.
Рассмотрим создание нового файла. Если файл с указанным именем не существует, вызов open создаст его, при условии, что аргумент flags содержит флаг O_CREAT. Флаг O_CREAT обычно дополняется флагом O_WRONLY или O_RDWR. Кроме того, на этот раз необходимо определить права доступа к файлу, например:
fd = open(“/home/marc/newfile”, O_RDWR | O_CREAT, PERM_FILE);
Иногда возникает необходимость удалять содержимое файла при открытии. Делается это с помощью передачи флага O_TRUNC:
fd = open(“/home/marc/newfile”, O_WRONLY | O_CREAT | O_TRUNC, PERM_FILE);
Использование флага O_TRUNC приводит к уничтожению всех данных в файле, поэтому его допустимо указывать только при открытии существующего файла и при условии, что процесс имеет право на запись в открываемый файл. По той же причине, флаг O_TRUNC не может использоваться совместно с флагом O_RDONLY. Чтобы создать новый файл (с флагом O_CREAT), процесс должен иметь право на запись в каталог, поскольку ссылка на файл будет записана в файл каталога. При открытии существующего файла права доступа к каталогу не имеют значения. В этом случае в расчет принимаются только права доступа к файлу. Комбинация флагов O_WRONLY | O_CREAT | O_TRUNC настолько обычна (создать файл или очистить его и открыть на запись), что для этой цели существует специальный системный вызов: creat - создает новый или очищает существующий файл и открывает его.
#include <sys/stat.h>
#include <fcntl.h>
int creat(
const char *path, /* полное имя файла*/
mode_t perms /* права доступа */
);
/* Возвращает дескриптор файла или -1 в случае ошибки (код ошибки находится в глобальной переменной errno) */
Фактически, вызов creat можно оформить в виде макроопределения:
#define creat(path, perms) open(path, O_WRONLY | O_CREAT | O_TRUNC, perms)
Каждому файлу назначается идентификатор пользователя-владельца и идентификатор группы-владельца. Правила назначения владельца и группы выглядят следующим образом:
в качестве владельца файлу назначается эффективный идентификатор пользователя процесса;
в качестве группы устанавливается либо идентификатор группы каталога, в котором создается файл, либо эффективный идентификатор группы процесса.
У приложения нет возможности выбрать, какая из двух групп будет присвоена файлу, но оно может узнать это с помощью системного вызова stat. Чтобы принудительно назначить файлу нужную группу, можно воспользоваться системным вызовом chown, хотя подобные требования к приложениям предъявляются довольно редко.
Существует еще один флаг - O_EXCL, который в сочетании с O_CREAT вызывает ошибку при попытке открыть существующий файл. Системный вызов open, используемый без флага O_CREAT, означает «открыть файл, если он существует, в противном случае – завершиться с ошибкой». С комбинацией флагов O_CREAT | O_EXCL - с точностью до наоборот «создать новый файл, если он не существует, в противном случае – завершиться с ошибкой». Одно из интересных применений флага O_EXCL - работа с файлами блокировок. Другая область применений – обслуживание временных файлов, которые должны удаляться при нормальном завершении приложения.
Использование файлов блокировок. Процессы, которые требуют исключительного доступа к ресурсу, могут придерживаться следующего протокола: прежде чем получить доступ к ресурсу, они должны попытаться создать файл, используя флаг O_EXCL. Это удастся сделать только одному процессу, все остальные вызовы open будут терпеть неудачу. В случае появления ошибки, процесс может немного подождать или заняться выполнением других действий и попробовать получить доступ к ресурсу позднее. В случае успешного создания файла, процесс выполняет необходимые действия с ресурсом и затем удаляет файл. После этого другой конкурирующий процесс сможет получить доступ к ресурсу. Такой способ блокировки будет работать, только если обеспечена атомарность процесса проверки существования файла и его создания – никакой другой процесс не должен иметь возможность исполняться в промежутке между этими двумя действиями. Необходим надежный способ, гарантирующий атомарность операции, который носит название блокировка. Протокол, описанный выше, прекрасно укладывается в вызов двух функций: lock и unlock, следующим образом:
if (lock (“accounts”)) {
…действия с ресурсом accounts…
unlock(“accounts”);
}
else
…невозможно установить блокировку…
Если теперь два процесса попытаются выполнить этот участок программы, то блокировка предотвратит одновременное исполнение защищенной секции кода (действия с ресурсом accounts). Когда процесс не может захватить блокировку, он начинает чередовать периоды ожидания с попытками захвата, такая последовательность действий называется голосованием. Это огромная нагрузка на центральный процессор и все лишь для того, чтобы получить ответ на вопрос: Моя очередь еще не подошла? Блокировка может освободится, когда процесс еще спит, и он не узнает об этом, пока не проснется, а это тоже лишняя трата времени. К счастью, среди прочих возможностей, в Unix существует так называемая система блокировок. Она обеспечивает пробуждение процесса, когда происходит ожидаемое им событие.
Описание флагов системного вызова open. Системному вызову open можно передать большое количество флагов, представленных в табл. 2.1.
Таблица 2.1. Флаги системного вызова open
Флаг |
Описание |
O_RDONLY |
Открыть только для чтения |
O_WRONLY |
Открыть только для записи |
O_RDWR |
Открыть для чтения и для записи |
O_APPEND |
Открыть для дополнения в конец файла |
O_CREAT |
Создать новый, если не существует |
O_DSYNC |
Установить режим синхронного ввода-вывода |
O_EXCL |
Не открывать, если существует. Используется в комбинации с O_CREAT |
O_NOCTTY |
Не делать устройство управляющим терминалом |
O_NONBLOCK |
Неблокирующий режим работы с именованными каналами и специальными файлами |
O_RSYNC |
Установить режим синхронного ввода-вывода |
O_SYNC |
Установить режим синхронного ввода-вывода |
O_TRUNC |
Удалить содержимое файла – усечь его размер до нуля |