dup2.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* Duplicate an open file descriptor to a specified file descriptor.
  2. Copyright (C) 1999, 2004-2007, 2009-2020 Free Software Foundation, Inc.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program 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 General Public License for more details.
  11. You should have received a copy of the GNU 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. # error #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. }