diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | include/fcntl.h | 4 | ||||
-rw-r--r-- | io/Makefile | 2 | ||||
-rw-r--r-- | io/have_o_cloexec.c | 24 | ||||
-rw-r--r-- | login/utmp_file.c | 8 | ||||
-rw-r--r-- | sysdeps/unix/opendir.c | 32 |
6 files changed, 71 insertions, 8 deletions
@@ -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 |