Предположим, что осуществляется следующий вызов:
newfd = dup(1);
Если предположить, что сложилась обычная ситуация, при которой оболочка открыла от имени программы файловые дескрипторы 0, 1 и 2, и не используются никакие другие дескрипторы, dup() откроет дубликат дескриптора 1, используя файловый дескриптор 3.
Если нужно, чтобы дубликатом стал дескриптор 2, можно воспользоваться следующей технологией:
close(2); /* Высвобождение файлового дескриптора 2 */
newfd = dup(1); /* Повторное использование файлового дескриптора 2 */
Этот код работает, только если был открыт дескриптор 0. Чтобы упростить показанный выше код и обеспечить неизменное получение нужного нам файлового дескриптора, можно воспользоваться системным вызовом dup2().
#include
int dup2(int
При успешном завершении возвращает новый файловый дескриптор, а при ошибке выдает –1
Системный вызов dup2() создает дубликат файлового дескриптора, заданного в аргументе oldfd, используя номер дескриптора, предоставленный в аргументе newfd. Если файловый дескриптор, указанный в newfd, уже открыт, dup2() сначала закрывает его. (Любые ошибки, происходящие при этом закрытии, просто игнорируются. Закрытие и повторное использование newfd выполняются атомарно, что исключает возможность повторного применения newfd между двумя шагами обработчика сигнала или параллельного потока, который выделяет файловый дескриптор.)
Предыдущие вызовы close() и dup() можно упростить, сведя их к следующему вызову:
dup2(1, 2);
Успешно завершенный вызов dup2() возвращает номер продублированного дескриптора (то есть значение, переданное в аргументе newfd).
Если аргумент oldfd не является допустимым файловым дескриптором, dup2() дает сбой с указанием на ошибку EBADF, и дескриптор, заданный в newfd, не закрывается. Если аргумент oldfd содержит допустимый файловый дескриптор и в аргументах oldfd и newfd хранится одно и то же значение, то dup2() не совершает никаких действий — дескриптор, указанный в newfd, не закрывается и dup2() возвращает в качестве результата своей работы значение аргумента newfd.
Еще один интерфейс, предоставляющий дополнительную гибкость для дублирования файловых дескрипторов, предусматривает использование операции F_DUPFD системного вызова fcntl():
newfd = fcntl(oldfd, F_DUPFD,
Этот вызов создает дубликат дескриптора, указанного в oldfd, путем использования наименьшего неиспользуемого дескриптора файла, который больше или равен номеру, заданному в startfd. Применяется, когда нужно обеспечить попадание нового дескриптора (newfd) в конкретный диапазон значений. Вызовы dup() и dup2() всегда могут быть записаны как вызовы close() и fcntl(), хотя они лаконичнее. (Следует также заметить, что некоторые коды ошибок в errno, возвращаемые dup2() и fcntl(), отличаются друг от друга — подробности см. на страницах руководств этих вызовов.)
На рис. 5.2 можно увидеть, что продублированные файловые дескрипторы совместно используют одно и то же значение файлового смещения и одни и те же флаги состояния в своих совместно используемых дескрипциях открытых файлов. Но новый файловый дескриптор имеет собственный набор флагов файлового дескриптора, и его флаг закрытия при выполнении — close-on-exec (FD_CLOEXEC) — всегда сброшен. Следующий рассматриваемый интерфейс позволяет получить явный контроль над флагом закрытия при выполнении нового файлового дескриптора.
Системный вызов dup3() выполняет ту же задачу, что и dup2(), но к нему добавляется новый аргумент, flags, который является битовой маской, изменяющей поведение системного вызова.
#define _GNU_SOURCE
#include
int dup3(int
При успешном завершении возвращает новый файловый дескриптор, а при ошибке выдает –1
В настоящее время dup3() поддерживает один флаг — O_CLOEXEC, заставляющий ядро установить флаг закрытия при выполнении (FD_CLOEXEC) для нового файлового дескриптора. Польза от применения этого флага такая же, как от флага O_CLOEXEC системного вызова open(), рассмотренного в разделе 4.3.1.
Системный вызов dup3() появился в Linux 2.6.27 и характерен только для Linux.
Начиная с версии Linux 2.6.24, в этой ОС также поддерживается дополнительная операция системного вызова fcntl(), предназначенная для дублирования файловых дескрипторов: F_DUPFD_CLOEXEC. Этот флаг делает то же самое, что и F_DUPFD, но дополнительно он устанавливает для нового файлового дескриптора флаг закрытия при выполнении (FD_CLOEXEC). Польза от этой операции обусловлена теми же причинами, что и применение флага O_CLOEXEC для системного вызова open(). Операция F_DUPFD_CLOEXEC не определена в SUSv3, но поддерживается в SUSv4.