xref: /dflybsd-src/contrib/grep/lib/fcntl.c (revision 91b9ed38d3db6a8a8ac5b66da1d43e6e331e259a)
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