DUP(2)

ИМЯ
dup, dup2, 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(): SVr4, 4.3BSD, POSIX.1-2001. 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) {
            /* обработка ошибок закрытия */
        }
    }

СМОТРИТЕ ТАКЖЕ
close(2), fcntl(2), open(2)