| DUP(2) | Руководство программиста Linux | 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() выполняет ту же задачу, что и dup(), но вместо использования самого маленького неиспользуемого номера файлового дескриптора, он использует номер файлового дескриптора, указанного в newfd. Если файловый дескриптор newfd уже открыт, то он закрывается перед повторным использованием.
Шаги по закрытию и повторному использованию файлового дескриптора newfd выполняются атомарно. Это важно, так как попытка реализовать подобное с помощью close(2) и dup() привело бы к состязательности, в силу чего newfd мог быть задействован повторно между этими двумя шагами. Такое повторное использование может произойти, из-за прерывания основной программы обработчиком сигналов, который выделяет файловый дескриптор, или из-за параллельной нити, выделяющей файловый дескриптор.
Также заметим следующее:
dup3() похож на dup2(). Отличия заключаются в следующем:
В случае успеха данные системные вызовы возвращают новый файловый дескриптор или -1, если произошла ошибка (в этом случае errno устанавливается должным образом).
Вызов 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) {
            /* обработка ошибок закрытия */
        }
    }
| 2017-09-15 | Linux |