summaryrefslogtreecommitdiff
path: root/boost/process/detail/posix/handles.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/process/detail/posix/handles.hpp')
-rw-r--r--boost/process/detail/posix/handles.hpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/boost/process/detail/posix/handles.hpp b/boost/process/detail/posix/handles.hpp
new file mode 100644
index 0000000000..1572f05933
--- /dev/null
+++ b/boost/process/detail/posix/handles.hpp
@@ -0,0 +1,146 @@
+// Copyright (c) 2019 Klemens D. Morgenstern
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
+#define BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
+
+#include <vector>
+#include <system_error>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <algorithm>
+#include <boost/process/detail/posix/handler.hpp>
+
+namespace boost { namespace process { namespace detail { namespace posix {
+
+
+using native_handle_type = int;
+
+inline std::vector<native_handle_type> get_handles(std::error_code & ec)
+{
+ std::vector<native_handle_type> res;
+
+ std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
+ if (!dir)
+ {
+ ec = ::boost::process::detail::get_last_error();
+ return {};
+ }
+ else
+ ec.clear();
+
+ auto my_fd = ::dirfd(dir.get());
+
+ struct ::dirent * ent_p;
+
+ while ((ent_p = readdir(dir.get())) != nullptr)
+ {
+ if (ent_p->d_name[0] == '.')
+ continue;
+
+ const auto conv = std::atoi(ent_p->d_name);
+ if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
+ continue;
+
+ if (conv == my_fd)
+ continue;
+
+ res.push_back(conv);
+ }
+ return res;
+}
+
+inline std::vector<native_handle_type> get_handles()
+{
+ std::error_code ec;
+
+ auto res = get_handles(ec);
+ if (ec)
+ boost::process::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
+
+ return res;
+}
+
+
+inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
+{
+ struct ::stat stat_;
+
+ if (::fstat(handle, &stat_) != 0)
+ {
+ ec = ::boost::process::detail::get_last_error();
+ }
+ else
+ ec.clear();
+
+ return S_ISCHR (stat_.st_mode) //This macro returns non-zero if the file is a character special file (a device like a terminal).
+ || S_ISBLK (stat_.st_mode) // This macro returns non-zero if the file is a block special file (a device like a disk).
+ || S_ISREG (stat_.st_mode) // This macro returns non-zero if the file is a regular file.
+ || S_ISFIFO (stat_.st_mode) // This macro returns non-zero if the file is a FIFO special file, or a pipe. See section 15. Pipes and FIFOs.
+ || S_ISSOCK (stat_.st_mode) ;// This macro returns non-zero if the file is a socket. See section 16. Sockets.;
+}
+
+
+inline bool is_stream_handle(native_handle_type handle)
+{
+ std::error_code ec;
+ auto res = is_stream_handle(handle, ec);
+ if (ec)
+ boost::process::detail::throw_error(ec, "fstat() failed");
+
+ return res;
+}
+
+struct limit_handles_ : handler_base_ext
+{
+ limit_handles_() {}
+ ~limit_handles_() {}
+ mutable std::vector<int> used_handles;
+
+ template<typename Executor>
+ void on_setup(Executor & exec) const
+ {
+ used_handles = get_used_handles(exec);
+ }
+
+ template<typename Executor>
+ void on_exec_setup(Executor & exec) const
+ {
+ auto dir = ::opendir("/dev/fd");
+ if (!dir)
+ {
+ exec.set_error(::boost::process::detail::get_last_error(), "opendir(\"/dev/fd\")");
+ return;
+ }
+
+ auto my_fd = ::dirfd(dir);
+ struct ::dirent * ent_p;
+
+ while ((ent_p = readdir(dir)) != nullptr)
+ {
+ if (ent_p->d_name[0] == '.')
+ continue;
+
+ const auto conv = std::atoi(ent_p->d_name);
+
+ if ((conv == my_fd) || (conv == -1))
+ continue;
+
+ if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end())
+ continue;
+
+ if (::close(conv) != 0)
+ {
+ exec.set_error(::boost::process::detail::get_last_error(), "close() failed");
+ return;
+ }
+ }
+ ::closedir(dir);
+ }
+};
+
+}}}}
+
+#endif //PROCESS_HANDLES_HPP