aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fcntl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fcntl.c')
-rw-r--r--lib/fcntl.c380
1 files changed, 203 insertions, 177 deletions
diff --git a/lib/fcntl.c b/lib/fcntl.c
index 8e976173c0b..74e0f5d3910 100644
--- a/lib/fcntl.c
+++ b/lib/fcntl.c
@@ -27,10 +27,10 @@
27#include <stdarg.h> 27#include <stdarg.h>
28#include <unistd.h> 28#include <unistd.h>
29 29
30#if !HAVE_FCNTL 30#ifdef __KLIBC__
31# define rpl_fcntl fcntl 31# define INCL_DOS
32# include <os2.h>
32#endif 33#endif
33#undef fcntl
34 34
35#if defined _WIN32 && ! defined __CYGWIN__ 35#if defined _WIN32 && ! defined __CYGWIN__
36/* Get declarations of the native Windows API functions. */ 36/* Get declarations of the native Windows API functions. */
@@ -166,93 +166,18 @@ dupfd (int oldfd, int newfd, int flags)
166} 166}
167#endif /* W32 */ 167#endif /* W32 */
168 168
169/* Forward declarations, because we '#undef fcntl' in the middle of this
170 compilation unit. */
171/* Our implementation of fcntl (fd, F_DUPFD, target). */
172static int rpl_fcntl_DUPFD (int fd, int target);
173/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */
174static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target);
169#ifdef __KLIBC__ 175#ifdef __KLIBC__
170 176/* Adds support for fcntl on directories. */
171# define INCL_DOS 177static int klibc_fcntl (int fd, int action, /* arg */...);
172# include <os2.h>
173
174static int
175klibc_fcntl (int fd, int action, /* arg */...)
176{
177 va_list arg_ptr;
178 int arg;
179 struct stat sbuf;
180 int result = -1;
181
182 va_start (arg_ptr, action);
183 arg = va_arg (arg_ptr, int);
184 result = fcntl (fd, action, arg);
185 /* EPERM for F_DUPFD, ENOTSUP for others */
186 if (result == -1 && (errno == EPERM || errno == ENOTSUP)
187 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
188 {
189 ULONG ulMode;
190
191 switch (action)
192 {
193 case F_DUPFD:
194 /* Find available fd */
195 while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
196 arg++;
197
198 result = dup2 (fd, arg);
199 break;
200
201 /* Using underlying APIs is right ? */
202 case F_GETFD:
203 if (DosQueryFHState (fd, &ulMode))
204 break;
205
206 result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
207 break;
208
209 case F_SETFD:
210 if (arg & ~FD_CLOEXEC)
211 break;
212
213 if (DosQueryFHState (fd, &ulMode))
214 break;
215
216 if (arg & FD_CLOEXEC)
217 ulMode |= OPEN_FLAGS_NOINHERIT;
218 else
219 ulMode &= ~OPEN_FLAGS_NOINHERIT;
220
221 /* Filter supported flags. */
222 ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
223 | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
224
225 if (DosSetFHState (fd, ulMode))
226 break;
227
228 result = 0;
229 break;
230
231 case F_GETFL:
232 result = 0;
233 break;
234
235 case F_SETFL:
236 if (arg != 0)
237 break;
238
239 result = 0;
240 break;
241
242 default :
243 errno = EINVAL;
244 break;
245 }
246 }
247
248 va_end (arg_ptr);
249
250 return result;
251}
252
253# define fcntl klibc_fcntl
254#endif 178#endif
255 179
180
256/* Perform the specified ACTION on the file descriptor FD, possibly 181/* Perform the specified ACTION on the file descriptor FD, possibly
257 using the argument ARG further described below. This replacement 182 using the argument ARG further described below. This replacement
258 handles the following actions, and forwards all others on to the 183 handles the following actions, and forwards all others on to the
@@ -273,112 +198,30 @@ klibc_fcntl (int fd, int action, /* arg */...)
273 return -1 and set errno. */ 198 return -1 and set errno. */
274 199
275int 200int
276rpl_fcntl (int fd, int action, /* arg */...) 201fcntl (int fd, int action, /* arg */...)
202#undef fcntl
203#ifdef __KLIBC__
204# define fcntl klibc_fcntl
205#endif
277{ 206{
278 va_list arg; 207 va_list arg;
279 int result = -1; 208 int result = -1;
280 va_start (arg, action); 209 va_start (arg, action);
281 switch (action) 210 switch (action)
282 { 211 {
283
284#if !HAVE_FCNTL
285 case F_DUPFD: 212 case F_DUPFD:
286 { 213 {
287 int target = va_arg (arg, int); 214 int target = va_arg (arg, int);
288 result = dupfd (fd, target, 0); 215 result = rpl_fcntl_DUPFD (fd, target);
289 break; 216 break;
290 } 217 }
291#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
292 case F_DUPFD:
293 {
294 int target = va_arg (arg, int);
295 /* Detect invalid target; needed for cygwin 1.5.x. */
296 if (target < 0 || getdtablesize () <= target)
297 errno = EINVAL;
298 else
299 {
300 /* Haiku alpha 2 loses fd flags on original. */
301 int flags = fcntl (fd, F_GETFD);
302 if (flags < 0)
303 {
304 result = -1;
305 break;
306 }
307 result = fcntl (fd, action, target);
308 if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
309 {
310 int saved_errno = errno;
311 close (result);
312 result = -1;
313 errno = saved_errno;
314 }
315# if REPLACE_FCHDIR
316 if (0 <= result)
317 result = _gl_register_dup (fd, result);
318# endif
319 }
320 break;
321 } /* F_DUPFD */
322#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
323 218
324 case F_DUPFD_CLOEXEC: 219 case F_DUPFD_CLOEXEC:
325 { 220 {
326 int target = va_arg (arg, int); 221 int target = va_arg (arg, int);
327 222 result = rpl_fcntl_DUPFD_CLOEXEC (fd, target);
328#if !HAVE_FCNTL
329 result = dupfd (fd, target, O_CLOEXEC);
330 break; 223 break;
331#else /* HAVE_FCNTL */ 224 }
332# if defined __HAIKU__
333 /* On Haiku, the system fcntl (fd, F_DUPFD_CLOEXEC, target) sets
334 the FD_CLOEXEC flag on fd, not on target. Therefore avoid the
335 system fcntl in this case. */
336# define have_dupfd_cloexec -1
337# else
338 /* Try the system call first, if the headers claim it exists
339 (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
340 may be running with a glibc that has the macro but with an
341 older kernel that does not support it. Cache the
342 information on whether the system call really works, but
343 avoid caching failure if the corresponding F_DUPFD fails
344 for any reason. 0 = unknown, 1 = yes, -1 = no. */
345 static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
346 if (0 <= have_dupfd_cloexec)
347 {
348 result = fcntl (fd, action, target);
349 if (0 <= result || errno != EINVAL)
350 {
351 have_dupfd_cloexec = 1;
352# if REPLACE_FCHDIR
353 if (0 <= result)
354 result = _gl_register_dup (fd, result);
355# endif
356 }
357 else
358 {
359 result = rpl_fcntl (fd, F_DUPFD, target);
360 if (result < 0)
361 break;
362 have_dupfd_cloexec = -1;
363 }
364 }
365 else
366# endif
367 result = rpl_fcntl (fd, F_DUPFD, target);
368 if (0 <= result && have_dupfd_cloexec == -1)
369 {
370 int flags = fcntl (result, F_GETFD);
371 if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
372 {
373 int saved_errno = errno;
374 close (result);
375 errno = saved_errno;
376 result = -1;
377 }
378 }
379 break;
380#endif /* HAVE_FCNTL */
381 } /* F_DUPFD_CLOEXEC */
382 225
383#if !HAVE_FCNTL 226#if !HAVE_FCNTL
384 case F_GETFD: 227 case F_GETFD:
@@ -598,3 +441,186 @@ rpl_fcntl (int fd, int action, /* arg */...)
598 va_end (arg); 441 va_end (arg);
599 return result; 442 return result;
600} 443}
444
445static int
446rpl_fcntl_DUPFD (int fd, int target)
447{
448 int result;
449#if !HAVE_FCNTL
450 result = dupfd (fd, target, 0);
451#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
452 /* Detect invalid target; needed for cygwin 1.5.x. */
453 if (target < 0 || getdtablesize () <= target)
454 {
455 result = -1;
456 errno = EINVAL;
457 }
458 else
459 {
460 /* Haiku alpha 2 loses fd flags on original. */
461 int flags = fcntl (fd, F_GETFD);
462 if (flags < 0)
463 result = -1;
464 else
465 {
466 result = fcntl (fd, F_DUPFD, target);
467 if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
468 {
469 int saved_errno = errno;
470 close (result);
471 result = -1;
472 errno = saved_errno;
473 }
474# if REPLACE_FCHDIR
475 if (0 <= result)
476 result = _gl_register_dup (fd, result);
477# endif
478 }
479 }
480#else
481 result = fcntl (fd, F_DUPFD, target);
482#endif
483 return result;
484}
485
486static int
487rpl_fcntl_DUPFD_CLOEXEC (int fd, int target)
488{
489 int result;
490#if !HAVE_FCNTL
491 result = dupfd (fd, target, O_CLOEXEC);
492#else /* HAVE_FCNTL */
493# if defined __HAIKU__
494 /* On Haiku, the system fcntl (fd, F_DUPFD_CLOEXEC, target) sets
495 the FD_CLOEXEC flag on fd, not on target. Therefore avoid the
496 system fcntl in this case. */
497# define have_dupfd_cloexec -1
498# else
499 /* Try the system call first, if the headers claim it exists
500 (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
501 may be running with a glibc that has the macro but with an
502 older kernel that does not support it. Cache the
503 information on whether the system call really works, but
504 avoid caching failure if the corresponding F_DUPFD fails
505 for any reason. 0 = unknown, 1 = yes, -1 = no. */
506 static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
507 if (0 <= have_dupfd_cloexec)
508 {
509 result = fcntl (fd, F_DUPFD_CLOEXEC, target);
510 if (0 <= result || errno != EINVAL)
511 {
512 have_dupfd_cloexec = 1;
513# if REPLACE_FCHDIR
514 if (0 <= result)
515 result = _gl_register_dup (fd, result);
516# endif
517 }
518 else
519 {
520 result = rpl_fcntl_DUPFD (fd, target);
521 if (result >= 0)
522 have_dupfd_cloexec = -1;
523 }
524 }
525 else
526# endif
527 result = rpl_fcntl_DUPFD (fd, target);
528 if (0 <= result && have_dupfd_cloexec == -1)
529 {
530 int flags = fcntl (result, F_GETFD);
531 if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
532 {
533 int saved_errno = errno;
534 close (result);
535 errno = saved_errno;
536 result = -1;
537 }
538 }
539#endif /* HAVE_FCNTL */
540 return result;
541}
542
543#undef fcntl
544
545#ifdef __KLIBC__
546
547static int
548klibc_fcntl (int fd, int action, /* arg */...);
549{
550 va_list arg_ptr;
551 int arg;
552 struct stat sbuf;
553 int result;
554
555 va_start (arg_ptr, action);
556 arg = va_arg (arg_ptr, int);
557 result = fcntl (fd, action, arg);
558 /* EPERM for F_DUPFD, ENOTSUP for others */
559 if (result == -1 && (errno == EPERM || errno == ENOTSUP)
560 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
561 {
562 ULONG ulMode;
563
564 switch (action)
565 {
566 case F_DUPFD:
567 /* Find available fd */
568 while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
569 arg++;
570
571 result = dup2 (fd, arg);
572 break;
573
574 /* Using underlying APIs is right ? */
575 case F_GETFD:
576 if (DosQueryFHState (fd, &ulMode))
577 break;
578
579 result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
580 break;
581
582 case F_SETFD:
583 if (arg & ~FD_CLOEXEC)
584 break;
585
586 if (DosQueryFHState (fd, &ulMode))
587 break;
588
589 if (arg & FD_CLOEXEC)
590 ulMode |= OPEN_FLAGS_NOINHERIT;
591 else
592 ulMode &= ~OPEN_FLAGS_NOINHERIT;
593
594 /* Filter supported flags. */
595 ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
596 | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
597
598 if (DosSetFHState (fd, ulMode))
599 break;
600
601 result = 0;
602 break;
603
604 case F_GETFL:
605 result = 0;
606 break;
607
608 case F_SETFL:
609 if (arg != 0)
610 break;
611
612 result = 0;
613 break;
614
615 default:
616 errno = EINVAL;
617 break;
618 }
619 }
620
621 va_end (arg_ptr);
622
623 return result;
624}
625
626#endif