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 + + 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 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); }