From da91bb7df9bc25e3349b9f3172bfa9d9962f293e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 8 Dec 2009 12:10:52 -0700 Subject: [PATCH] fcntl: work around cygwin bug in F_DUPFD fcntl(0,F_DUPFD,10000000) mistakenly failed with EMFILE instead of EINVAL, and fcntl(0,F_DUPFD,-1) mistakenly passed. * m4/fcntl.m4 (gl_REPLACE_FCNTL): New macro. (gl_FUNC_FCNTL): Use it. Test for F_DUPFD bug. * lib/fcntl.c (rpl_fcntl) : Work around it. : Reduce calls to _gl_register_dup. * doc/posix-functions/fcntl.texi (fcntl): Document it. Signed-off-by: Eric Blake --- ChangeLog | 7 +++++++ doc/posix-functions/fcntl.texi | 5 +++++ lib/fcntl.c | 40 +++++++++++++++++++++++++++++++++------- m4/fcntl.m4 | 42 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 82 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 94e82285e..01e54a99c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-12-16 Eric Blake + fcntl: work around cygwin bug in F_DUPFD + * m4/fcntl.m4 (gl_REPLACE_FCNTL): New macro. + (gl_FUNC_FCNTL): Use it. Test for F_DUPFD bug. + * lib/fcntl.c (rpl_fcntl) : Work around it. + : Reduce calls to _gl_register_dup. + * doc/posix-functions/fcntl.texi (fcntl): Document it. + fcntl: support F_DUPFD_CLOEXEC on systems with fcntl * modules/fcntl (Files): List new files. (configure.ac): Run a test. diff --git a/doc/posix-functions/fcntl.texi b/doc/posix-functions/fcntl.texi index 5e1aea501..ce38e429d 100644 --- a/doc/posix-functions/fcntl.texi +++ b/doc/posix-functions/fcntl.texi @@ -15,6 +15,11 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.7.1, mingw, Interix 3.5, BeOS. Note that the gnulib replacement code is functional but not atomic. + +@item +The @code{F_DUPFD} action of this function does not reject +out-of-range targets properly on some platforms: +Cygwin 1.5.x. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/fcntl.c b/lib/fcntl.c index 3c05d31f7..894b478f6 100644 --- a/lib/fcntl.c +++ b/lib/fcntl.c @@ -35,6 +35,10 @@ handles the following actions, and forwards all others on to the native fcntl. + F_DUPFD - duplicate FD, with int ARG being the minimum target fd. + If successful, return the duplicate, which will be inheritable; + otherwise return -1 and set errno. + F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum target fd. If successful, return the duplicate, which will not be inheritable; otherwise return -1 and set errno. */ @@ -47,6 +51,26 @@ rpl_fcntl (int fd, int action, /* arg */...) va_start (arg, action); switch (action) { + +#if FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR + case F_DUPFD: + { + int target = va_arg (arg, int); + /* Detect invalid target; needed for cygwin 1.5.x. */ + if (target < 0 || getdtablesize () <= target) + errno = EINVAL; + else + { + result = fcntl (fd, action, target); +# if REPLACE_FCHDIR + if (0 <= result) + result = _gl_register_dup (fd, result); +# endif + } + break; + } /* F_DUPFD */ +#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */ + case F_DUPFD_CLOEXEC: { int target = va_arg (arg, int); @@ -63,17 +87,23 @@ rpl_fcntl (int fd, int action, /* arg */...) { result = fcntl (fd, action, target); if (0 <= result || errno != EINVAL) - have_dupfd_cloexec = 1; + { + have_dupfd_cloexec = 1; +#if REPLACE_FCHDIR + if (0 <= result) + result = _gl_register_dup (fd, result); +#endif + } else { - result = fcntl (fd, F_DUPFD, target); + result = rpl_fcntl (fd, F_DUPFD, target); if (result < 0) break; have_dupfd_cloexec = -1; } } else - result = fcntl (fd, F_DUPFD, target); + result = rpl_fcntl (fd, F_DUPFD, target); if (0 <= result && have_dupfd_cloexec == -1) { int flags = fcntl (result, F_GETFD); @@ -85,10 +115,6 @@ rpl_fcntl (int fd, int action, /* arg */...) result = -1; } } -#if REPLACE_FCHDIR - if (0 <= result) - result = _gl_register_dup (fd, result); -#endif break; } /* F_DUPFD_CLOEXEC */ diff --git a/m4/fcntl.m4 b/m4/fcntl.m4 index f361b7d57..b2a7e6bc2 100644 --- a/m4/fcntl.m4 +++ b/m4/fcntl.m4 @@ -1,13 +1,12 @@ -# fcntl.m4 serial 1 +# fcntl.m4 serial 2 dnl Copyright (C) 2009 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # For now, this module ensures that fcntl() -# - supports or emulates F_DUPFD_CLOEXEC -# Still to be ported to various platforms: # - supports F_DUPFD correctly +# - supports or emulates F_DUPFD_CLOEXEC # Still to be ported to mingw: # - F_GETFD, F_SETFD, F_DUPFD # - F_DUPFD_CLOEXEC @@ -19,10 +18,33 @@ AC_DEFUN([gl_FUNC_FCNTL], dnl Persuade glibc to expose F_DUPFD_CLOEXEC. AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_REQUIRE([gl_FCNTL_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) AC_CHECK_FUNCS_ONCE([fcntl]) if test $ac_cv_func_fcntl = no; then HAVE_FCNTL=0 else + dnl cygwin 1.5.x F_DUPFD has wrong errno, and allows negative target + AC_CACHE_CHECK([whether fcntl handles F_DUPFD correctly], + [gl_cv_func_fcntl_f_dupfd_works], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include +]], [[return fcntl (0, F_DUPFD, -1) != -1; + ]])], + [gl_cv_func_fcntl_f_dupfd_works=yes], + [gl_cv_func_fcntl_f_dupfd_works=no], + [# Guess that it works on glibc systems + case $host_os in #(( + *-gnu*) gl_cv_func_fcntl_f_dupfd_works="guessing yes";; + *) gl_cv_func_fcntl_f_dupfd_works="guessing no";; + esac])]) + case $gl_cv_func_fcntl_f_dupfd_works in + *yes) ;; + *) gl_REPLACE_FCNTL + AC_DEFINE([FCNTL_DUPFD_BUGGY], [1], [Define this to 1 if F_DUPFD + behavior does not match POSIX]) ;; + esac + + dnl Many systems lack F_DUPFD_CLOEXEC AC_CACHE_CHECK([whether fcntl understands F_DUPFD_CLOEXEC], [gl_cv_func_fcntl_f_dupfd_cloexec], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -42,8 +64,18 @@ choke me [gl_cv_func_fcntl_f_dupfd_cloexec="needs runtime check"])], [gl_cv_func_fcntl_f_dupfd_cloexec=no])]) if test "$gl_cv_func_fcntl_f_dupfd_cloexec" != yes; then - REPLACE_FCNTL=1 - AC_LIBOBJ([fcntl]) + gl_REPLACE_FCNTL + dnl No witness macro needed for this bug. fi fi ]) + +AC_DEFUN([gl_REPLACE_FCNTL], +[ + AC_REQUIRE([gl_FCNTL_H_DEFAULTS]) + AC_CHECK_FUNCS_ONCE([fcntl]) + if test $ac_cv_func_fcntl = yes; then + REPLACE_FCNTL=1 + AC_LIBOBJ([fcntl]) + fi +]) -- 2.11.0