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