11.5.3. Дублирование файловых дескрипторов
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].