chiark / gitweb /
util: add brute-force fallback for close_all_fds()
authorLennart Poettering <lennart@poettering.net>
Tue, 13 Mar 2012 01:29:27 +0000 (02:29 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 13 Mar 2012 01:29:27 +0000 (02:29 +0100)
If /proc is not available (i.e. in chroot envs) let's fall back to brute
forcing our way through the fd table.

https://bugzilla.redhat.com/show_bug.cgi?id=784921

src/util.c

index 3a855c1be48e5f97e9f8bc6d476cc09a7b5d5aea..73481abee608fa4a56e3c427ce50711d0386cdf1 100644 (file)
@@ -2207,13 +2207,47 @@ int fd_cloexec(int fd, bool cloexec) {
         return 0;
 }
 
+static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
+        unsigned i;
+
+        assert(n_fdset == 0 || fdset);
+
+        for (i = 0; i < n_fdset; i++)
+                if (fdset[i] == fd)
+                        return true;
+
+        return false;
+}
+
 int close_all_fds(const int except[], unsigned n_except) {
         DIR *d;
         struct dirent *de;
         int r = 0;
 
-        if (!(d = opendir("/proc/self/fd")))
-                return -errno;
+        assert(n_except == 0 || except);
+
+        d = opendir("/proc/self/fd");
+        if (!d) {
+                int fd;
+                struct rlimit rl;
+
+                /* When /proc isn't available (for example in chroots)
+                 * the fallback is brute forcing through the fd
+                 * table */
+
+                assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
+                for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
+
+                        if (fd_in_set(fd, except, n_except))
+                                continue;
+
+                        if (close_nointr(fd) < 0)
+                                if (errno != EBADF && r == 0)
+                                        r = -errno;
+                }
+
+                return r;
+        }
 
         while ((de = readdir(d))) {
                 int fd = -1;
@@ -2231,20 +2265,8 @@ int close_all_fds(const int except[], unsigned n_except) {
                 if (fd == dirfd(d))
                         continue;
 
-                if (except) {
-                        bool found;
-                        unsigned i;
-
-                        found = false;
-                        for (i = 0; i < n_except; i++)
-                                if (except[i] == fd) {
-                                        found = true;
-                                        break;
-                                }
-
-                        if (found)
-                                continue;
-                }
+                if (fd_in_set(fd, except, n_except))
+                        continue;
 
                 if (close_nointr(fd) < 0) {
                         /* Valgrind has its own FD and doesn't want to have it closed */