about summary refs log tree commit diff
path: root/sysdeps/unix/opendir.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/opendir.c')
-rw-r--r--sysdeps/unix/opendir.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c
index 36fb6f458d..34f5b719d3 100644
--- a/sysdeps/unix/opendir.c
+++ b/sysdeps/unix/opendir.c
@@ -31,6 +31,7 @@
 
 #include <dirstream.h>
 #include <not-cancel.h>
+#include <kernel-features.h>
 
 
 /* opendir() must not accidentally open something other than a directory.
@@ -110,7 +111,11 @@ __opendir (const char *name)
 	 }
     }
 
-  int fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE);
+  int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE;
+#ifdef O_CLOEXEC
+  flags |= O_CLOEXEC;
+#endif
+  int fd = open_not_cancel_2 (name, flags);
   if (__builtin_expect (fd, 0) < 0)
     return NULL;
 
@@ -138,12 +143,33 @@ __opendir (const char *name)
 weak_alias (__opendir, opendir)
 
 
+#ifdef __ASSUME_O_CLOEXEC
+# define check_have_o_cloexec(fd) 1
+#else
+static int
+check_have_o_cloexec (int fd)
+{
+  if (__have_o_cloexec == 0)
+    __have_o_cloexec = (__fcntl (fd, F_GETFD, 0) & FD_CLOEXEC) == 0 ? -1 : 1;
+  return __have_o_cloexec > 0;
+}
+#endif
+
+
 DIR *
 internal_function
 __alloc_dir (int fd, bool close_fd, const struct stat64 *statp)
 {
-  if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0)
-    goto lose;
+  /* We always have to set the close-on-exit flag if the user provided
+     the file descriptor.  Otherwise only if we have no working
+     O_CLOEXEC support.  */
+#ifdef O_CLOEXEC
+  if (! close_fd || ! check_have_o_cloexec (fd))
+#endif
+    {
+      if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0)
+	goto lose;
+    }
 
   size_t allocation;
 #ifdef _STATBUF_ST_BLKSIZE