This commit introduces a new `close_all_fds` function in s-s-d to close all file
descriptors prior to starting a new process. The function leverages the
`close_range` system call if it is supported (available in glibc >= 2.34 and
kernel >= 5.9). If `close_range` is not available, the function falls back to
iterating over each file descriptor individually.

These changes address the issue where s-s-d could freeze when the system has a
relatively high `max_fds` setting.
---
this change might be useful for systems with a high `max_fds` setting, i was
found this problem while trying to run s-s-d in docker container since it have
default max_fds set to 1073741816 and it will take a long time to close all fds

maybe this patch should be backported to previous version of s-s-d?

 configure.ac              |  1 +
 utils/start-stop-daemon.c | 25 ++++++++++++++++++-------
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/configure.ac b/configure.ac
index 3f1a86362..faed01518 100644
--- a/configure.ac
+++ b/configure.ac
@@ -213,6 +213,7 @@ AC_CHECK_FUNCS([\
 AC_CHECK_FUNCS([\
   setsid \
   getdtablesize \
+  close_range \
   getprocs64 \
   getprogname \
   getexecname \
diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index 8899f0c03..029733b0e 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -496,14 +496,26 @@ parse_unsigned(const char *string, int base, int *value_r)
        return 0;
 }
 
-static long
-get_open_fd_max(void)
+static void
+close_all_fds(void)
 {
+       long max_fd;
+       int close_range_ret = ENOSYS;
+
 #ifdef HAVE_GETDTABLESIZE
-       return getdtablesize();
+       max_fd = getdtablesize();
 #else
-       return sysconf(_SC_OPEN_MAX);
+       max_fd = sysconf(_SC_OPEN_MAX);
 #endif
+
+#ifdef HAVE_CLOSE_RANGE
+       close_range_ret = close_range(3, max_fd, 0);
+#endif
+       if (close_range_ret == ENOSYS) {
+               long fd;
+               for (fd = max_fd - 1; fd >= 3; fd--)
+                       close(fd);
+       }
 }
 
 #ifndef HAVE_SETSID
@@ -2664,9 +2676,8 @@ do_start(int argc, char **argv)
 
                dup2(devnull_fd, 0); /* stdin */
 
-                /* Now close all extra fds. */
-               for (i = get_open_fd_max() - 1; i >= 3; --i)
-                       close(i);
+               /* Now close all extra fds. */
+               close_all_fds();
        }
        execv(startas, argv);
        fatale("unable to start %s", startas);
-- 
2.46.0

Reply via email to