|
7 | 7 | #include "base/string.hpp" |
8 | 8 | #include "base/array.hpp" |
9 | 9 | #include "base/threadpool.hpp" |
| 10 | +#include <array> |
| 11 | +#include <boost/filesystem.hpp> |
| 12 | +#include <boost/lexical_cast.hpp> |
10 | 13 | #include <boost/thread/tss.hpp> |
| 14 | +#include <cstddef> |
| 15 | +#include <set> |
11 | 16 | #include <typeinfo> |
12 | 17 | #include <vector> |
13 | 18 |
|
| 19 | +#ifndef _WIN32 |
| 20 | +#include <unistd.h> |
| 21 | +#endif /* _WIN32 */ |
| 22 | + |
14 | 23 | namespace icinga |
15 | 24 | { |
16 | 25 |
|
@@ -80,6 +89,14 @@ class Utility |
80 | 89 | #ifndef _WIN32 |
81 | 90 | static void SetNonBlocking(int fd, bool nb = true); |
82 | 91 | static void SetCloExec(int fd, bool cloexec = true); |
| 92 | + |
| 93 | + template<size_t exceptAmount> |
| 94 | + static inline |
| 95 | + void CloseAllFDs(const std::array<int, exceptAmount>& except); |
| 96 | + |
| 97 | + template<size_t exceptAmount, class OnClose> |
| 98 | + static inline |
| 99 | + void CloseAllFDs(const std::array<int, exceptAmount>& except, OnClose onClose); |
83 | 100 | #endif /* _WIN32 */ |
84 | 101 |
|
85 | 102 | static void SetNonBlockingSocket(SOCKET s, bool nb = true); |
@@ -157,6 +174,72 @@ class Utility |
157 | 174 | static boost::thread_specific_ptr<unsigned int> m_RandSeed; |
158 | 175 | }; |
159 | 176 |
|
| 177 | +#ifndef _WIN32 |
| 178 | +template<size_t exceptAmount> |
| 179 | +inline void Utility::CloseAllFDs(const std::array<int, exceptAmount>& except) |
| 180 | +{ |
| 181 | + CloseAllFDs(except, [](int) {}); |
| 182 | +} |
| 183 | + |
| 184 | +template<size_t exceptAmount, class OnClose> |
| 185 | +inline void Utility::CloseAllFDs(const std::array<int, exceptAmount>& except, OnClose onClose) |
| 186 | +{ |
| 187 | +#if defined(__linux__) || defined(__APPLE__) |
| 188 | + namespace fs = boost::filesystem; |
| 189 | + |
| 190 | + std::set<int> fds; |
| 191 | + |
| 192 | + for (fs::directory_iterator current (fs::path( |
| 193 | +#ifdef __linux__ |
| 194 | + "/proc/self/fd" |
| 195 | +#endif /* __linux__ */ |
| 196 | +#ifdef __APPLE__ |
| 197 | + "/dev/fd" |
| 198 | +#endif /* __APPLE__ */ |
| 199 | + )), end; current != end; ++current) { |
| 200 | + auto entry (current->path().filename()); |
| 201 | + int fd; |
| 202 | + |
| 203 | + try { |
| 204 | + fd = boost::lexical_cast<int>(entry.c_str()); |
| 205 | + } catch (...) { |
| 206 | + continue; |
| 207 | + } |
| 208 | + |
| 209 | + fds.emplace(fd); |
| 210 | + } |
| 211 | + |
| 212 | + for (auto fd : except) { |
| 213 | + fds.erase(fd); |
| 214 | + } |
| 215 | + |
| 216 | + for (auto fd : fds) { |
| 217 | + if (close(fd) >= 0) { |
| 218 | + onClose(fd); |
| 219 | + } |
| 220 | + } |
| 221 | +#else /* __linux__ || __APPLE__ */ |
| 222 | + rlimit rl; |
| 223 | + |
| 224 | + if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) { |
| 225 | + rlim_t maxfds = rl.rlim_max; |
| 226 | + |
| 227 | + if (maxfds == RLIM_INFINITY) { |
| 228 | + maxfds = 65536; |
| 229 | + } |
| 230 | + |
| 231 | + std::set<int> fds (except.begin(), except.end()); |
| 232 | + |
| 233 | + for (int fd = 0; fd < maxfds; ++fd) { |
| 234 | + if (fds.find(fd) == fds.end() && close(fd) >= 0) { |
| 235 | + onClose(fd); |
| 236 | + } |
| 237 | + } |
| 238 | + } |
| 239 | +#endif /* __linux__ || __APPLE__ */ |
| 240 | +} |
| 241 | +#endif /* _WIN32 */ |
| 242 | + |
160 | 243 | } |
161 | 244 |
|
162 | 245 | #endif /* UTILITY_H */ |
0 commit comments