dup2(2) создать дубликат файлового дескриптора

Other Alias

dup, dup3

ОБЗОР

#include <unistd.h>


int dup(int oldfd);
int dup2(int oldfd, int newfd);

#define _GNU_SOURCE /* Смотрите feature_test_macros(7) */
#include <fcntl.h> /* Определение констант O_* */
#include <unistd.h>

int dup3(int oldfd, int newfd, int flags);

ОПИСАНИЕ

Системный вызов dup() создаёт копию файлового дескриптора oldfd, используя для нового дескриптора самый маленький свободный номер файлового дескриптора.

После успешного выполнения старый и новый файловые дескрипторы являются взаимозаменяемыми. Они указывают на одно и то же открытое файловое описание (смотрите open(2)) и поэтому имеют общее файловое смещение и флаги состояния файла; например, если файловое смещение изменить с помощью lseek(2) через один из файловых дескрипторов, то смещение изменится и для другого.

Эти два файловых дескриптора имеют различные флаги дескриптора файла (флаг close-on-exec). Флаг close-on-exec (FD_CLOEXEC; см. fcntl(2)) у копии дескриптора сбрасывается.

dup2()

Системный вызов dup2() выполняет ту же задачу, что и dup(), но вместо использования самого маленького неиспользуемого номера файлового дескриптора, он использует номер файлового дескриптора, указанного в newfd. Если файловый дескриптор newfd уже открыт, то он закрывается перед повторным использованием.

Шаги по закрытию и повторному использованию файлового дескриптора newfd выполняются атомарно. Это важно, так как попытка реализовать подобное с помощью close(2) и dup() привело бы к состязательности, в силу чего newfd мог быть задействован повторно между этими двумя шагами. Такое повторное использование может произойти, из-за прерывания основной программы обработчиком сигналов, который выделяет файловый дескриптор, или из-за параллельной нити, выделяющей файловый дескриптор.

Также заметим следующее:

*
Если oldfd является некорректным файловым дескриптором, то вызов завершается с ошибкой, а newfd не закрывается.
*
Если oldfd является корректным файловым дескриптором, а номер newfd совпадает с oldfd, то dup2() не делает ничего и возвращает значение newfd.

dup3()

dup3() похож на dup2(). Отличия заключаются в следующем:
*
Вызывающий может принудительно установить флаг close-on-exec flag у нового файлового дескриптора, указав O_CLOEXEC в flags. Зачем это может быть нужно смотрите в open(2).
*
Если oldfd равно newfd, то dup3() выдает ошибку EINVAL.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

В случае успеха данные системные вызовы возвращают новый файловый дескриптор или -1, если произошла ошибка (в этом случае errno устанавливается должным образом).

ОШИБКИ

EBADF
Значение oldfd не является открытым файловым дескриптором.
EBADF
Значение newfd находится вне допустимого диапазона файловых дескрипторов (смотрите описание RLIMIT_NOFILE в getrlimit(2)).
EBUSY
(только в Linux) Может случиться в dup2() или dup3() при возникновении состязательности вызовов open(2) и dup().
EINTR
Вызов dup2() или dup3() был прерван каким-либо сигналом. Смотрите signal(7).
EINVAL
(dup3()) flags содержит некорректное значение.
EINVAL
(dup3()) oldfd было равно newfd.
EMFILE
Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс (смотрите описание RLIMIT_NOFILE в getrlimit(2)).

ВЕРСИИ

Вызов dup3() был добавлен в Linux версии 2.6.27; поддержка в glibc доступна с версии 2.9.

СООТВЕТСТВИЕ СТАНДАРТАМ

dup(), dup2(): POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.

dup3() есть только в Linux.

ЗАМЕЧАНИЯ

Ошибка, которую возвращает dup2(), отличается от той, что возвращает fcntl(…, F_DUPFD, …), когда newfd находится вне допустимых пределов. На некоторых системах dup2() также иногда возвращает EINVAL — как F_DUPFD.

Если был открыт newfd, то любые ошибки, о которых было бы сообщено close(2), теряются. Если это важно, то (если программа однонитевая и не выделяет файловые дескрипторы в обработчиках сигналов) правильней будет не закрывать newfd перед вызовом dup2(), из-за состязательности, описанной выше. Вместо этого можно использовать, например, такой код:

    /* Получить копию «newfd», которую затем можно
       использовать для проверки ошибок close(); ошибка EBADF
       означает, что «newfd» не открыт. */
    tmpfd = dup(newfd);
    if (tmpfd == -1 && errno != EBADF) {
        /* обработка неожидаемой ошибки dup() */
    }
    /* атомарное копирование «oldfd» в «newfd» */
    if (dup2(oldfd, newfd) == -1) {
        /* обработка ошибки dup2() */
    }
    /* теперь проверим ошибки close() у файла, на который изначально
       ссылался «newfd» */
    if (tmpfd != -1) {
        if (close(tmpfd) == -1) {
            /* обработка ошибок закрытия */
        }
    }