about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--include/fcntl.h4
-rw-r--r--io/Makefile2
-rw-r--r--io/have_o_cloexec.c24
-rw-r--r--login/utmp_file.c8
-rw-r--r--sysdeps/unix/opendir.c32
6 files changed, 71 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 169bb7edaa..833ece1969 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2007-08-02  Ulrich Drepper  <drepper@redhat.com>
 
+	* 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.
+
 	* sysdeps/unix/opendir.c (__alloc_dir): Don't initialize ->data.
 	Avoid memset, add explicit initialization.
 	* sysdeps/unix/dirstream.h (struct __dirstream): Move data elemtn
diff --git a/include/fcntl.h b/include/fcntl.h
index 1e919befb6..d5e5ddff02 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -41,4 +41,8 @@ extern void __atfct_seterrno_2 (int errval, int fd1, const char *buf1,
 /* Flag determining whether the *at system calls are available.  */
 extern int __have_atfcts attribute_hidden;
 
+#ifdef O_CLOEXEC
+extern int __have_o_cloexec attribute_hidden;
+#endif
+
 #endif
diff --git a/io/Makefile b/io/Makefile
index da589b118a..1acda4c8b6 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -54,6 +54,8 @@ routines :=								\
 	sendfile sendfile64 \
 	utimensat futimens
 
+aux := have_o_cloexec
+
 # These routines will be omitted from the libc shared object.
 # Instead the static object files will be included in a special archive
 # linked against when the shared library will be used.
diff --git a/io/have_o_cloexec.c b/io/have_o_cloexec.c
new file mode 100644
index 0000000000..a83e8a4487
--- /dev/null
+++ b/io/have_o_cloexec.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <fcntl.h>
+#include <kernel-features.h>
+
+#if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
+int __have_o_cloexec;
+#endif
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 4a9e409454..a1c6a25716 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -157,9 +157,7 @@ setutent_file (void)
 
 #ifndef __ASSUME_O_CLOEXEC
 # ifdef O_CLOEXEC
-      static int have_o_cloexec;
-
-      if (have_o_cloexec <= 0)
+      if (__have_o_cloexec <= 0)
 # endif
 	{
 	  /* We have to make sure the file is `closed on exec'.  */
@@ -167,8 +165,8 @@ setutent_file (void)
 	  if (result >= 0)
 	    {
 # ifdef O_CLOEXEC
-	      if (have_o_cloexec == 0)
-		have_o_cloexec = (result & FD_CLOEXEC) ? 1 : -1;
+	      if (__have_o_cloexec == 0)
+		__have_o_cloexec = (result & FD_CLOEXEC) ? 1 : -1;
 # endif
 
 	      result = fcntl_not_cancel (file_fd, F_SETFD,
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