dup2.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /* Duplicate an open file descriptor to a specified file descriptor.
  2. Copyright (C) 1999, 2004-2007, 2009-2023 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. /* written by Paul Eggert */
  14. #include <config.h>
  15. /* Specification. */
  16. #include <unistd.h>
  17. #include <errno.h>
  18. #include <fcntl.h>
  19. #undef dup2
  20. #if defined _WIN32 && ! defined __CYGWIN__
  21. /* Get declarations of the native Windows API functions. */
  22. # define WIN32_LEAN_AND_MEAN
  23. # include <windows.h>
  24. # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  25. # include "msvc-inval.h"
  26. # endif
  27. /* Get _get_osfhandle. */
  28. # if GNULIB_MSVC_NOTHROW
  29. # include "msvc-nothrow.h"
  30. # else
  31. # include <io.h>
  32. # endif
  33. # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  34. static int
  35. dup2_nothrow (int fd, int desired_fd)
  36. {
  37. int result;
  38. TRY_MSVC_INVAL
  39. {
  40. result = _dup2 (fd, desired_fd);
  41. }
  42. CATCH_MSVC_INVAL
  43. {
  44. errno = EBADF;
  45. result = -1;
  46. }
  47. DONE_MSVC_INVAL;
  48. return result;
  49. }
  50. # else
  51. # define dup2_nothrow _dup2
  52. # endif
  53. static int
  54. ms_windows_dup2 (int fd, int desired_fd)
  55. {
  56. int result;
  57. /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open,
  58. dup2 (fd, fd) returns 0, but all further attempts to use fd in
  59. future dup2 calls will hang. */
  60. if (fd == desired_fd)
  61. {
  62. if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
  63. {
  64. errno = EBADF;
  65. return -1;
  66. }
  67. return fd;
  68. }
  69. /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
  70. https://bugs.winehq.org/show_bug.cgi?id=21289 */
  71. if (desired_fd < 0)
  72. {
  73. errno = EBADF;
  74. return -1;
  75. }
  76. result = dup2_nothrow (fd, desired_fd);
  77. if (result == 0)
  78. result = desired_fd;
  79. return result;
  80. }
  81. # define dup2 ms_windows_dup2
  82. #elif defined __KLIBC__
  83. # include <InnoTekLIBC/backend.h>
  84. static int
  85. klibc_dup2dirfd (int fd, int desired_fd)
  86. {
  87. int tempfd;
  88. int dupfd;
  89. tempfd = open ("NUL", O_RDONLY);
  90. if (tempfd == -1)
  91. return -1;
  92. if (tempfd == desired_fd)
  93. {
  94. close (tempfd);
  95. char path[_MAX_PATH];
  96. if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
  97. return -1;
  98. return open(path, O_RDONLY);
  99. }
  100. dupfd = klibc_dup2dirfd (fd, desired_fd);
  101. close (tempfd);
  102. return dupfd;
  103. }
  104. static int
  105. klibc_dup2 (int fd, int desired_fd)
  106. {
  107. int dupfd;
  108. struct stat sbuf;
  109. dupfd = dup2 (fd, desired_fd);
  110. if (dupfd == -1 && errno == ENOTSUP \
  111. && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
  112. {
  113. close (desired_fd);
  114. return klibc_dup2dirfd (fd, desired_fd);
  115. }
  116. return dupfd;
  117. }
  118. # define dup2 klibc_dup2
  119. #endif
  120. int
  121. rpl_dup2 (int fd, int desired_fd)
  122. {
  123. int result;
  124. #ifdef F_GETFL
  125. /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
  126. On Cygwin 1.5.x, dup2 (1, 1) returns 0.
  127. On Cygwin 1.7.17, dup2 (1, -1) dumps core.
  128. On Cygwin 1.7.25, dup2 (1, 256) can dump core.
  129. On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */
  130. # if HAVE_SETDTABLESIZE
  131. setdtablesize (desired_fd + 1);
  132. # endif
  133. if (desired_fd < 0)
  134. fd = desired_fd;
  135. if (fd == desired_fd)
  136. return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
  137. #endif
  138. result = dup2 (fd, desired_fd);
  139. /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */
  140. if (result == -1 && errno == EMFILE)
  141. errno = EBADF;
  142. #if REPLACE_FCHDIR
  143. if (fd != desired_fd && result != -1)
  144. result = _gl_register_dup (fd, result);
  145. #endif
  146. return result;
  147. }