aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--include/unistd.h1
-rw-r--r--io/Makefile4
-rw-r--r--io/Versions3
-rw-r--r--io/closefrom.c34
-rw-r--r--io/tst-closefrom.c152
-rw-r--r--manual/llio.texi10
-rw-r--r--posix/unistd.h6
-rw-r--r--sysdeps/mach/hurd/i386/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/Makefile3
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/alpha/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/arc/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/arm/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/arm/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/closefrom.c35
-rw-r--r--sysdeps/unix/sysv/linux/closefrom_fallback.c97
-rw-r--r--sysdeps/unix/sysv/linux/csky/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/hppa/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/i386/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/ia64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/nios2/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sh/be/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sh/le/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist1
44 files changed, 380 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index be04b217fe..e01a245ac5 100644
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,10 @@ Major new features:
* On Linux, the close_range function has been added. It allows efficiently
closing a range of file descriptors on recent kernels (version 5.9).
+* The function closefrom has been added. It closes all file descriptors
+ greater than given integer. This function is a GNU extension, although it
+ also present in other systems.
+
Deprecated and removed features, and other changes affecting compatibility:
* The function pthread_mutex_consistent_np has been deprecated; programs
diff --git a/include/unistd.h b/include/unistd.h
index 691405a945..114a43128e 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -158,6 +158,7 @@ extern int __brk (void *__addr) attribute_hidden;
extern int __close (int __fd);
libc_hidden_proto (__close)
extern int __libc_close (int __fd);
+extern _Bool __closefrom_fallback (int __lowfd) attribute_hidden;
extern ssize_t __read (int __fd, void *__buf, size_t __nbytes);
libc_hidden_proto (__read)
extern ssize_t __write (int __fd, const void *__buf, size_t __n);
diff --git a/io/Makefile b/io/Makefile
index 1a16990205..ebb7d56d67 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -56,7 +56,8 @@ routines := \
sendfile sendfile64 copy_file_range \
utimensat futimens file_change_detection \
fts64-time64 \
- ftw64-time64
+ ftw64-time64 \
+ closefrom
others := pwd
test-srcs := ftwtest ftwtest-time64
@@ -77,6 +78,7 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
tst-lutimes \
tst-futimens \
tst-utimensat \
+ tst-closefrom \
tests-time64 := \
tst-futimens-time64 \
diff --git a/io/Versions b/io/Versions
index 88caf76bbc..4e19540885 100644
--- a/io/Versions
+++ b/io/Versions
@@ -137,6 +137,9 @@ libc {
stat; stat64; fstat; fstat64; lstat; lstat64; fstatat; fstatat64;
mknod; mknodat;
}
+ GLIBC_2.34 {
+ closefrom;
+ }
GLIBC_PRIVATE {
__libc_fcntl64;
__fcntl_nocancel;
diff --git a/io/closefrom.c b/io/closefrom.c
new file mode 100644
index 0000000000..01660a7531
--- /dev/null
+++ b/io/closefrom.c
@@ -0,0 +1,34 @@
+/* Close a range of file descriptors.
+ Copyright (C) 2021 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, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <not-cancel.h>
+
+void
+__closefrom (int lowfd)
+{
+ int maxfd = __getdtablesize ();
+ if (maxfd == -1)
+ __fortify_fail ("closefrom failed to get the file descriptor table size");
+
+ for (int i = 0; i < maxfd; i++)
+ if (i >= lowfd)
+ __close_nocancel_nostatus (i);
+}
+weak_alias (__closefrom, closefrom)
diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
new file mode 100644
index 0000000000..d4c187073c
--- /dev/null
+++ b/io/tst-closefrom.c
@@ -0,0 +1,152 @@
+/* Smoke test for the closefrom.
+ Copyright (C) 2021 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, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/xunistd.h>
+
+#include <array_length.h>
+
+#define NFDS 100
+
+static int
+open_multiple_temp_files (void)
+{
+ /* Check if the temporary file descriptor has no no gaps. */
+ int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+ for (int i = 1; i <= NFDS; i++)
+ TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i);
+ return lowfd;
+}
+
+static int
+closefrom_test (void)
+{
+ struct support_descriptors *descrs = support_descriptors_list ();
+
+ int lowfd = open_multiple_temp_files ();
+
+ const int maximum_fd = lowfd + NFDS;
+ const int half_fd = lowfd + NFDS / 2;
+ const int gap = maximum_fd / 4;
+
+ /* Close half of the descriptors and check result. */
+ closefrom (half_fd);
+
+ for (int i = half_fd; i <= maximum_fd; i++)
+ {
+ TEST_COMPARE (fcntl (i, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+ for (int i = 0; i < half_fd; i++)
+ TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+ /* Create some gaps, close up to a threshold, and check result. */
+ xclose (lowfd + 35);
+ xclose (lowfd + 38);
+ xclose (lowfd + 42);
+ xclose (lowfd + 46);
+
+ /* Close half of the descriptors and check result. */
+ closefrom (gap);
+ for (int i = gap + 1; i < maximum_fd; i++)
+ {
+ TEST_COMPARE (fcntl (i, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+ for (int i = 0; i < gap; i++)
+ TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+ /* Close the remmaining but the last one. */
+ closefrom (lowfd + 1);
+ for (int i = lowfd + 1; i <= maximum_fd; i++)
+ {
+ TEST_COMPARE (fcntl (i, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+ TEST_VERIFY (fcntl (lowfd, F_GETFL) > -1);
+
+ /* Close the last one. */
+ closefrom (lowfd);
+ TEST_COMPARE (fcntl (lowfd, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+
+ /* Double check by check the /proc. */
+ support_descriptors_check (descrs);
+ support_descriptors_free (descrs);
+
+ return 0;
+}
+
+/* Check if closefrom works even when no new file descriptors can be
+ created. */
+static int
+closefrom_test_file_desc_limit (void)
+{
+ int max_fd = NFDS;
+ {
+ struct rlimit rl;
+ if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+
+ max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
+ rl.rlim_cur = max_fd;
+
+ if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+ }
+
+ /* Exhauste the file descriptor limit. */
+ int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+ for (;;)
+ {
+ int fd = open ("/dev/null", O_RDONLY, 0600);
+ if (fd == -1)
+ {
+ if (errno != EMFILE)
+ FAIL_EXIT1 ("open: %m");
+ break;
+ }
+ TEST_VERIFY_EXIT (fd < max_fd);
+ }
+
+ closefrom (lowfd);
+ for (int i = lowfd; i < NFDS; i++)
+ {
+ TEST_COMPARE (fcntl (i, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ closefrom_test ();
+ closefrom_test_file_desc_limit ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/manual/llio.texi b/manual/llio.texi
index e21a71fdd0..2c59f6badf 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -334,6 +334,16 @@ The kernel does not implement the required functionality.
@end table
@end deftypefun
+@deftypefun void closefrom (int @var{lowfd})
+@standards{GNU, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
+
+The function @code{closefrom} closes all file descriptors larger than or equal
+to @var{lowfd} then @var{lowfd}. This function is similar to calling
+@code{close} for all open file descriptors not less than @var{lowfd}.
+
+Already closed file descriptors are ignored.
+@end deftypefun
@node I/O Primitives
@section Input and Output Primitives
diff --git a/posix/unistd.h b/posix/unistd.h
index 217c6c5363..3dca65732f 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -357,6 +357,12 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
__THROW. */
extern int close (int __fd);
+#ifdef __USE_MISC
+/* Close all open file descriptors greater than or equal to LOWFD.
+ Negative LOWFD is clamped to 0. */
+extern void closefrom (int __lowfd) __THROW;
+#endif
+
/* Read NBYTES into BUF from FD. Return the
number read, -1 for errors or 0 for EOF.
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index fcfe64f26b..475bf2d6e9 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2225,6 +2225,7 @@ GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 _hurd_libc_proc_init F
+GLIBC_2.34 closefrom F
GLIBC_2.34 dladdr F
GLIBC_2.34 dladdr1 F
GLIBC_2.34 dlclose F
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index e308711168..d45a16af8b 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -64,7 +64,8 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
pselect32 \
xstat fxstat lxstat xstat64 fxstat64 lxstat64 \
fxstatat fxstatat64 \
- xmknod xmknodat convert_scm_timestamps
+ xmknod xmknodat convert_scm_timestamps \
+ closefrom_fallback
CFLAGS-gethostid.c = -fexceptions
CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 428b23fc65..5d5dc5ae57 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2408,6 +2408,7 @@ GLIBC_2.34 aio_write F
GLIBC_2.34 aio_write64 F
GLIBC_2.34 call_once F
GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
GLIBC_2.34 cnd_broadcast F
GLIBC_2.34 cnd_destroy F
GLIBC_2.34 cnd_init F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d5c24d09ee..5f863c7d46 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2507,6 +2507,7 @@ GLIBC_2.34 aio_write F
GLIBC_2.34 aio_write64 F
GLIBC_2.34 call_once F
GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
GLIBC_2.34 cnd_broadcast F
GLIBC_2.34 cnd_destroy F
GLIBC_2.34 cnd_init F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 6213e42bba..e9349e550f 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2167,6 +2167,7 @@ GLIBC_2.34 aio_write F
GLIBC_2.34 aio_write64 F
GLIBC_2.34 call_once F
GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
GLIBC_2.34 cnd_broadcast F
GLIBC_2.34 cnd_destroy F
GLIBC_2.34 cnd_init F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 37c395e4cb..cdfa582b30 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -301,6 +301,7 @@ GLIBC_2.34 aio_write F
GLIBC_2.34 aio_write64 F
GLIBC_2.34 call_once F
GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
GLIBC_2.34 cnd_broadcast F
GLIBC_2.34 cnd_destroy F
GLIBC_2.34 cnd_init F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist