about summary refs log tree commit diff
path: root/sysdeps/unix/opendir.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-08-03 04:09:03 +0000
committerUlrich Drepper <drepper@redhat.com>2007-08-03 04:09:03 +0000
commitcbf0489bcf3eebeeba595a514461057a4e2f1e8b (patch)
tree5494b98023b95a29643094578424382515a41724 /sysdeps/unix/opendir.c
parentfa39685d5c7df2502213418bead44e9543a9b9ec (diff)
downloadglibc-cbf0489bcf3eebeeba595a514461057a4e2f1e8b.tar.gz
glibc-cbf0489bcf3eebeeba595a514461057a4e2f1e8b.tar.xz
glibc-cbf0489bcf3eebeeba595a514461057a4e2f1e8b.zip
* io/Makefile (aux): Add have_o_cloexec.
	* include/fcntl.h: Declare __have_o_cloexec.
	* io/have_o_cloexec.c: New file.
	* sysdeps/unix/opendir.c (__opendir): Use O_CLOEXEC is available.
	(__alloc_dir): If O_CLOEXEC has been used, don't duplicate the
	fcntl call if not necessary.
	* login/utmp_file.c (setutent_file): Use __have_o_cloexec instead
	of local variable.
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