diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2017-08-09T14·22+0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2017-08-09T14·22+0200 |
commit | af765a8eab288eb638100e027b97a1d15e4e3026 (patch) | |
tree | 0ab17da6aae1af4c83efef428deae6d0b534aa93 | |
parent | c6184dec6c208d39a329586d0503b7a51bc2ded1 (diff) |
Use /proc/self/fd to efficiently close all FDs on Linux
Issue #1506.
-rw-r--r-- | src/libstore/build.cc | 2 | ||||
-rw-r--r-- | src/libutil/util.cc | 18 | ||||
-rw-r--r-- | src/libutil/util.hh | 4 |
3 files changed, 19 insertions, 5 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index db5f606fa883..9250a9b1778f 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2556,7 +2556,7 @@ void DerivationGoal::runChild() throw SysError(format("changing into '%1%'") % tmpDir); /* Close all other file descriptors. */ - closeMostFDs(set<int>()); + closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}); #if __linux__ /* Change the personality to 32-bit if we're doing an diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 27f4fea187d2..55d3e1d16f6c 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -310,6 +310,7 @@ string readLine(int fd) while (1) { checkInterrupt(); char ch; + // FIXME: inefficient ssize_t rd = read(fd, &ch, 1); if (rd == -1) { if (errno != EINTR) @@ -962,11 +963,24 @@ string runProgram(Path program, bool searchPath, const Strings & args, void closeMostFDs(const set<int> & exceptions) { +#if __linux__ + try { + for (auto & s : readDirectory("/proc/self/fd")) { + auto fd = std::stoi(s.name); + if (!exceptions.count(fd)) { + debug("closing leaked FD %d", fd); + close(fd); + } + } + return; + } catch (SysError &) { + } +#endif + int maxFD = 0; maxFD = sysconf(_SC_OPEN_MAX); for (int fd = 0; fd < maxFD; ++fd) - if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO - && exceptions.find(fd) == exceptions.end()) + if (!exceptions.count(fd)) close(fd); /* ignore result */ } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 7ea32e8d9f14..f37f2c5d1be5 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -261,8 +261,8 @@ public: list of strings. */ std::vector<char *> stringsToCharPtrs(const Strings & ss); -/* Close all file descriptors except stdin, stdout, stderr, and those - listed in the given set. Good practice in child processes. */ +/* Close all file descriptors except those listed in the given set. + Good practice in child processes. */ void closeMostFDs(const set<int> & exceptions); /* Set the close-on-exec flag for the given file descriptor. */ |