Blob Blame History Raw
upstream commit a44cece

 ChangeLog    |   12 ++++++++++++
 NEWS         |    5 +++++
 lib/fdleak.c |   32 +++++++++++++++++++++++++++++++-
 3 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9a6d7d4..abe1993 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2010-04-04  James Youngman  <jay@gnu.org>
+
+	Fix Savannah bug #29435: fd_is_cloexec does not work on Fedora
+	buildhosts.
+	Fix open_cloexec on hosts which ignore O_CLOEXEC (i.e. old kernels).
+	* lib/fdleak.c (o_cloexec_works): New function, detects whether
+	the open flag O_CLOEXEC has any effect.
+	(open_cloexec): Call o_cloexec_works, just once, to find out
+	whether O_CLOEXEC is effective.  If not, set the close-on-exec
+	flag on fds by calling set_cloexec_flag.
+	* NEWS: Mention this bugfix.
+
 2010-04-03  James Youngman  <jay@gnu.org>
 
 	Prepare for release of findutils-4.5.7.
diff --git a/NEWS b/NEWS
index f2eef6f..e171b87 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,10 @@
 GNU findutils NEWS - User visible changes.      -*- outline -*- (allout)
 
+** Bug Fixes
+
+#29435: fd_is_cloexec does not work on Fedora buildhosts
+
+
 * Major changes in release 4.5.7, 2010-04-03
 
 ** Performance changes
diff --git a/lib/fdleak.c b/lib/fdleak.c
index 2c362cf..47f9579 100644
--- a/lib/fdleak.c
+++ b/lib/fdleak.c
@@ -303,11 +303,30 @@ find_first_leaked_fd (const int* prev_non_cloexec_fds, size_t n)
   return context.leaked_fd;
 }
 
+/* Determine if O_CLOEXEC actually works (Savannah bug #29435:
+   fd_is_cloexec () does not work on Fedora buildhosts).
+ */
+static bool
+o_cloexec_works (void)
+{
+  bool result = false;
+  int fd = open ("/", O_RDONLY|O_CLOEXEC);
+  if (fd >= 0)
+    {
+      result = fd_is_cloexec (fd);
+      close (fd);
+    }
+  return result;
+}
+
+
 int
 open_cloexec (const char *path, int flags, ...)
 {
   int fd;
   mode_t mode = 0;
+  static bool cloexec_works = false;
+  static bool cloexec_status_known = false;
 
   if (flags & O_CREAT)
     {
@@ -322,8 +341,19 @@ open_cloexec (const char *path, int flags, ...)
       va_end (ap);
     }
 
+  /* Kernels usually ignore open flags they don't recognise, so it
+   * is possible this program was built against a library which
+   * defines O_CLOEXEC, but is running on a kernel that (silently)
+   * does not recognise it.   We figure this out by just trying it,
+   * once.
+   */
+  if (!cloexec_status_known)
+    {
+      cloexec_works = o_cloexec_works ();
+      cloexec_status_known = true;
+    }
   fd = open (path, flags|O_CLOEXEC, mode);
-  if ((fd >= 0) && !O_CLOEXEC)
+  if ((fd >= 0) && !(O_CLOEXEC && cloexec_works))
     {
       set_cloexec_flag (fd, true);
     }