Scroll to navigation

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()

Системный вызов 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 устанавливается должным образом).

ОШИБКИ

Значение oldfd не является открытым файловым дескриптором.
Значение newfd находится вне допустимого диапазона файловых дескрипторов (смотрите описание RLIMIT_NOFILE в getrlimit(2)).
(только в Linux) Может случиться в dup2() или dup3() при возникновении состязательности вызовов open(2) и dup().
Вызов dup2() или dup3() был прерван каким-либо сигналом. Смотрите signal(7).
(dup3()) flags содержит некорректное значение.
(dup3()) oldfd было равно newfd.
Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс (смотрите описание 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) {
/* обработка ошибок закрытия */
} }

СМ. ТАКЖЕ

close(2), fcntl(2), open(2), pidfd_getfd(2)

ЗАМЕЧАНИЯ

Эта страница является частью проекта Linux man-pages версии 5.10. Описание проекта, информацию об ошибках и последнюю версию этой страницы можно найти по адресу https://www.kernel.org/doc/man-pages/.

ПЕРЕВОД

Русский перевод этой страницы руководства был сделан Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.

1 ноября 2020 г. Linux