123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // 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
|