fcntl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /* Provide file descriptor control.
  2. Copyright (C) 2009-2016 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 <http://www.gnu.org/licenses/>. */
  13. /* Written by Eric Blake <ebb9@byu.net>. */
  14. #include <config.h>
  15. /* Specification. */
  16. #include <fcntl.h>
  17. #include <errno.h>
  18. #include <limits.h>
  19. #include <stdarg.h>
  20. #include <unistd.h>
  21. #if !HAVE_FCNTL
  22. # define rpl_fcntl fcntl
  23. #endif
  24. #undef fcntl
  25. #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  26. /* Get declarations of the native Windows API functions. */
  27. # define WIN32_LEAN_AND_MEAN
  28. # include <windows.h>
  29. /* Get _get_osfhandle. */
  30. # include "msvc-nothrow.h"
  31. /* Upper bound on getdtablesize(). See lib/getdtablesize.c. */
  32. # define OPEN_MAX_MAX 0x10000
  33. /* Duplicate OLDFD into the first available slot of at least NEWFD,
  34. which must be positive, with FLAGS determining whether the duplicate
  35. will be inheritable. */
  36. static int
  37. dupfd (int oldfd, int newfd, int flags)
  38. {
  39. /* Mingw has no way to create an arbitrary fd. Iterate until all
  40. file descriptors less than newfd are filled up. */
  41. HANDLE curr_process = GetCurrentProcess ();
  42. HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
  43. unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
  44. unsigned int fds_to_close_bound = 0;
  45. int result;
  46. BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
  47. int mode;
  48. if (newfd < 0 || getdtablesize () <= newfd)
  49. {
  50. errno = EINVAL;
  51. return -1;
  52. }
  53. if (old_handle == INVALID_HANDLE_VALUE
  54. || (mode = setmode (oldfd, O_BINARY)) == -1)
  55. {
  56. /* oldfd is not open, or is an unassigned standard file
  57. descriptor. */
  58. errno = EBADF;
  59. return -1;
  60. }
  61. setmode (oldfd, mode);
  62. flags |= mode;
  63. for (;;)
  64. {
  65. HANDLE new_handle;
  66. int duplicated_fd;
  67. unsigned int index;
  68. if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
  69. old_handle, /* SourceHandle */
  70. curr_process, /* TargetProcessHandle */
  71. (PHANDLE) &new_handle, /* TargetHandle */
  72. (DWORD) 0, /* DesiredAccess */
  73. inherit, /* InheritHandle */
  74. DUPLICATE_SAME_ACCESS)) /* Options */
  75. {
  76. switch (GetLastError ())
  77. {
  78. case ERROR_TOO_MANY_OPEN_FILES:
  79. errno = EMFILE;
  80. break;
  81. case ERROR_INVALID_HANDLE:
  82. case ERROR_INVALID_TARGET_HANDLE:
  83. case ERROR_DIRECT_ACCESS_HANDLE:
  84. errno = EBADF;
  85. break;
  86. case ERROR_INVALID_PARAMETER:
  87. case ERROR_INVALID_FUNCTION:
  88. case ERROR_INVALID_ACCESS:
  89. errno = EINVAL;
  90. break;
  91. default:
  92. errno = EACCES;
  93. break;
  94. }
  95. result = -1;
  96. break;
  97. }
  98. duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
  99. if (duplicated_fd < 0)
  100. {
  101. CloseHandle (new_handle);
  102. result = -1;
  103. break;
  104. }
  105. if (newfd <= duplicated_fd)
  106. {
  107. result = duplicated_fd;
  108. break;
  109. }
  110. /* Set the bit duplicated_fd in fds_to_close[]. */
  111. index = (unsigned int) duplicated_fd / CHAR_BIT;
  112. if (fds_to_close_bound <= index)
  113. {
  114. if (sizeof fds_to_close <= index)
  115. /* Need to increase OPEN_MAX_MAX. */
  116. abort ();
  117. memset (fds_to_close + fds_to_close_bound, '\0',
  118. index + 1 - fds_to_close_bound);
  119. fds_to_close_bound = index + 1;
  120. }
  121. fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
  122. }
  123. /* Close the previous fds that turned out to be too small. */
  124. {
  125. int saved_errno = errno;
  126. unsigned int duplicated_fd;
  127. for (duplicated_fd = 0;
  128. duplicated_fd < fds_to_close_bound * CHAR_BIT;
  129. duplicated_fd++)
  130. if ((fds_to_close[duplicated_fd / CHAR_BIT]
  131. >> (duplicated_fd % CHAR_BIT))
  132. & 1)
  133. close (duplicated_fd);
  134. errno = saved_errno;
  135. }
  136. # if REPLACE_FCHDIR
  137. if (0 <= result)
  138. result = _gl_register_dup (oldfd, result);
  139. # endif
  140. return result;
  141. }
  142. #endif /* W32 */
  143. #ifdef __KLIBC__
  144. # define INCL_DOS
  145. # error #include <os2.h>
  146. static int
  147. klibc_fcntl (int fd, int action, /* arg */...)
  148. {
  149. va_list arg_ptr;
  150. int arg;
  151. struct stat sbuf;
  152. int result = -1;
  153. va_start (arg_ptr, action);
  154. arg = va_arg (arg_ptr, int);
  155. result = fcntl (fd, action, arg);
  156. /* EPERM for F_DUPFD, ENOTSUP for others */
  157. if (result == -1 && (errno == EPERM || errno == ENOTSUP)
  158. && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
  159. {
  160. ULONG ulMode;
  161. switch (action)
  162. {
  163. case F_DUPFD:
  164. /* Find available fd */
  165. while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
  166. arg++;
  167. result = dup2 (fd, arg);
  168. break;
  169. /* Using underlying APIs is right ? */
  170. case F_GETFD:
  171. if (DosQueryFHState (fd, &ulMode))
  172. break;
  173. result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
  174. break;
  175. case F_SETFD:
  176. if (arg & ~FD_CLOEXEC)
  177. break;
  178. if (DosQueryFHState (fd, &ulMode))
  179. break;
  180. if (arg & FD_CLOEXEC)
  181. ulMode |= OPEN_FLAGS_NOINHERIT;
  182. else
  183. ulMode &= ~OPEN_FLAGS_NOINHERIT;
  184. /* Filter supported flags. */
  185. ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
  186. | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
  187. if (DosSetFHState (fd, ulMode))
  188. break;
  189. result = 0;
  190. break;
  191. case F_GETFL:
  192. result = 0;
  193. break;
  194. case F_SETFL:
  195. if (arg != 0)
  196. break;
  197. result = 0;
  198. break;
  199. default :
  200. errno = EINVAL;
  201. break;
  202. }
  203. }
  204. va_end (arg_ptr);
  205. return result;
  206. }
  207. # define fcntl klibc_fcntl
  208. #endif
  209. /* Perform the specified ACTION on the file descriptor FD, possibly
  210. using the argument ARG further described below. This replacement
  211. handles the following actions, and forwards all others on to the
  212. native fcntl. An unrecognized ACTION returns -1 with errno set to
  213. EINVAL.
  214. F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
  215. If successful, return the duplicate, which will be inheritable;
  216. otherwise return -1 and set errno.
  217. F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
  218. target fd. If successful, return the duplicate, which will not be
  219. inheritable; otherwise return -1 and set errno.
  220. F_GETFD - ARG need not be present. If successful, return a
  221. non-negative value containing the descriptor flags of FD (only
  222. FD_CLOEXEC is portable, but other flags may be present); otherwise
  223. return -1 and set errno. */
  224. int
  225. rpl_fcntl (int fd, int action, /* arg */...)
  226. {
  227. va_list arg;
  228. int result = -1;
  229. va_start (arg, action);
  230. switch (action)
  231. {
  232. #if !HAVE_FCNTL
  233. case F_DUPFD:
  234. {
  235. int target = va_arg (arg, int);
  236. result = dupfd (fd, target, 0);
  237. break;
  238. }
  239. #elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
  240. case F_DUPFD:
  241. {
  242. int target = va_arg (arg, int);
  243. /* Detect invalid target; needed for cygwin 1.5.x. */
  244. if (target < 0 || getdtablesize () <= target)
  245. errno = EINVAL;
  246. else
  247. {
  248. /* Haiku alpha 2 loses fd flags on original. */
  249. int flags = fcntl (fd, F_GETFD);
  250. if (flags < 0)
  251. {
  252. result = -1;
  253. break;
  254. }
  255. result = fcntl (fd, action, target);
  256. if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
  257. {
  258. int saved_errno = errno;
  259. close (result);
  260. result = -1;
  261. errno = saved_errno;
  262. }
  263. # if REPLACE_FCHDIR
  264. if (0 <= result)
  265. result = _gl_register_dup (fd, result);
  266. # endif
  267. }
  268. break;
  269. } /* F_DUPFD */
  270. #endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
  271. case F_DUPFD_CLOEXEC:
  272. {
  273. int target = va_arg (arg, int);
  274. #if !HAVE_FCNTL
  275. result = dupfd (fd, target, O_CLOEXEC);
  276. break;
  277. #else /* HAVE_FCNTL */
  278. /* Try the system call first, if the headers claim it exists
  279. (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
  280. may be running with a glibc that has the macro but with an
  281. older kernel that does not support it. Cache the
  282. information on whether the system call really works, but
  283. avoid caching failure if the corresponding F_DUPFD fails
  284. for any reason. 0 = unknown, 1 = yes, -1 = no. */
  285. static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
  286. if (0 <= have_dupfd_cloexec)
  287. {
  288. result = fcntl (fd, action, target);
  289. if (0 <= result || errno != EINVAL)
  290. {
  291. have_dupfd_cloexec = 1;
  292. # if REPLACE_FCHDIR
  293. if (0 <= result)
  294. result = _gl_register_dup (fd, result);
  295. # endif
  296. }
  297. else
  298. {
  299. result = rpl_fcntl (fd, F_DUPFD, target);
  300. if (result < 0)
  301. break;
  302. have_dupfd_cloexec = -1;
  303. }
  304. }
  305. else
  306. result = rpl_fcntl (fd, F_DUPFD, target);
  307. if (0 <= result && have_dupfd_cloexec == -1)
  308. {
  309. int flags = fcntl (result, F_GETFD);
  310. if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
  311. {
  312. int saved_errno = errno;
  313. close (result);
  314. errno = saved_errno;
  315. result = -1;
  316. }
  317. }
  318. break;
  319. #endif /* HAVE_FCNTL */
  320. } /* F_DUPFD_CLOEXEC */
  321. #if !HAVE_FCNTL
  322. case F_GETFD:
  323. {
  324. # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  325. HANDLE handle = (HANDLE) _get_osfhandle (fd);
  326. DWORD flags;
  327. if (handle == INVALID_HANDLE_VALUE
  328. || GetHandleInformation (handle, &flags) == 0)
  329. errno = EBADF;
  330. else
  331. result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
  332. # else /* !W32 */
  333. /* Use dup2 to reject invalid file descriptors. No way to
  334. access this information, so punt. */
  335. if (0 <= dup2 (fd, fd))
  336. result = 0;
  337. # endif /* !W32 */
  338. break;
  339. } /* F_GETFD */
  340. #endif /* !HAVE_FCNTL */
  341. /* Implementing F_SETFD on mingw is not trivial - there is no
  342. API for changing the O_NOINHERIT bit on an fd, and merely
  343. changing the HANDLE_FLAG_INHERIT bit on the underlying handle
  344. can lead to odd state. It may be possible by duplicating the
  345. handle, using _open_osfhandle with the right flags, then
  346. using dup2 to move the duplicate onto the original, but that
  347. is not supported for now. */
  348. default:
  349. {
  350. #if HAVE_FCNTL
  351. void *p = va_arg (arg, void *);
  352. result = fcntl (fd, action, p);
  353. #else
  354. errno = EINVAL;
  355. #endif
  356. break;
  357. }
  358. }
  359. va_end (arg);
  360. return result;
  361. }