fcntl.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /* Provide file descriptor control.
  2. Copyright (C) 2009-2021 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 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 <stdlib.h>
  21. #include <unistd.h>
  22. #ifdef __KLIBC__
  23. # define INCL_DOS
  24. # include <os2.h>
  25. #endif
  26. #if defined _WIN32 && ! defined __CYGWIN__
  27. /* Get declarations of the native Windows API functions. */
  28. # define WIN32_LEAN_AND_MEAN
  29. # include <windows.h>
  30. /* Get _get_osfhandle. */
  31. # if GNULIB_MSVC_NOTHROW
  32. # include "msvc-nothrow.h"
  33. # else
  34. # include <io.h>
  35. # endif
  36. /* Upper bound on getdtablesize(). See lib/getdtablesize.c. */
  37. # define OPEN_MAX_MAX 0x10000
  38. /* Duplicate OLDFD into the first available slot of at least NEWFD,
  39. which must be positive, with FLAGS determining whether the duplicate
  40. will be inheritable. */
  41. static int
  42. dupfd (int oldfd, int newfd, int flags)
  43. {
  44. /* Mingw has no way to create an arbitrary fd. Iterate until all
  45. file descriptors less than newfd are filled up. */
  46. HANDLE curr_process = GetCurrentProcess ();
  47. HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
  48. unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
  49. unsigned int fds_to_close_bound = 0;
  50. int result;
  51. BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
  52. int mode;
  53. if (newfd < 0 || getdtablesize () <= newfd)
  54. {
  55. errno = EINVAL;
  56. return -1;
  57. }
  58. if (old_handle == INVALID_HANDLE_VALUE
  59. || (mode = _setmode (oldfd, O_BINARY)) == -1)
  60. {
  61. /* oldfd is not open, or is an unassigned standard file
  62. descriptor. */
  63. errno = EBADF;
  64. return -1;
  65. }
  66. _setmode (oldfd, mode);
  67. flags |= mode;
  68. for (;;)
  69. {
  70. HANDLE new_handle;
  71. int duplicated_fd;
  72. unsigned int index;
  73. if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
  74. old_handle, /* SourceHandle */
  75. curr_process, /* TargetProcessHandle */
  76. (PHANDLE) &new_handle, /* TargetHandle */
  77. (DWORD) 0, /* DesiredAccess */
  78. inherit, /* InheritHandle */
  79. DUPLICATE_SAME_ACCESS)) /* Options */
  80. {
  81. switch (GetLastError ())
  82. {
  83. case ERROR_TOO_MANY_OPEN_FILES:
  84. errno = EMFILE;
  85. break;
  86. case ERROR_INVALID_HANDLE:
  87. case ERROR_INVALID_TARGET_HANDLE:
  88. case ERROR_DIRECT_ACCESS_HANDLE:
  89. errno = EBADF;
  90. break;
  91. case ERROR_INVALID_PARAMETER:
  92. case ERROR_INVALID_FUNCTION:
  93. case ERROR_INVALID_ACCESS:
  94. errno = EINVAL;
  95. break;
  96. default:
  97. errno = EACCES;
  98. break;
  99. }
  100. result = -1;
  101. break;
  102. }
  103. duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
  104. if (duplicated_fd < 0)
  105. {
  106. CloseHandle (new_handle);
  107. result = -1;
  108. break;
  109. }
  110. if (newfd <= duplicated_fd)
  111. {
  112. result = duplicated_fd;
  113. break;
  114. }
  115. /* Set the bit duplicated_fd in fds_to_close[]. */
  116. index = (unsigned int) duplicated_fd / CHAR_BIT;
  117. if (fds_to_close_bound <= index)
  118. {
  119. if (sizeof fds_to_close <= index)
  120. /* Need to increase OPEN_MAX_MAX. */
  121. abort ();
  122. memset (fds_to_close + fds_to_close_bound, '\0',
  123. index + 1 - fds_to_close_bound);
  124. fds_to_close_bound = index + 1;
  125. }
  126. fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
  127. }
  128. /* Close the previous fds that turned out to be too small. */
  129. {
  130. int saved_errno = errno;
  131. unsigned int duplicated_fd;
  132. for (duplicated_fd = 0;
  133. duplicated_fd < fds_to_close_bound * CHAR_BIT;
  134. duplicated_fd++)
  135. if ((fds_to_close[duplicated_fd / CHAR_BIT]
  136. >> (duplicated_fd % CHAR_BIT))
  137. & 1)
  138. close (duplicated_fd);
  139. errno = saved_errno;
  140. }
  141. # if REPLACE_FCHDIR
  142. if (0 <= result)
  143. result = _gl_register_dup (oldfd, result);
  144. # endif
  145. return result;
  146. }
  147. #endif /* W32 */
  148. /* Forward declarations, because we '#undef fcntl' in the middle of this
  149. compilation unit. */
  150. /* Our implementation of fcntl (fd, F_DUPFD, target). */
  151. static int rpl_fcntl_DUPFD (int fd, int target);
  152. /* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */
  153. static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target);
  154. #ifdef __KLIBC__
  155. /* Adds support for fcntl on directories. */
  156. static int klibc_fcntl (int fd, int action, /* arg */...);
  157. #endif
  158. /* Perform the specified ACTION on the file descriptor FD, possibly
  159. using the argument ARG further described below. This replacement
  160. handles the following actions, and forwards all others on to the
  161. native fcntl. An unrecognized ACTION returns -1 with errno set to
  162. EINVAL.
  163. F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
  164. If successful, return the duplicate, which will be inheritable;
  165. otherwise return -1 and set errno.
  166. F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
  167. target fd. If successful, return the duplicate, which will not be
  168. inheritable; otherwise return -1 and set errno.
  169. F_GETFD - ARG need not be present. If successful, return a
  170. non-negative value containing the descriptor flags of FD (only
  171. FD_CLOEXEC is portable, but other flags may be present); otherwise
  172. return -1 and set errno. */
  173. int
  174. fcntl (int fd, int action, /* arg */...)
  175. #undef fcntl
  176. #ifdef __KLIBC__
  177. # define fcntl klibc_fcntl
  178. #endif
  179. {
  180. va_list arg;
  181. int result = -1;
  182. va_start (arg, action);
  183. switch (action)
  184. {
  185. case F_DUPFD:
  186. {
  187. int target = va_arg (arg, int);
  188. result = rpl_fcntl_DUPFD (fd, target);
  189. break;
  190. }
  191. case F_DUPFD_CLOEXEC:
  192. {
  193. int target = va_arg (arg, int);
  194. result = rpl_fcntl_DUPFD_CLOEXEC (fd, target);
  195. break;
  196. }
  197. #if !HAVE_FCNTL
  198. case F_GETFD:
  199. {
  200. # if defined _WIN32 && ! defined __CYGWIN__
  201. HANDLE handle = (HANDLE) _get_osfhandle (fd);
  202. DWORD flags;
  203. if (handle == INVALID_HANDLE_VALUE
  204. || GetHandleInformation (handle, &flags) == 0)
  205. errno = EBADF;
  206. else
  207. result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
  208. # else /* !W32 */
  209. /* Use dup2 to reject invalid file descriptors. No way to
  210. access this information, so punt. */
  211. if (0 <= dup2 (fd, fd))
  212. result = 0;
  213. # endif /* !W32 */
  214. break;
  215. } /* F_GETFD */
  216. #endif /* !HAVE_FCNTL */
  217. /* Implementing F_SETFD on mingw is not trivial - there is no
  218. API for changing the O_NOINHERIT bit on an fd, and merely
  219. changing the HANDLE_FLAG_INHERIT bit on the underlying handle
  220. can lead to odd state. It may be possible by duplicating the
  221. handle, using _open_osfhandle with the right flags, then
  222. using dup2 to move the duplicate onto the original, but that
  223. is not supported for now. */
  224. default:
  225. {
  226. #if HAVE_FCNTL
  227. switch (action)
  228. {
  229. #ifdef F_BARRIERFSYNC /* macOS */
  230. case F_BARRIERFSYNC:
  231. #endif
  232. #ifdef F_CHKCLEAN /* macOS */
  233. case F_CHKCLEAN:
  234. #endif
  235. #ifdef F_CLOSEM /* NetBSD, HP-UX */
  236. case F_CLOSEM:
  237. #endif
  238. #ifdef F_FLUSH_DATA /* macOS */
  239. case F_FLUSH_DATA:
  240. #endif
  241. #ifdef F_FREEZE_FS /* macOS */
  242. case F_FREEZE_FS:
  243. #endif
  244. #ifdef F_FULLFSYNC /* macOS */
  245. case F_FULLFSYNC:
  246. #endif
  247. #ifdef F_GETCONFINED /* macOS */
  248. case F_GETCONFINED:
  249. #endif
  250. #ifdef F_GETDEFAULTPROTLEVEL /* macOS */
  251. case F_GETDEFAULTPROTLEVEL:
  252. #endif
  253. #ifdef F_GETFD /* POSIX */
  254. case F_GETFD:
  255. #endif
  256. #ifdef F_GETFL /* POSIX */
  257. case F_GETFL:
  258. #endif
  259. #ifdef F_GETLEASE /* Linux */
  260. case F_GETLEASE:
  261. #endif
  262. #ifdef F_GETNOSIGPIPE /* macOS */
  263. case F_GETNOSIGPIPE:
  264. #endif
  265. #ifdef F_GETOWN /* POSIX */
  266. case F_GETOWN:
  267. #endif
  268. #ifdef F_GETPIPE_SZ /* Linux */
  269. case F_GETPIPE_SZ:
  270. #endif
  271. #ifdef F_GETPROTECTIONCLASS /* macOS */
  272. case F_GETPROTECTIONCLASS:
  273. #endif
  274. #ifdef F_GETPROTECTIONLEVEL /* macOS */
  275. case F_GETPROTECTIONLEVEL:
  276. #endif
  277. #ifdef F_GET_SEALS /* Linux */
  278. case F_GET_SEALS:
  279. #endif
  280. #ifdef F_GETSIG /* Linux */
  281. case F_GETSIG:
  282. #endif
  283. #ifdef F_MAXFD /* NetBSD */
  284. case F_MAXFD:
  285. #endif
  286. #ifdef F_RECYCLE /* macOS */
  287. case F_RECYCLE:
  288. #endif
  289. #ifdef F_SETFIFOENH /* HP-UX */
  290. case F_SETFIFOENH:
  291. #endif
  292. #ifdef F_THAW_FS /* macOS */
  293. case F_THAW_FS:
  294. #endif
  295. /* These actions take no argument. */
  296. result = fcntl (fd, action);
  297. break;
  298. #ifdef F_ADD_SEALS /* Linux */
  299. case F_ADD_SEALS:
  300. #endif
  301. #ifdef F_BADFD /* Solaris */
  302. case F_BADFD:
  303. #endif
  304. #ifdef F_CHECK_OPENEVT /* macOS */
  305. case F_CHECK_OPENEVT:
  306. #endif
  307. #ifdef F_DUP2FD /* FreeBSD, AIX, Solaris */
  308. case F_DUP2FD:
  309. #endif
  310. #ifdef F_DUP2FD_CLOEXEC /* FreeBSD, Solaris */
  311. case F_DUP2FD_CLOEXEC:
  312. #endif
  313. #ifdef F_DUP2FD_CLOFORK /* Solaris */
  314. case F_DUP2FD_CLOFORK:
  315. #endif
  316. #ifdef F_DUPFD /* POSIX */
  317. case F_DUPFD:
  318. #endif
  319. #ifdef F_DUPFD_CLOEXEC /* POSIX */
  320. case F_DUPFD_CLOEXEC:
  321. #endif
  322. #ifdef F_DUPFD_CLOFORK /* Solaris */
  323. case F_DUPFD_CLOFORK:
  324. #endif
  325. #ifdef F_GETXFL /* Solaris */
  326. case F_GETXFL:
  327. #endif
  328. #ifdef F_GLOBAL_NOCACHE /* macOS */
  329. case F_GLOBAL_NOCACHE:
  330. #endif
  331. #ifdef F_MAKECOMPRESSED /* macOS */
  332. case F_MAKECOMPRESSED:
  333. #endif
  334. #ifdef F_MOVEDATAEXTENTS /* macOS */
  335. case F_MOVEDATAEXTENTS:
  336. #endif
  337. #ifdef F_NOCACHE /* macOS */
  338. case F_NOCACHE:
  339. #endif
  340. #ifdef F_NODIRECT /* macOS */
  341. case F_NODIRECT:
  342. #endif
  343. #ifdef F_NOTIFY /* Linux */
  344. case F_NOTIFY:
  345. #endif
  346. #ifdef F_OPLKACK /* IRIX */
  347. case F_OPLKACK:
  348. #endif
  349. #ifdef F_OPLKREG /* IRIX */
  350. case F_OPLKREG:
  351. #endif
  352. #ifdef F_RDAHEAD /* macOS */
  353. case F_RDAHEAD:
  354. #endif
  355. #ifdef F_SETBACKINGSTORE /* macOS */
  356. case F_SETBACKINGSTORE:
  357. #endif
  358. #ifdef F_SETCONFINED /* macOS */
  359. case F_SETCONFINED:
  360. #endif
  361. #ifdef F_SETFD /* POSIX */
  362. case F_SETFD:
  363. #endif
  364. #ifdef F_SETFL /* POSIX */
  365. case F_SETFL:
  366. #endif
  367. #ifdef F_SETLEASE /* Linux */
  368. case F_SETLEASE:
  369. #endif
  370. #ifdef F_SETNOSIGPIPE /* macOS */
  371. case F_SETNOSIGPIPE:
  372. #endif
  373. #ifdef F_SETOWN /* POSIX */
  374. case F_SETOWN:
  375. #endif
  376. #ifdef F_SETPIPE_SZ /* Linux */
  377. case F_SETPIPE_SZ:
  378. #endif
  379. #ifdef F_SETPROTECTIONCLASS /* macOS */
  380. case F_SETPROTECTIONCLASS:
  381. #endif
  382. #ifdef F_SETSIG /* Linux */
  383. case F_SETSIG:
  384. #endif
  385. #ifdef F_SINGLE_WRITER /* macOS */
  386. case F_SINGLE_WRITER:
  387. #endif
  388. /* These actions take an 'int' argument. */
  389. {
  390. int x = va_arg (arg, int);
  391. result = fcntl (fd, action, x);
  392. }
  393. break;
  394. default:
  395. /* Other actions take a pointer argument. */
  396. {
  397. void *p = va_arg (arg, void *);
  398. result = fcntl (fd, action, p);
  399. }
  400. break;
  401. }
  402. #else
  403. errno = EINVAL;
  404. #endif
  405. break;
  406. }
  407. }
  408. va_end (arg);
  409. return result;
  410. }
  411. static int
  412. rpl_fcntl_DUPFD (int fd, int target)
  413. {
  414. int result;
  415. #if !HAVE_FCNTL
  416. result = dupfd (fd, target, 0);
  417. #elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
  418. /* Detect invalid target; needed for cygwin 1.5.x. */
  419. if (target < 0 || getdtablesize () <= target)
  420. {
  421. result = -1;
  422. errno = EINVAL;
  423. }
  424. else
  425. {
  426. /* Haiku alpha 2 loses fd flags on original. */
  427. int flags = fcntl (fd, F_GETFD);
  428. if (flags < 0)
  429. result = -1;
  430. else
  431. {
  432. result = fcntl (fd, F_DUPFD, target);
  433. if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
  434. {
  435. int saved_errno = errno;
  436. close (result);
  437. result = -1;
  438. errno = saved_errno;
  439. }
  440. # if REPLACE_FCHDIR
  441. if (0 <= result)
  442. result = _gl_register_dup (fd, result);
  443. # endif
  444. }
  445. }
  446. #else
  447. result = fcntl (fd, F_DUPFD, target);
  448. #endif
  449. return result;
  450. }
  451. static int
  452. rpl_fcntl_DUPFD_CLOEXEC (int fd, int target)
  453. {
  454. int result;
  455. #if !HAVE_FCNTL
  456. result = dupfd (fd, target, O_CLOEXEC);
  457. #else /* HAVE_FCNTL */
  458. # if defined __NetBSD__ || defined __HAIKU__
  459. /* On NetBSD 9.0, the system fcntl (fd, F_DUPFD_CLOEXEC, target)
  460. has only the same effect as fcntl (fd, F_DUPFD, target). */
  461. /* On Haiku, the system fcntl (fd, F_DUPFD_CLOEXEC, target) sets
  462. the FD_CLOEXEC flag on fd, not on target. Therefore avoid the
  463. system fcntl in this case. */
  464. # define have_dupfd_cloexec -1
  465. # else
  466. /* Try the system call first, if the headers claim it exists
  467. (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
  468. may be running with a glibc that has the macro but with an
  469. older kernel that does not support it. Cache the
  470. information on whether the system call really works, but
  471. avoid caching failure if the corresponding F_DUPFD fails
  472. for any reason. 0 = unknown, 1 = yes, -1 = no. */
  473. static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
  474. if (0 <= have_dupfd_cloexec)
  475. {
  476. result = fcntl (fd, F_DUPFD_CLOEXEC, target);
  477. if (0 <= result || errno != EINVAL)
  478. {
  479. have_dupfd_cloexec = 1;
  480. # if REPLACE_FCHDIR
  481. if (0 <= result)
  482. result = _gl_register_dup (fd, result);
  483. # endif
  484. }
  485. else
  486. {
  487. result = rpl_fcntl_DUPFD (fd, target);
  488. if (result >= 0)
  489. have_dupfd_cloexec = -1;
  490. }
  491. }
  492. else
  493. # endif
  494. result = rpl_fcntl_DUPFD (fd, target);
  495. if (0 <= result && have_dupfd_cloexec == -1)
  496. {
  497. int flags = fcntl (result, F_GETFD);
  498. if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
  499. {
  500. int saved_errno = errno;
  501. close (result);
  502. errno = saved_errno;
  503. result = -1;
  504. }
  505. }
  506. #endif /* HAVE_FCNTL */
  507. return result;
  508. }
  509. #undef fcntl
  510. #ifdef __KLIBC__
  511. static int
  512. klibc_fcntl (int fd, int action, /* arg */...)
  513. {
  514. va_list arg_ptr;
  515. int arg;
  516. struct stat sbuf;
  517. int result;
  518. va_start (arg_ptr, action);
  519. arg = va_arg (arg_ptr, int);
  520. result = fcntl (fd, action, arg);
  521. /* EPERM for F_DUPFD, ENOTSUP for others */
  522. if (result == -1 && (errno == EPERM || errno == ENOTSUP)
  523. && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
  524. {
  525. ULONG ulMode;
  526. switch (action)
  527. {
  528. case F_DUPFD:
  529. /* Find available fd */
  530. while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
  531. arg++;
  532. result = dup2 (fd, arg);
  533. break;
  534. /* Using underlying APIs is right ? */
  535. case F_GETFD:
  536. if (DosQueryFHState (fd, &ulMode))
  537. break;
  538. result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
  539. break;
  540. case F_SETFD:
  541. if (arg & ~FD_CLOEXEC)
  542. break;
  543. if (DosQueryFHState (fd, &ulMode))
  544. break;
  545. if (arg & FD_CLOEXEC)
  546. ulMode |= OPEN_FLAGS_NOINHERIT;
  547. else
  548. ulMode &= ~OPEN_FLAGS_NOINHERIT;
  549. /* Filter supported flags. */
  550. ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
  551. | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
  552. if (DosSetFHState (fd, ulMode))
  553. break;
  554. result = 0;
  555. break;
  556. case F_GETFL:
  557. result = 0;
  558. break;
  559. case F_SETFL:
  560. if (arg != 0)
  561. break;
  562. result = 0;
  563. break;
  564. default:
  565. errno = EINVAL;
  566. break;
  567. }
  568. }
  569. va_end (arg_ptr);
  570. return result;
  571. }
  572. #endif