int fcntl (int fd, int command, long arg);

Для многих команд arg не используется. Ниже мы обсудим большую часть применений fcntl(). Этот вызов используется для блокировки файлов, аренды файлов, неблокирующего ввода-вывода, который рассматривается в главе 13, а также уведомления об изменениях каталогов, представленного в главе 14.

11.5.1. Изменение режима доступа к открытому файлу

Режим добавления (указываемый флагом O_APPEND при открытии файла) и неблокирующий режим (флаг O_NONBLOCK), могут быть включены и отключены уже после того, как файл был открыт, с помощью команды F_SETFL в fcntl(). Параметр arg при этом должен содержать флаги, которые нужно установить — если какой-то из флагов не указан для fd, он отключается.

F_GETFL можно использовать для запроса текущих установленных флагов файла. Это возвращает все флаги, включая режим чтения/записи для открытого файла. F_SETFL позволяет только устанавливать упомянутые выше флаги — любые другие флаги, представленные в аргументе arg, игнорируются.

fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_RDONLY);

Такой вызов абсолютно правильный, но он не делает ничего. Включение режима добавления для открытого файлового дескриптора выглядит так, как показано ниже.

fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_APPEND);

Следует отметить, что это предохраняет установку O_NONBLOCK. Отключение режима добавления выглядит похоже.

fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_APPEND);

11.5.2. Модификация флага 'закрыть при выполнении'

Во время системного вызова exec() дескрипторы файлов обычно остаются открытыми для использования в новых программах. В некоторых случаях может потребоваться, чтобы файлы закрывались, когда вызывается exec(). Вместо закрытия их вручную вы можете попросить систему закрыть соответствующий файловый дескриптор при вызове exec() с помощью команд F_GETFD и F_SETFD в fcntl(). Если флаг 'закрыть при выполнении' (close-on-exec) установлен, когда применяется F_GETFD, возвращается ненулевое значение, в противном случае возвращается ноль. Флаг 'закрыть при выполнении' устанавливается командой F_SETFD; он отключается, если arg равно 0, в противном случае он включается.

Ниже показано, как можно заставить fd закрываться, когда процесс вызывает exec().

fcntl(fd, F_SETFD, 1);

11.5.3. Дублирование файловых дескрипторов

Иногда процессам требуется создать новый файловый дескриптор, который ссылается на ранее открытый файл. Командные оболочки используют эту функциональность для перенаправления стандартного ввода, вывода и потока ошибок по запросу пользователя. Если процессу не важно, какой файловый дескриптор будет использован для новой ссылки, он должен использовать dup() .

#include <unistd.h>

int dup(int oldfd);

dup() возвращает файловый дескриптор, который ссылается на тот же inode, что и oldfd, или -1 в случае ошибки, oldfd остается корректным дескриптором, по-прежнему ссылающимся на исходный файл. Новый файловый дескриптор — это всегда наименьший доступный файловый дескриптор. Если процессу нужно получить новый файловый дескриптор с определенным значением (например, 0, чтобы перенаправить стандартный ввод), то он должен использовать dup2().

#include <unistd.h>

int dup2(int oldfd, int newfd);

Если newfd ссылается на уже открытый дескриптор, то он закрывается. Если вызов завершен успешно, он возвращает новый файловый дескриптор и newfd ссылается на тот же файл, что oldfd. Системный вызов fcntl() представляет почти ту же функциональность командой F_DUPFD. Первый аргумент — fd — это уже открытый файловый дескриптор. Новый файловый дескриптор — это первый доступный дескриптор, равный или больший, чем значение последнего аргумента fcntl(). (В этом состоит отличие от работы dup2().) Вы можете реализовать dup2() через fcntl() следующим образом.

int dup2(int oldfd, int newfd) {

 close(newfd); /* ensure new fd is available */

 return fcntl(oldfd, F_DUPFD, newfd);

}

Создание двух файловых дескрипторов, ссылающихся на один и тот же файл — это не то же самое, что открытие файла дважды. Почти все атрибуты дублированных дескрипторов разделяются: они разделяют текущую позицию, режим доступа и блокировки. (Все это записывается в файловой структуре[50], которая создается при каждом открытии файла. Файловый дескриптор ссылается на файловую структуру, и дескриптор, возвращенный dup() , ссылается на одну и ту же структуру.) Единственный атрибут, который может независимо управляться в этих двух дескрипторах — это состояние 'закрыть при выполнении'. После того, как процесс вызывает fork(), то файлы, открытые в родительском процессе, наследуются дочерним, и эти пары файловых дескрипторов (один в родительском процессе, другой — в дочернем) ведут себя так, будто файловые дескрипторы были дублированы с текущей позицией и другими разделенными атрибутами[51].

11.6. Создание неименованных каналов

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

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ОБРАНЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату