mirror of
https://github.com/boostorg/process.git
synced 2026-01-19 04:22:15 +00:00
prototype for limit_fd
This commit is contained in:
@@ -16,13 +16,16 @@
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context
|
||||
::boost::process::detail::posix::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
@@ -33,6 +36,7 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
@@ -76,9 +80,19 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
if (pipe)
|
||||
return {STDIN_FILENO, pipe->native_source(), pipe->native_sink()};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {STDIN_FILENO, STDIN_FILENO, STDIN_FILENO};
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <array>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -45,12 +47,24 @@ inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::in
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context
|
||||
::boost::process::detail::posix::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
if (pipe)
|
||||
return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {pp1, pp2, pp1, pp2};
|
||||
}
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct close_in : handler_base_ext
|
||||
struct close_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
@@ -23,6 +24,9 @@ struct close_in : handler_base_ext
|
||||
if (::close(STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return STDIN_FILENO;}
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -20,6 +21,8 @@ struct close_out : handler_base_ext
|
||||
{
|
||||
template <class Executor>
|
||||
inline void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1};}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct close_fd_ : handler_base_ext
|
||||
struct close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
close_fd_(int fd) : fd_(fd) {}
|
||||
|
||||
@@ -27,12 +29,15 @@ struct close_fd_ : handler_base_ext
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return fd_;}
|
||||
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
struct close_fds_ : handler_base_ext
|
||||
struct close_fds_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
public:
|
||||
close_fds_(const Range &fds) : fds_(fds) {}
|
||||
@@ -48,6 +53,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
Range& get_used_handles() {return fds_;}
|
||||
|
||||
private:
|
||||
Range fds_;
|
||||
};
|
||||
@@ -55,7 +62,7 @@ private:
|
||||
|
||||
|
||||
template <class FileDescriptor>
|
||||
struct bind_fd_ : handler_base_ext
|
||||
struct bind_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
public:
|
||||
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
|
||||
@@ -67,6 +74,9 @@ public:
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {id_, fd_};}
|
||||
|
||||
|
||||
private:
|
||||
int id_;
|
||||
FileDescriptor fd_;
|
||||
|
||||
@@ -13,16 +13,22 @@
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct file_in : handler_base_ext
|
||||
struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, handle};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t)) {}
|
||||
file_in(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : handler_base_ext
|
||||
struct file_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
@@ -27,6 +28,13 @@ struct file_out : handler_base_ext
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
|
||||
file_out(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {handle, pp1, pp2};
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#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 {
|
||||
|
||||
@@ -45,7 +47,7 @@ inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
|
||||
res.push_back(conv);
|
||||
}
|
||||
|
||||
::closedir(dir);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -92,13 +94,52 @@ inline bool is_stream_handle(native_handle_type handle)
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
limit_handles_() {}
|
||||
~limit_handles_() {}
|
||||
mutable std::vector<int> used_handles;
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor &) const {}
|
||||
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
|
||||
|
||||
@@ -14,13 +14,21 @@
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct null_in : handler_base_ext
|
||||
struct null_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
file_descriptor source{"/dev/null", file_descriptor::read};
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, source.handle()};
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
|
||||
@@ -13,17 +13,27 @@
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : handler_base_ext
|
||||
struct null_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
file_descriptor sink{"/dev/null", file_descriptor::write};
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {sink.handle(), pp1, pp2};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -13,17 +13,23 @@
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct pipe_in : handler_base_ext
|
||||
struct pipe_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
int source;
|
||||
int sink; //opposite end
|
||||
|
||||
pipe_in(int sink, int source) : source(source), sink(sink) {}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, source, sink};
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
|
||||
|
||||
@@ -14,15 +14,25 @@
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : handler_base_ext
|
||||
struct pipe_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
{
|
||||
int sink;
|
||||
int source; //opposite end
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
return {source, sink, pp1, pp2};
|
||||
}
|
||||
|
||||
pipe_out(int sink, int source) : sink(sink), source(source) {}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -123,6 +123,7 @@ inline bool is_stream_handle(native_handle_type handle)
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
template<typename Executor>
|
||||
|
||||
@@ -79,12 +79,20 @@ using limit_handles_ = ::boost::process::detail::api::limit_handles_;
|
||||
* The limit_handles property sets all properties to be inherited only expcitly. It closes all unused file-descriptors on posix after the fork and
|
||||
* removes the inherit flags on windows.
|
||||
*
|
||||
* \note This is executed after the fork on posix.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* system("gcc", limit_handles);
|
||||
* \endcode
|
||||
*
|
||||
* Since limit also closes the standard handles unless they are explicitly redirected they can be ignored by `limit_handles` in the following way.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* system("gcc", limit_handles.allowStd())
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
constexpr static ::boost::process::detail::api::limit_handles_ limit_handles;
|
||||
const static ::boost::process::detail::api::limit_handles_ limit_handles;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -150,8 +150,8 @@ BOOST_AUTO_TEST_CASE(iterate_handles, *boost::unit_test::timeout(5))
|
||||
bp::extend::on_setup(on_setup_t(res)));
|
||||
|
||||
BOOST_CHECK_EQUAL(ret, 42);
|
||||
BOOST_CHECK_EQUAL(std::count(res.begin(), res.end(), source), 1);
|
||||
BOOST_CHECK_EQUAL(std::count(res.begin(), res.end(), sink ), 1);
|
||||
BOOST_CHECK_GE(std::count(res.begin(), res.end(), source), 1);
|
||||
BOOST_CHECK_GE(std::count(res.begin(), res.end(), sink ), 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(limit_fd, *boost::unit_test::timeout(5))
|
||||
@@ -164,8 +164,10 @@ BOOST_AUTO_TEST_CASE(limit_fd, *boost::unit_test::timeout(5))
|
||||
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stdout), bp::std_err > stderr), EXIT_SUCCESS);
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stderr), bp::std_err > stderr), EXIT_SUCCESS);
|
||||
|
||||
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stdout), bp::std_err > stderr, bp::limit_handles), EXIT_FAILURE);
|
||||
BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv[1], "--has-handle", get_handle(stderr), bp::std_err > stderr, bp::limit_handles), EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
@@ -227,7 +227,11 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
else if (vm.count("has-handle"))
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const auto handle = reinterpret_cast<boost::this_process::native_handle_type>(vm["has-handle"].as<std::uintptr_t>());
|
||||
#else
|
||||
const auto handle = static_cast<boost::this_process::native_handle_type>(vm["has-handle"].as<std::uintptr_t>());
|
||||
#endif
|
||||
auto all_handles = boost::this_process::get_handles();
|
||||
return (std::find(all_handles.begin(), all_handles.end(), handle) != all_handles.end()) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user