?????????? ????????? - ??????????????? - /home/agenciai/public_html/cd38d8/process.tar
???????
group.hpp 0000644 00000015150 15125237361 0006420 0 ustar 00 // Copyright (c) 2016 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) /** * \file boost/process/group.hpp * * Defines a group process class. * For additional information see the platform specific implementations: * * - [windows - job object](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161.aspx) * - [posix - process group](http://pubs.opengroup.org/onlinepubs/009695399/functions/setpgid.html) * */ #ifndef BOOST_PROCESS_GROUP_HPP #define BOOST_PROCESS_GROUP_HPP #include <boost/process/detail/config.hpp> #include <boost/process/child.hpp> #include <chrono> #include <memory> #include <boost/none.hpp> #include <atomic> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/group_handle.hpp> #include <boost/process/detail/posix/group_ref.hpp> #include <boost/process/detail/posix/wait_group.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/group_handle.hpp> #include <boost/process/detail/windows/group_ref.hpp> #include <boost/process/detail/windows/wait_group.hpp> #endif namespace boost { namespace process { namespace detail { struct group_builder; } /** * Represents a process group. * * Groups are movable but non-copyable. The destructor * automatically closes handles to the group process. * * The group will have the same interface as std::thread. * * \note If the destructor is called without a previous detach or wait, the group will be terminated. * * \attention If a default-constructed group is used before being used in a process launch, the behaviour is undefined. * * \attention Waiting for groups is currently broken on windows and will most likely result in a dead-lock. */ class group { ::boost::process::detail::api::group_handle _group_handle; bool _attached = true; public: typedef ::boost::process::detail::api::group_handle group_handle; ///Native representation of the handle. typedef group_handle::handle_t native_handle_t; explicit group(group_handle &&ch) : _group_handle(std::move(ch)) {} ///Construct the group from a native_handle explicit group(native_handle_t & handle) : _group_handle(handle) {}; group(const group&) = delete; ///Move constructor group(group && lhs) : _group_handle(std::move(lhs._group_handle)), _attached (lhs._attached) { lhs._attached = false; } ///Default constructor group() = default; group& operator=(const group&) = delete; ///Move assign group& operator=(group && lhs) { _group_handle= std::move(lhs._group_handle); _attached = lhs._attached; return *this; }; ///Detach the group void detach() {_attached = false; } /** Join the child. This just calls wait, but that way the naming is similar to std::thread */ void join() {wait();} /** Check if the child is joinable. */ bool joinable() {return _attached;} /** Destructor * * \note If the destructor is called without a previous detach or wait, the group will be terminated. * */ ~group() { std::error_code ec; if ( _attached && valid()) terminate(ec); } ///Obtain the native handle of the group. native_handle_t native_handle() const { return _group_handle.handle(); } ///Wait for the process group to exit. void wait() { boost::process::detail::api::wait(_group_handle); } ///\overload void wait() void wait(std::error_code & ec) noexcept { boost::process::detail::api::wait(_group_handle, ec); } /** Wait for the process group to exit for period of time. * \return True if all child processes exited while waiting.*/ template< class Rep, class Period > bool wait_for (const std::chrono::duration<Rep, Period>& rel_time) { return boost::process::detail::api::wait_for(_group_handle, rel_time); } /** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */ template< class Rep, class Period > bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept { return boost::process::detail::api::wait_for(_group_handle, rel_time, ec); } /** Wait for the process group to exit until a point in time. * \return True if all child processes exited while waiting.*/ template< class Clock, class Duration > bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) { return boost::process::detail::api::wait_until(_group_handle, timeout_time); } /** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */ template< class Clock, class Duration > bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept { return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec); } ///Check if the group has a valid handle. bool valid() const { return _group_handle.valid(); } ///Convenience to call valid. explicit operator bool() const {return valid();} ///Terminate the process group, i.e. all processes in the group void terminate() { ::boost::process::detail::api::terminate(_group_handle); } ///\overload void terminate() void terminate(std::error_code & ec) noexcept { ::boost::process::detail::api::terminate(_group_handle, ec); } ///Assign a child process to the group void add(const child &c) { _group_handle.add(c.native_handle()); } ///\overload void assign(const child & c) void add(const child &c, std::error_code & ec) noexcept { _group_handle.add(c.native_handle(), ec); } ///Check if the child process is in the group bool has(const child &c) { return _group_handle.has(c.native_handle()); } ///\overload bool has(const child &) bool has(const child &c, std::error_code & ec) noexcept { return _group_handle.has(c.native_handle(), ec); } friend struct detail::group_builder; }; namespace detail { struct group_tag; struct group_builder { group * group_p; void operator()(group & grp) {this->group_p = &grp;}; typedef api::group_ref result_type; api::group_ref get_initializer() {return api::group_ref (group_p->_group_handle);}; }; template<> struct initializer_tag<group> { typedef group_tag type; }; template<> struct initializer_builder<group_tag> { typedef group_builder type; }; } }} #endif search_path.hpp 0000644 00000003357 15125237361 0007553 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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) /** * \file boost/process/search_path.hpp * * Defines a function to search for an executable in path. */ #ifndef BOOST_PROCESS_SEARCH_PATH_HPP #define BOOST_PROCESS_SEARCH_PATH_HPP #include <boost/process/detail/config.hpp> #include <boost/process/environment.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/search_path.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/search_path.hpp> #endif namespace boost { namespace process { /** * Searches for an executable in path. * * filename must be a basename including the file extension. * It must not include any directory separators (like a slash). * On Windows the file extension may be omitted. The function * will then try the various file extensions for executables on * Windows to find filename. * * \param filename The base of the filename to find * * \param path the set of paths to search, defaults to the "PATH" environment variable. * * \returns the absolute path to the executable filename or an * empty string if filename isn't found */ inline boost::filesystem::path search_path(const boost::filesystem::path &filename, const std::vector<boost::filesystem::path> path = ::boost::this_process::path()) { return ::boost::process::detail::api::search_path(filename, path); } }} #endif start_dir.hpp 0000644 00000006571 15125237361 0007266 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_START_IN_DIR_HPP #define BOOST_PROCESS_START_IN_DIR_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler.hpp> #include <boost/process/locale.hpp> #include <boost/process/detail/traits/wchar_t.hpp> #if defined (BOOST_POSIX_API) #include <boost/process/detail/posix/start_dir.hpp> #elif defined (BOOST_WINDOWS_API) #include <boost/process/detail/windows/start_dir.hpp> #endif #include <boost/process/detail/config.hpp> #include <string> #include <boost/filesystem/path.hpp> /** \file boost/process/start_dir.hpp * Header which provides the start_dir property, which allows to set the directory the process shall be started in. \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::start_dir">start_dir</globalname>; } } </programlisting> \endxmlonly */ namespace boost { namespace process { namespace detail { struct start_dir_ { constexpr start_dir_() {}; template<typename Char> api::start_dir_init<Char> operator()(const std::basic_string<Char> & st) const {return {st}; } template<typename Char> api::start_dir_init<Char> operator()(std::basic_string<Char> && s) const {return {std::move(s)}; } template<typename Char> api::start_dir_init<Char> operator()(const Char* s) const {return {s}; } api::start_dir_init<typename boost::filesystem::path::value_type> operator()(const boost::filesystem::path & st) const {return {st.native()}; } template<typename Char> api::start_dir_init<Char> operator= (const std::basic_string<Char> & st) const {return {st}; } template<typename Char> api::start_dir_init<Char> operator= (std::basic_string<Char> && s) const {return {std::move(s)}; } template<typename Char> api::start_dir_init<Char> operator= (const Char* s) const {return {s}; } api::start_dir_init<typename boost::filesystem::path::value_type> operator= (const boost::filesystem::path & st) const {return {st.native()}; } }; template<> struct is_wchar_t<api::start_dir_init<wchar_t>> : std::true_type {}; template<> struct char_converter<char, api::start_dir_init<wchar_t>> { static api::start_dir_init<char> conv(const api::start_dir_init<wchar_t> & in) { return api::start_dir_init<char>{::boost::process::detail::convert(in.str())}; } }; template<> struct char_converter<wchar_t, api::start_dir_init<char>> { static api::start_dir_init<wchar_t> conv(const api::start_dir_init<char> & in) { return api::start_dir_init<wchar_t>{::boost::process::detail::convert(in.str())}; } }; } /** To set the start dir, the `start_dir` property is provided. The valid operations are the following: \code{.cpp} start_dir=path start_dir(path) \endcode It can be used with `std::string`, `std::wstring` and `boost::filesystem::path`. */ constexpr ::boost::process::detail::start_dir_ start_dir; }} #endif env.hpp 0000644 00000030015 15125237361 0006051 0 ustar 00 // Copyright (c) 2016 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_ENV_HPP_ #define BOOST_PROCESS_DETAIL_ENV_HPP_ #include <boost/process/environment.hpp> #include <boost/none.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/env_init.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/env_init.hpp> #endif /** \file boost/process/env.hpp * * This header which provides the `env` property. It allows the modification of the * environment the child process will run in, in a functional style. * * \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>; } } </programlisting> * \endxmlonly * * For additional information see the platform documentations: * * - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx) * - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html) * */ namespace boost { namespace process { namespace detail { template<typename Char> std::size_t make_env_string_size(const std::basic_string<Char> & ch) { return ch.size() + 1; } template<typename Char> std::size_t make_env_string_size(const Char * ch) { std::size_t sz = 0; while (ch[sz] != null_char<Char>()) sz++; sz++; return sz; } template<typename Char, typename Container> inline std::basic_string<Char> make_env_string(const Container & value) { std::size_t sz = 0; for (auto & v : value) sz += make_env_string_size(v); std::basic_string<Char> s; s.reserve(sz); //+1 for ;, end doesn't have one. for (auto & val : value) (s += val) += api::env_seperator<Char>(); s.resize(s.size() -1); //remove last ';' return s; } template<typename Char> struct env_set { using string_type = std::basic_string<Char>; string_type key; string_type value; }; template<typename Char> struct env_append { using string_type = std::basic_string<Char>; string_type key; string_type value; }; template<typename Char> struct env_reset { using string_type = std::basic_string<Char>; string_type key; }; template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {}; template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {}; template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {}; template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {}; template<> struct char_converter<char, env_set<wchar_t>> { static env_set<char> conv(const env_set<wchar_t> & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter<wchar_t, env_set<char>> { static env_set<wchar_t> conv(const env_set<char> & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter<char, env_append<wchar_t>> { static env_append<char> conv(const env_append<wchar_t> & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter<wchar_t, env_append<char>> { static env_append<wchar_t> conv(const env_append<char> & in) { return {::boost::process::detail::convert(in.key), ::boost::process::detail::convert(in.value)}; } }; template<> struct char_converter<char, env_reset<wchar_t>> { static env_reset<char> conv(const env_reset<wchar_t> & in) { return {::boost::process::detail::convert(in.key)}; } }; template<> struct char_converter<wchar_t, env_reset<char>> { static env_reset<wchar_t> conv(const env_reset<char> & in) { return {::boost::process::detail::convert(in.key)}; } }; template<typename Char> struct env_init { basic_environment<Char> env; }; template<> struct char_converter<char, env_init<wchar_t>> { static env_init<char> conv(const env_init<wchar_t> & in) { return {basic_environment<char>(in.env)}; } }; template<> struct char_converter<wchar_t, env_init<char>> { static env_init<wchar_t> conv(const env_init<char> & in) { return {basic_environment<wchar_t>(in.env)}; } }; template<> struct char_converter<char, basic_environment<wchar_t>> { static basic_environment<char> conv(const basic_environment<wchar_t> & in) { return { basic_environment<char>(in) }; } }; template<> struct char_converter<wchar_t, basic_environment<char>> { static basic_environment<wchar_t> conv(const basic_environment<char> & in) { return { basic_environment<wchar_t>(in) }; } }; template<typename Char> struct env_proxy { using string_type = std::basic_string<Char>; string_type key; env_set<Char> operator=(const string_type & value) { return {std::move(key), value}; } env_set<Char> operator=(const std::vector<string_type> & value) { return {std::move(key), make_env_string<Char>(value)}; } env_set<Char> operator=(const std::initializer_list<const Char*> & value) { return {std::move(key), make_env_string<Char>(value)}; } env_append<Char> operator+=(const string_type & value) { return {std::move(key), value}; } env_append<Char> operator+=(const std::vector<string_type> & value) { return {std::move(key), make_env_string<Char>(value)}; } env_append<Char> operator+=(const std::initializer_list<const Char*> & value) { return {std::move(key), make_env_string<Char>(value)}; } env_reset<Char> operator=(boost::none_t) { return {std::move(key)}; } }; struct env_ { constexpr env_() {}; template<typename Char> env_set<Char> operator()(const std::basic_string<Char> & key, const std::basic_string<Char> & value) const { return {key, value}; } template<typename Char> env_set<Char> operator()(const std::basic_string<Char> & key, const std::vector<std::basic_string<Char>> & value) const { return {key, make_env_string<Char>(value)}; } template<typename Char> env_set<Char> operator()(const std::basic_string<Char> & key, const std::initializer_list<Char*> & value) const { return {key, make_env_string<Char>(value)}; } template<typename Char> env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t) { return {key}; } template<typename Char> env_proxy<Char> operator[](const std::basic_string<Char> & key) const { return {key}; } template<typename Char> env_proxy<Char> operator[](const Char* key) const { return {key}; } template<typename Char> env_init<Char> operator()(const basic_environment<Char> & env) const { return {env}; } template<typename Char> env_init<Char> operator= (const basic_environment<Char> & env) const { return {env}; } }; template<typename Char> struct env_builder { basic_environment<Char> env; env_builder() : env{basic_native_environment<Char>()} {} void operator()(const basic_environment<Char> & e) { env = e; } void operator()(env_init<Char> & ei) { env = std::move(ei.env); } void operator()(env_set<Char> & es) { env[es.key] = es.value; } void operator()(env_reset<Char> & es) { env.erase(es.key); } template<typename T> void operator()(env_append<T> & es) { env[es.key] += es.value; } typedef api::env_init<Char> result_type; api::env_init<Char> get_initializer() { return api::env_init<Char>(std::move(env)); } }; template<> struct initializer_builder<env_tag<char>> { typedef env_builder<char> type; }; template<> struct initializer_builder<env_tag<wchar_t>> { typedef env_builder<wchar_t> type; }; } /** The `env` property provides a functional way to modify the environment used by the child process. If none is passed the environment is inherited from the father process. Appending means that the environment will be interpreted as a ';' or ':' separated list as used in `PATH`. On both `posix` and `windows` the environment variables can be lists of strings, separated by ';'. This is typically used for the `PATH` variable. By default the environment will be inherited from the launching process, which is also true if environment are modified with this initializer. \section env_details Details \subsection env_operations Operations \subsubsection env_set_var Setting variables To set a variable `id` the value `value` the following syntax can be used. \code{.cpp} env[id] = value; env(id, value); \endcode `std::initializer_list` is among the allowed types, so the following syntax is also possible. \code{.cpp} env[id] = {value1, value2}; env(id, {value1, value2}); \endcode \note Creates the variable if it does not exist. The following lists contain possible value types, with `char_type` being either `char` or `wchar_t` for both `id` and `value`. \paragraph id id - `std::basic_string<char_type>` - `const char_type *` \paragraph env_set_var_value value - `std::basic_string<char_type>` - `const char_type * ` - `std::initializer_list<const char_type *>` - `std::vector<std::basic_string<char_type>>` \note Using `std::vector` or `std::initializer_list` \subsubsection env_append_var Append variables Appending means, that a variable will be interpreted as a To append a variable `id` the value `value` the following syntax can be used: \code{.cpp} env[id] += value; \endcode `std::initializer_list` is among the allowed types, so the following syntax is also possible. \code{.cpp} env[id] += {value1, value2}; \endcode \note Creates the variable if it does not exist. The following lists contain possible value types, with `char_type` being either `char` or `wchar_t` for both `id` and `value`. \paragraph env_append_var_id id - `std::basic_string<char_type>` - `const char_type *` \paragraph env_append_var_value value - `std::basic_string<char_type>` - `const char_type *` - `std::initializer_list<const char_type *>` - `std::vector<std::basic_string<char_type>>` \subsubsection env_reset Reset variables Reseting signle variables can be done in the following way: \code{.cpp} env[id] = boost::none; env(id, boost::none); \endcode \note This does not set the value empty, but removes it from the list. The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`: \paragraph env_reset_var_id id - `std::basic_string<char_type>` - `const char_type *` \subsubsection env_init Initialize the environment The whole environment can be initialized from an object of type \xmlonly <classname>boost::process::environment</classname> \endxmlonly \code{.cpp} env=env; env(env); \endcode \note The passed `environment` can also be default-constructed to get an empty environment. \paragraph env_init_var_id id - `std::basic_string<char_type>` - `const char_type *` \paragraph env_init_var_value value - `boost::process::basic_environment<char_type>` \subsection env_example Example \code{.cpp} spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE"); \endcode If the overload style should be done by passing an instance of \xmlonly <classname>boost::process::environment</classname> \endxmlonly the above example would look like this. \code{.cpp} environment e = this_process::environment(); e["PATH"] += "F:/boost"; e.erase("SOME_VAR"); e["NEW_VAR"] = "VALUE"; spawn("b2", e); \endcode \warning Passing an empty environment will cause undefined behaviour. */ constexpr boost::process::detail::env_ env{}; }} #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */ system.hpp 0000644 00000007775 15125237361 0006626 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/system.hpp * * Defines a system function. */ #ifndef BOOST_PROCESS_SYSTEM_HPP #define BOOST_PROCESS_SYSTEM_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/on_exit.hpp> #include <boost/process/child.hpp> #include <boost/process/detail/async_handler.hpp> #include <boost/process/detail/execute_impl.hpp> #include <boost/asio/post.hpp> #include <type_traits> #include <mutex> #include <condition_variable> #if defined(BOOST_POSIX_API) #include <boost/process/posix.hpp> #endif namespace boost { namespace process { namespace detail { struct system_impl_success_check : handler { bool succeeded = false; template<typename Exec> void on_success(Exec &) { succeeded = true; } }; template<typename IoService, typename ...Args> inline int system_impl( std::true_type, /*needs ios*/ std::true_type, /*has io_context*/ Args && ...args) { IoService & ios = ::boost::process::detail::get_io_context_var(args...); system_impl_success_check check; std::atomic_bool exited{false}; child c(std::forward<Args>(args)..., check, ::boost::process::on_exit( [&](int, const std::error_code&) { boost::asio::post(ios.get_executor(), [&]{exited.store(true);}); })); if (!c.valid() || !check.succeeded) return -1; while (!exited.load()) ios.poll(); return c.exit_code(); } template<typename IoService, typename ...Args> inline int system_impl( std::true_type, /*needs ios */ std::false_type, /*has io_context*/ Args && ...args) { IoService ios; child c(ios, std::forward<Args>(args)...); if (!c.valid()) return -1; ios.run(); if (c.running()) c.wait(); return c.exit_code(); } template<typename IoService, typename ...Args> inline int system_impl( std::false_type, /*needs ios*/ std::true_type, /*has io_context*/ Args && ...args) { child c(std::forward<Args>(args)...); if (!c.valid()) return -1; c.wait(); return c.exit_code(); } template<typename IoService, typename ...Args> inline int system_impl( std::false_type, /*has async */ std::false_type, /*has io_context*/ Args && ...args) { child c(std::forward<Args>(args)... #if defined(BOOST_POSIX_API) ,::boost::process::posix::sig.dfl() #endif ); if (!c.valid()) return -1; c.wait(); return c.exit_code(); } } /** Launches a process and waits for its exit. It works as std::system, though it allows all the properties boost.process provides. It will execute the process and wait for it's exit; then return the exit_code. \code{.cpp} int ret = system("ls"); \endcode \attention Using this function with synchronous pipes leads to many potential deadlocks. When using this function with an asynchronous properties and NOT passing an io_context object, the system function will create one and run it. When the io_context is passed to the function, the system function will check if it is active, and call the io_context::run function if not. */ template<typename ...Args> inline int system(Args && ...args) { typedef typename ::boost::process::detail::needs_io_context<Args...>::type need_ios; typedef typename ::boost::process::detail::has_io_context<Args...>::type has_ios; return ::boost::process::detail::system_impl<boost::asio::io_context>( need_ios(), has_ios(), std::forward<Args>(args)...); } }} #endif shell.hpp 0000644 00000005035 15125237361 0006374 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_SHELL_PATH_HPP #define BOOST_PROCESS_SHELL_PATH_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/traits/wchar_t.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/shell_path.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/shell_path.hpp> #endif /** \file boost/process/shell.hpp * * Header which provides the shell property. This provides the * property to launch a process through the system shell. * It also allows the user to obtain the shell-path via shell(). \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::shell">shell</globalname>; } } </programlisting> \endxmlonly */ namespace boost { namespace process { namespace detail { struct shell_ { constexpr shell_() {} boost::filesystem::path operator()() const { return boost::process::detail::api::shell_path(); } boost::filesystem::path operator()(std::error_code & ec) const noexcept { return boost::process::detail::api::shell_path(ec); } }; template<> struct is_wchar_t<shell_> : is_wchar_t<boost::filesystem::path> { }; } /** The shell property enables to launch a program through the shell of the system. \code{.cpp} system("gcc", shell); \endcode The shell argument goes without any expression. The operator() is overloaded, to obtain the path of the system shell. \code{.cpp} auto shell_cmd = shell(); //avoid exceptions std::error_code ec; shell_cmd = shell(ec); \endcode \attention Launching through the shell will NOT provide proper error handling, i.e. you will get an error via the return code. \attention Executing shell commands that incorporate unsanitized input from an untrusted source makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution. For this reason, the use of `shell` is strongly discouraged in cases where the command string is constructed from external input: */ constexpr ::boost::process::detail::shell_ shell; }} #endif extend.hpp 0000644 00000034371 15125237361 0006561 0 ustar 00 // Copyright (c) 2016 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_EXTENSIONS_HPP_ #define BOOST_PROCESS_EXTENSIONS_HPP_ #include <boost/process/detail/handler.hpp> #include <boost/process/detail/used_handles.hpp> #if defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/executor.hpp> #include <boost/process/detail/windows/async_handler.hpp> #include <boost/process/detail/windows/asio_fwd.hpp> #else #include <boost/process/detail/posix/executor.hpp> #include <boost/process/detail/posix/async_handler.hpp> #include <boost/process/detail/posix/asio_fwd.hpp> #endif /** \file boost/process/extend.hpp * * This header which provides the types and functions provided for custom extensions. * * \xmlonly Please refer to the <link linkend="boost_process.extend">tutorial</link> for more details. \endxmlonly */ namespace boost { namespace process { namespace detail { template<typename Tuple> inline asio::io_context& get_io_context(const Tuple & tup); } ///Namespace for extensions \attention This is experimental. namespace extend { #if defined(BOOST_WINDOWS_API) template<typename Char, typename Sequence> using windows_executor = ::boost::process::detail::windows::executor<Char, Sequence>; template<typename Sequence> struct posix_executor; #elif defined(BOOST_POSIX_API) template<typename Sequence> using posix_executor = ::boost::process::detail::posix::executor<Sequence>; template<typename Char, typename Sequence> struct windows_executor; #endif using ::boost::process::detail::handler; using ::boost::process::detail::api::require_io_context; using ::boost::process::detail::api::async_handler; using ::boost::process::detail::get_io_context; using ::boost::process::detail::get_last_error; using ::boost::process::detail::throw_last_error; using ::boost::process::detail::uses_handles; using ::boost::process::detail::foreach_used_handle; using ::boost::process::detail::get_used_handles; ///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter. constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup; ///This handler is invoked if an error occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter. constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error; ///This handler is invoked if launching the process has succeeded. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success; #if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) ///This handler is invoked if the fork failed. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix. constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_fork_error_ > on_fork_error; ///This handler is invoked if the fork succeeded. The required signature is `void(Exec &)`, where `Exec` is a template parameter. \note Only available on posix. constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_setup_ > on_exec_setup; ///This handler is invoked if the exec call errored. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix. constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_error_ > on_exec_error; #endif #if defined(BOOST_PROCESS_DOXYGEN) ///Helper function to get the last error code system-independent inline std::error_code get_last_error(); ///Helper function to get and throw the last system error. /// \throws boost::process::process_error /// \param msg A message to add to the error code. inline void throw_last_error(const std::string & msg); ///\overload void throw_last_error(const std::string & msg) inline void throw_last_error(); /** This function gets the io_context from the initializer sequence. * * \attention Yields a compile-time error if no `io_context` is provided. * \param seq The Sequence of the initializer. */ template<typename Sequence> inline asio::io_context& get_io_context(const Sequence & seq); /** This class is the base for every initializer, to be used for extensions. * * The usage is done through compile-time polymorphism, so that the required * functions can be overloaded. * * \note None of the function need to be `const`. * */ struct handler { ///This function is invoked before the process launch. \note It is not required to be const. template <class Executor> void on_setup(Executor&) const {} /** This function is invoked if an error occured while trying to launch the process. * \note It is not required to be const. */ template <class Executor> void on_error(Executor&, const std::error_code &) const {} /** This function is invoked if the process was successfully launched. * \note It is not required to be const. */ template <class Executor> void on_success(Executor&) const {} /**This function is invoked if an error occured during the call of `fork`. * \note This function will only be called on posix. */ template<typename Executor> void on_fork_error (Executor &, const std::error_code&) const {} /**This function is invoked if the call of `fork` was successful, before * calling `execve`. * \note This function will only be called on posix. * \attention It will be invoked from the new process. */ template<typename Executor> void on_exec_setup (Executor &) const {} /**This function is invoked if the call of `execve` failed. * \note This function will only be called on posix. * \attention It will be invoked from the new process. */ template<typename Executor> void on_exec_error (Executor &, const std::error_code&) const {} }; /** Inheriting the class will tell the launching process that an `io_context` is * needed. This should always be used when \ref get_io_context is used. * */ struct require_io_context {}; /** Inheriting this class will tell the launching function, that an event handler * shall be invoked when the process exits. This automatically does also inherit * \ref require_io_context. * * You must add the following function to your implementation: * \code{.cpp} template<typename Executor> std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec) { auto handler_ = this->handler; return [handler_](int exit_code, const std::error_code & ec) { handler_(static_cast<int>(exit_code), ec); }; } \endcode The callback will be obtained by calling this function on setup and it will be invoked when the process exits. * * \warning Cannot be used with \ref boost::process::spawn */ struct async_handler : handler, require_io_context { }; ///The posix executor type. /** This type represents the posix executor and can be used for overloading in a custom handler. * \note It is an alias for the implementation on posix, and a forward-declaration on windows. * * \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept. \xmlonly As information for extension development, here is the structure of the process launching (in pseudo-code and uml) <xi:include href="posix_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> <mediaobject> <caption> <para>The sequence if when no error occurs.</para> </caption> <imageobject> <imagedata fileref="boost_process/posix_success.svg"/> </imageobject> </mediaobject> <mediaobject> <caption> <para>The sequence if the execution fails.</para> </caption> <imageobject> <imagedata fileref="boost_process/posix_exec_err.svg"/> </imageobject> </mediaobject> <mediaobject> <caption> <para>The sequence if the fork fails.</para> </caption> <imageobject> <imagedata fileref="boost_process/posix_fork_err.svg"/> </imageobject> </mediaobject> \endxmlonly \note Error handling if execve fails is done through a pipe, unless \ref ignore_error is used. */ template<typename Sequence> struct posix_executor { ///A reference to the actual initializer-sequence Sequence & seq; ///A pointer to the name of the executable. const char * exe = nullptr; ///A pointer to the argument-vector. char *const* cmd_line = nullptr; ///A pointer to the environment variables, as default it is set to [environ](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html) char **env = ::environ; ///The pid of the process - it will be -1 before invoking [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), and after forking either 0 for the new process or a positive value if in the current process. */ pid_t pid = -1; ///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_context` and \ref child. std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); ///This function returns a const reference to the error state of the executor. const std::error_code & error() const; ///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it /// might throw an exception. \note This is the required way to handle errors in initializers. void set_error(const std::error_code &ec, const std::string &msg); ///\overload void set_error(const std::error_code &ec, const std::string &msg); void set_error(const std::error_code &ec, const char* msg); }; ///The windows executor type. /** This type represents the posix executor and can be used for overloading in a custom handler. * * \note It is an alias for the implementation on posix, and a forward-declaration on windows. * \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept. * \tparam Char The used char-type, either `char` or `wchar_t`. * \xmlonly As information for extension development, here is the structure of the process launching (in pseudo-code and uml)<xi:include href="windows_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> <mediaobject> <caption> <para>The sequence for windows process creation.</para> </caption> <imageobject> <imagedata fileref="boost_process/windows_exec.svg"/> </imageobject> </mediaobject> \endxmlonly */ template<typename Char, typename Sequence> struct windows_executor { ///A reference to the actual initializer-sequence Sequence & seq; ///A pointer to the name of the executable. It's null by default. const Char * exe = nullptr; ///A pointer to the argument-vector. Must be set by some initializer. char Char* cmd_line = nullptr; ///A pointer to the environment variables. It's null by default. char Char* env = nullptr; ///A pointer to the working directory. It's null by default. const Char * work_dir = nullptr; ///A pointer to the process-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It's null by default. ::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr; ///A pointer to the thread-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It' null by default. ::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr; ///A logical bool value setting whether handles shall be inherited or not. ::boost::detail::winapi::BOOL_ inherit_handles = false; ///The element holding the process-information after process creation. The type is [PROCESS_INFORMATION](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873.aspx) ::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0}; ///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_context` and \ref child. std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); ///This function returns a const reference to the error state of the executor. const std::error_code & error() const; ///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it /// might throw an exception. \note This is the required way to handle errors in initializers. void set_error(const std::error_code &ec, const std::string &msg); ///\overload void set_error(const std::error_code &ec, const std::string &msg); void set_error(const std::error_code &ec, const char* msg); ///The creation flags of the process ::boost::detail::winapi::DWORD_ creation_flags; ///The type of the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx), depending on the char-type. typedef typename detail::startup_info<Char>::type startup_info_t; ///The type of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx), depending the char-type; only defined with winapi-version equal or higher than 6. typedef typename detail::startup_info_ex<Char>::type startup_info_ex_t; ///This function switches the information, so that the extended structure is used. \note It's only defined with winapi-version equal or higher than 6. void set_startup_info_ex(); ///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process. startup_info_t startup_info; ///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or highter than 6. startup_info_ex_t startup_info_ex; }; #endif } } } #endif environment.hpp 0000644 00000060266 15125237361 0007640 0 ustar 00 // Copyright (c) 2016 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_ENVIRONMENT_HPP_ #define BOOST_PROCESS_ENVIRONMENT_HPP_ #include <boost/process/detail/config.hpp> #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/case_conv.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/filesystem/path.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/environment.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/environment.hpp> #endif namespace boost { namespace process { namespace detail { template<typename Char, typename Environment> struct const_entry { using value_type = Char ; using pointer = const value_type * ; using string_type = std::basic_string<value_type> ; using range = boost::iterator_range<pointer> ; using environment_t = Environment ; std::vector<string_type> to_vector() const { if (_data == nullptr) return std::vector<string_type>(); std::vector<string_type> data; auto str = string_type(_data); struct splitter { bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();} bool operator()(char c) const {return c == api::env_seperator<char> ();} } s; boost::split(data, _data, s); return data; } string_type to_string() const { if (_data != nullptr) return string_type(_data); else return string_type(); } string_type get_name() const {return string_type(_name.begin(), _name.end());} explicit const_entry(string_type&& name, pointer data, environment_t & env_) : _name(std::move(name)), _data(data), _env(&env_) {} explicit const_entry(string_type &&name, environment_t & env) : _name(std::move(name)), _data(nullptr), _env(&env) {} const_entry(const const_entry&) = default; const_entry& operator=(const const_entry&) = default; void reload() { auto p = _env->find(_name); if (p == _env->end()) _data = nullptr; else _data = p->_data; this->_env->reload(); } bool empty() const { return _data == nullptr; } protected: string_type _name; pointer _data; environment_t * _env; }; template<typename Char, typename Environment> struct entry : const_entry<Char, Environment> { using father = const_entry<Char, Environment>; using value_type = typename father::value_type; using string_type = typename father::string_type; using pointer = typename father::pointer; using environment_t = typename father::environment_t; explicit entry(string_type&& name, pointer data, environment_t & env) : father(std::move(name), data, env) {} explicit entry(string_type &&name, environment_t & env_) : father(std::move(name), env_) {} entry(const entry&) = default; entry& operator=(const entry&) = default; void assign(const string_type &value) { this->_env->set(this->_name, value); this->reload(); } void assign(const std::vector<string_type> &value) { string_type data; for (auto &v : value) { if (&v != &value.front()) data += api::env_seperator<value_type>(); data += v; } this->_env->set(this->_name, data); this->reload(); } void assign(const std::initializer_list<string_type> &value) { string_type data; for (auto &v : value) { if (&v != &*value.begin()) data += api::env_seperator<value_type>(); data += v; } this->_env->set(this->_name, data); this->reload(); } void append(const string_type &value) { if (this->_data == nullptr) this->_env->set(this->_name, value); else { string_type st = this->_data; this->_env->set(this->_name, st + api::env_seperator<value_type>() + value); } this->reload(); } void clear() { this->_env->reset(this->_name); this->_env->reload(); this->_data = nullptr; } entry &operator=(const string_type & value) { assign(value); return *this; } entry &operator=(const std::vector<string_type> & value) { assign(value); return *this; } entry &operator=(const std::initializer_list<string_type> & value) { assign(value); return *this; } entry &operator+=(const string_type & value) { append(value); return *this; } }; template<typename Char, typename Environment> struct make_entry { make_entry(const make_entry&) = default; make_entry& operator=(const make_entry&) = default; Environment *env; make_entry(Environment & env) : env(&env) {}; entry<Char, Environment> operator()(const Char* data) const { auto p = data; while ((*p != equal_sign<Char>()) && (*p != null_char<Char>())) p++; auto name = std::basic_string<Char>(data, p); p++; //go behind equal sign return entry<Char, Environment>(std::move(name), p, *env); } }; template<typename Char, typename Environment> struct make_const_entry { make_const_entry(const make_const_entry&) = default; make_const_entry& operator=(const make_const_entry&) = default; Environment *env; make_const_entry(Environment & env) : env(&env) {}; const_entry<Char, Environment> operator()(const Char* data) const { auto p = data; while ((*p != equal_sign<Char>()) && (*p != null_char<Char>())) p++; auto name = std::basic_string<Char>(data, p); p++; //go behind equal sign return const_entry<Char, Environment>(std::move(name), p, *env); } }; } #if !defined (BOOST_PROCESS_DOXYGEN) template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl> class basic_environment_impl : public Implementation<Char> { Char** _get_end() const { auto p = this->_env_impl; while (*p != nullptr) p++; return p; } public: using string_type = std::basic_string<Char>; using implementation_type = Implementation<Char>; using base_type = basic_environment_impl<Char, Implementation>; using entry_maker = detail::make_entry<Char, base_type>; using entry_type = detail::entry <Char, base_type>; using const_entry_type = detail::const_entry <Char, const base_type>; using const_entry_maker = detail::make_const_entry<Char, const base_type>; friend entry_type; friend const_entry_type; using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>; using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>; using size_type = std::size_t; iterator begin() {return iterator(this->_env_impl, entry_maker(*this));} const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));} const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));} iterator end() {return iterator(_get_end(), entry_maker(*this));} const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));} const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));} iterator find( const string_type& key ) { auto p = this->_env_impl; auto st1 = key + ::boost::process::detail::equal_sign<Char>(); while (*p != nullptr) { if (std::equal(st1.begin(), st1.end(), *p)) break; p++; } return iterator(p, entry_maker(*this)); } const_iterator find( const string_type& key ) const { auto p = this->_env_impl; auto st1 = key + ::boost::process::detail::equal_sign<Char>(); while (*p != nullptr) { if (std::equal(st1.begin(), st1.end(), *p)) break; p++; } return const_iterator(p, const_entry_maker(*this)); } std::size_t count(const string_type & st) const { auto p = this->_env_impl; auto st1 = st + ::boost::process::detail::equal_sign<Char>(); while (*p != nullptr) { if (std::equal(st1.begin(), st1.end(), *p)) return 1u; p++; } return 0u; } void erase(const string_type & id) { implementation_type::reset(id); this->reload(); } std::pair<iterator,bool> emplace(const string_type & id, const string_type & value) { auto f = find(id); if (f == end()) { implementation_type::set(id, value); this->reload(); return std::pair<iterator, bool>(find(id), true); } else return std::pair<iterator, bool>(f, false); } using implementation_type::implementation_type; using implementation_type::operator=; using native_handle_type = typename implementation_type::native_handle_type; using implementation_type::native_handle; //copy ctor if impl is copy-constructible bool empty() { return *this->_env_impl == nullptr; } std::size_t size() const { return (_get_end() - this->_env_impl); } void clear() { std::vector<string_type> names; names.resize(size()); std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();}); for (auto & nm : names) implementation_type::reset(nm); this->reload(); } entry_type at( const string_type& key ) { auto f = find(key); if (f== end()) throw std::out_of_range(key + " not found"); return *f; } const_entry_type at( const string_type& key ) const { auto f = find(key); if (f== end()) throw std::out_of_range(key + " not found"); return *f; } entry_type operator[](const string_type & key) { auto p = find(key); if (p != end()) return *p; return entry_type(string_type(key), *this); } }; #endif #if defined(BOOST_PROCESS_DOXYGEN) /**Template representation of environments. It takes a character type (`char` or `wchar_t`) * as template parameter to implement the environment */ template<typename Char> class basic_environment { public: typedef std::basic_string<Char> string_type; typedef boost::transform_iterator< entry_maker, Char**> iterator ; typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ; typedef std::size_t size_type ; iterator begin() ; ///<Returns an iterator to the beginning const_iterator begin() const ; ///<Returns an iterator to the beginning const_iterator cbegin() const ; ///<Returns an iterator to the beginning iterator end() ; ///<Returns an iterator to the end const_iterator end() const; ///<Returns an iterator to the end const_iterator cend() const; ///<Returns an iterator to the end iterator find( const string_type& key ); ///<Find a variable by its name const_iterator find( const string_type& key ) const; ///<Find a variable by its name std::size_t count(const string_type & st) const; ///<Number of variables void erase(const string_type & id); ///<Erase variable by id. ///Emplace an environment variable. std::pair<iterator,bool> emplace(const string_type & id, const string_type & value); ///Default constructor basic_environment(); ///Copy constructor. basic_environment(const basic_environment & ); ///Move constructor. basic_environment(basic_environment && ); ///Copy assignment. basic_environment& operator=(const basic_environment & ); ///Move assignment. basic_environment& operator=(basic_environment && ); typedef typename detail::implementation_type::native_handle_type native_handle; ///Check if environment has entries. bool empty(); ///Get the number of variables. std::size_t size() const; ///Clear the environment. @attention Use with care, passed environment cannot be empty. void clear(); ///Get the entry with the key. Throws if it does not exist. entry_type at( const string_type& key ); ///Get the entry with the key. Throws if it does not exist. const_entry_type at( const string_type& key ) const; ///Get the entry with the given key. It creates the entry if it doesn't exist. entry_type operator[](const string_type & key); /**Proxy class used for read access to members by [] or .at() * @attention Holds a reference to the environment it was created from. */ template<typename Char, typename Environment> struct const_entry_type { typedef Char value_type; typedef const value_type * pointer; typedef std::basic_string<value_type> string_type; typedef boost::iterator_range<pointer> range; typedef Environment environment_t; ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. std::vector<string_type> to_vector() const ///Get the value as string. string_type to_string() const ///Get the name of this entry. string_type get_name() const {return string_type(_name.begin(), _name.end());} ///Copy Constructor const_entry(const const_entry&) = default; ///Move Constructor const_entry& operator=(const const_entry&) = default; ///Check if the entry is empty. bool empty() const; }; /**Proxy class used for read and write access to members by [] or .at() * @attention Holds a reference to the environment it was created from. */ template<typename Char, typename Environment> struct entry_type { typedef Char value_type; typedef const value_type * pointer; typedef std::basic_string<value_type> string_type; typedef boost::iterator_range<pointer> range; typedef Environment environment_t; ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. std::vector<string_type> to_vector() const ///Get the value as string. string_type to_string() const ///Get the name of this entry. string_type get_name() const {return string_type(_name.begin(), _name.end());} ///Copy Constructor entry(const entry&) = default; ///Move Constructor entry& operator=(const entry&) = default; ///Check if the entry is empty. bool empty() const; ///Assign a string to the value void assign(const string_type &value); ///Assign a set of strings to the entry; they will be separated by ';' or ':'. void assign(const std::vector<string_type> &value); ///Append a string to the end of the entry, it will separated by ';' or ':'. void append(const string_type &value); ///Reset the value void clear(); ///Assign a string to the entry. entry &operator=(const string_type & value); ///Assign a set of strings to the entry; they will be separated by ';' or ':'. entry &operator=(const std::vector<string_type> & value); ///Append a string to the end of the entry, it will separated by ';' or ':'. entry &operator+=(const string_type & value); }; }; /**Template representation of the environment of this process. It takes a template * as template parameter to implement the environment. All instances of this class * refer to the same environment, but might not get updated if another one makes changes. */ template<typename Char> class basic_native_environment { public: typedef std::basic_string<Char> string_type; typedef boost::transform_iterator< entry_maker, Char**> iterator ; typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ; typedef std::size_t size_type ; iterator begin() ; ///<Returns an iterator to the beginning const_iterator begin() const ; ///<Returns an iterator to the beginning const_iterator cbegin() const ; ///<Returns an iterator to the beginning iterator end() ; ///<Returns an iterator to the end const_iterator end() const; ///<Returns an iterator to the end const_iterator cend() const; ///<Returns an iterator to the end iterator find( const string_type& key ); ///<Find a variable by its name const_iterator find( const string_type& key ) const; ///<Find a variable by its name std::size_t count(const string_type & st) const; ///<Number of variables void erase(const string_type & id); ///<Erase variable by id. ///Emplace an environment variable. std::pair<iterator,bool> emplace(const string_type & id, const string_type & value); ///Default constructor basic_native_environment(); ///Move constructor. basic_native_environment(basic_native_environment && ); ///Move assignment. basic_native_environment& operator=(basic_native_environment && ); typedef typename detail::implementation_type::native_handle_type native_handle; ///Check if environment has entries. bool empty(); ///Get the number of variables. std::size_t size() const; ///Get the entry with the key. Throws if it does not exist. entry_type at( const string_type& key ); ///Get the entry with the key. Throws if it does not exist. const_entry_type at( const string_type& key ) const; ///Get the entry with the given key. It creates the entry if it doesn't exist. entry_type operator[](const string_type & key); /**Proxy class used for read access to members by [] or .at() * @attention Holds a reference to the environment it was created from. */ template<typename Char, typename Environment> struct const_entry_type { typedef Char value_type; typedef const value_type * pointer; typedef std::basic_string<value_type> string_type; typedef boost::iterator_range<pointer> range; typedef Environment environment_t; ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. std::vector<string_type> to_vector() const ///Get the value as string. string_type to_string() const ///Get the name of this entry. string_type get_name() const {return string_type(_name.begin(), _name.end());} ///Copy Constructor const_entry(const const_entry&) = default; ///Move Constructor const_entry& operator=(const const_entry&) = default; ///Check if the entry is empty. bool empty() const; }; /**Proxy class used for read and write access to members by [] or .at() * @attention Holds a reference to the environment it was created from. */ template<typename Char, typename Environment> struct entry_type { typedef Char value_type; typedef const value_type * pointer; typedef std::basic_string<value_type> string_type; typedef boost::iterator_range<pointer> range; typedef Environment environment_t; ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. std::vector<string_type> to_vector() const ///Get the value as string. string_type to_string() const ///Get the name of this entry. string_type get_name() const {return string_type(_name.begin(), _name.end());} ///Copy Constructor entry(const entry&) = default; ///Move Constructor entry& operator=(const entry&) = default; ///Check if the entry is empty. bool empty() const; ///Assign a string to the value void assign(const string_type &value); ///Assign a set of strings to the entry; they will be separated by ';' or ':'. void assign(const std::vector<string_type> &value); ///Append a string to the end of the entry, it will separated by ';' or ':'. void append(const string_type &value); ///Reset the value void clear(); ///Assign a string to the entry. entry &operator=(const string_type & value); ///Assign a set of strings to the entry; they will be separated by ';' or ':'. entry &operator=(const std::vector<string_type> & value); ///Append a string to the end of the entry, it will separated by ';' or ':'. entry &operator+=(const string_type & value); }; }; #endif ///Definition of the environment for the current process. template<typename Char> class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl> { public: using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>; using base_type::base_type; using base_type::operator=; }; ///Type definition to hold a seperate environment. template<typename Char> class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl> { public: using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>; using base_type::base_type; using base_type::operator=; }; #if !defined(BOOST_NO_ANSI_APIS) ///Definition of the environment for the current process. typedef basic_native_environment<char> native_environment; #endif ///Definition of the environment for the current process. typedef basic_native_environment<wchar_t> wnative_environment; #if !defined(BOOST_NO_ANSI_APIS) ///Type definition to hold a seperate environment. typedef basic_environment<char> environment; #endif ///Type definition to hold a seperate environment. typedef basic_environment<wchar_t> wenvironment; } ///Namespace containing information of the calling process. namespace this_process { ///Definition of the native handle type. typedef ::boost::process::detail::api::native_handle_t native_handle_type; #if !defined(BOOST_NO_ANSI_APIS) ///Definition of the environment for this process. using ::boost::process::native_environment; #endif ///Definition of the environment for this process. using ::boost::process::wnative_environment; ///Get the process id of the current process. inline int get_id() { return ::boost::process::detail::api::get_id();} ///Get the native handle of the current process. inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();} #if !defined(BOOST_NO_ANSI_APIS) ///Get the enviroment of the current process. inline native_environment environment() { return ::boost::process:: native_environment(); } #endif ///Get the enviroment of the current process. inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); } ///Get the path environment variable of the current process runs. inline std::vector<boost::filesystem::path> path() { #if defined(BOOST_WINDOWS_API) const ::boost::process::wnative_environment ne{}; typedef typename ::boost::process::wnative_environment::const_entry_type value_type; static constexpr auto id = L"PATH"; #else const ::boost::process::native_environment ne{}; typedef typename ::boost::process::native_environment::const_entry_type value_type; static constexpr auto id = "PATH"; #endif auto itr = std::find_if(ne.cbegin(), ne.cend(), [&](const value_type & e) {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());}); if (itr == ne.cend()) return {}; auto vec = itr->to_vector(); std::vector<boost::filesystem::path> val; val.resize(vec.size()); std::copy(vec.begin(), vec.end(), val.begin()); return val; } } } #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */ async_system.hpp 0000644 00000010667 15125237361 0010015 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/async_system.hpp * * Defines the asynchrounous version of the system function. */ #ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP #define BOOST_PROCESS_ASYNC_SYSTEM_HPP #include <boost/process/detail/config.hpp> #include <boost/process/async.hpp> #include <boost/process/child.hpp> #include <boost/process/detail/async_handler.hpp> #include <boost/process/detail/execute_impl.hpp> #include <type_traits> #include <memory> #include <boost/asio/async_result.hpp> #include <boost/asio/post.hpp> #include <boost/system/error_code.hpp> #include <tuple> #if defined(BOOST_POSIX_API) #include <boost/process/posix.hpp> #endif namespace boost { namespace process { namespace detail { template<typename ExitHandler> struct async_system_handler : ::boost::process::detail::api::async_handler { boost::asio::io_context & ios; boost::asio::async_completion< ExitHandler, void(boost::system::error_code, int)> init; #if defined(BOOST_POSIX_API) bool errored = false; #endif template<typename ExitHandler_> async_system_handler( boost::asio::io_context & ios, ExitHandler_ && exit_handler) : ios(ios), init(exit_handler) { } template<typename Exec> void on_error(Exec&, const std::error_code & ec) { #if defined(BOOST_POSIX_API) errored = true; #endif auto & h = init.completion_handler; boost::asio::post( ios.get_executor(), [h, ec]() mutable { h(boost::system::error_code(ec.value(), boost::system::system_category()), -1); }); } BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) get_result() { return init.result.get(); } template<typename Executor> std::function<void(int, const std::error_code&)> on_exit_handler(Executor&) { #if defined(BOOST_POSIX_API) if (errored) return [](int , const std::error_code &){}; #endif auto & h = init.completion_handler; return [h](int exit_code, const std::error_code & ec) mutable { h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code); }; } }; template<typename ExitHandler> struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {}; } /** This function provides an asynchronous interface to process launching. It uses the same properties and parameters as the other launching function, but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html) It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine the return value (from the second parameter, `exit_handler`). \param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html) \param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)` \note This function does not allow custom error handling, since those are done through the `exit_handler`. */ #if defined(BOOST_PROCESS_DOXYGEN) template<typename ExitHandler, typename ...Args> inline boost::process::detail::dummy async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args); #endif template<typename ExitHandler, typename ...Args> inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args) { detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)}; typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type has_err_handling; static_assert(!has_err_handling::value, "async_system cannot have custom error handling"); child(ios, std::forward<Args>(args)..., async_h ).detach(); return async_h.get_result(); } }} #endif args.hpp 0000644 00000021410 15125237361 0006214 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_ARGS_HPP #define BOOST_PROCESS_ARGS_HPP /** \file boost/process/args.hpp * * This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the * alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly . * * \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>; } } </programlisting> \endxmlonly */ #include <boost/process/detail/basic_cmd.hpp> #include <iterator> namespace boost { namespace process { namespace detail { struct args_ { template<typename T> using remove_reference_t = typename std::remove_reference<T>::type; template<typename T> using value_type = typename remove_reference_t<T>::value_type; template<typename T> using vvalue_type = value_type<value_type<T>>; template <class Range> arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const { return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range)); } template <class Range> arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const { return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range)); } template <class Range> arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const { return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range)); } template<typename Char> arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const { return arg_setter_<Char, false>(str); } template<typename Char> arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const { return arg_setter_<Char, false>(str); } template<typename Char> arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const { return arg_setter_<Char, false>(str); } template<typename Char> arg_setter_<Char, true> operator()(const Char* str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, true> operator+=(const Char* str) const { return arg_setter_<Char, true> (str); } template<typename Char> arg_setter_<Char, false> operator= (const Char* str) const { return arg_setter_<Char, false>(str); } // template<typename Char, std::size_t Size> // arg_setter_<Char, true> operator()(const Char (&str) [Size]) const // { // return arg_setter_<Char, true> (str); // } // template<typename Char, std::size_t Size> // arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const // { // return arg_setter_<Char, true> (str); // } // template<typename Char, std::size_t Size> // arg_setter_<Char, false> operator= (const Char (&str) [Size]) const // { // return arg_setter_<Char, false>(str); // } arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const { return arg_setter_<char, true>(range.begin(), range.end()); } arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const { return arg_setter_<char, true>(range.begin(), range.end()); } arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const { return arg_setter_<char, false>(range.begin(), range.end()); } arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const { return arg_setter_<char, true>(range.begin(), range.end()); } arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const { return arg_setter_<char, true>(range.begin(), range.end()); } arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const { return arg_setter_<char, false>(range.begin(), range.end()); } arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const { return arg_setter_<wchar_t, true>(range.begin(), range.end()); } arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const { return arg_setter_<wchar_t, true>(range.begin(), range.end()); } arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const { return arg_setter_<wchar_t, false>(range.begin(), range.end()); } arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const { return arg_setter_<wchar_t, true>(range.begin(), range.end()); } arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const { return arg_setter_<wchar_t, true>(range.begin(), range.end()); } arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const { return arg_setter_<wchar_t, false>(range.begin(), range.end()); } }; } /** The `args` property allows to explicitly set arguments for the execution. The name of the executable will always be the first element in the arg-vector. \section args_details Details \subsection args_operations Operations \subsubsection args_set_var Setting values To set a the argument vector the following syntax can be used. \code{.cpp} args = value; args(value); \endcode `std::initializer_list` is among the allowed types, so the following syntax is also possible. \code{.cpp} args = {value1, value2}; args({value1, value2}); \endcode Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`. \paragraph args_set_var_value value - `std::basic_string<char_type>` - `const char_type * ` - `std::initializer_list<const char_type *>` - `std::vector<std::basic_string<char_type>>` Additionally any range of `std::basic_string<char_type>` can be passed. \subsubsection args_append_var Appending values To append a the argument vector the following syntax can be used. \code{.cpp} args += value; \endcode `std::initializer_list` is among the allowed types, so the following syntax is also possible. \code{.cpp} args += {value1, value2}; \endcode Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`. \paragraph args_append_var_value value - `std::basic_string<char_type>` - `const char_type * ` - `std::initializer_list<const char_type *>` - `std::vector<std::basic_string<char_type>>` Additionally any range of `std::basic_string<char_type>` can be passed. \subsection args_example Example The overload form is used when more than one string is passed, from the second one forward. I.e. the following expressions have the same results: \code{.cpp} spawn("gcc", "--version"); spawn("gcc", args ="--version"); spawn("gcc", args+="--version"); spawn("gcc", args ={"--version"}); spawn("gcc", args+={"--version"}); \endcode \note A string will be parsed and set in quotes if it has none and contains spaces. */ constexpr boost::process::detail::args_ args{}; ///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly . constexpr boost::process::detail::args_ argv{}; }} #endif pipe.hpp 0000644 00000044513 15125237361 0006226 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_PIPE_HPP #define BOOST_PROCESS_PIPE_HPP #include <boost/config.hpp> #include <boost/process/detail/config.hpp> #include <streambuf> #include <istream> #include <ostream> #include <vector> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/basic_pipe.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/basic_pipe.hpp> #endif namespace boost { namespace process { using ::boost::process::detail::api::basic_pipe; #if defined(BOOST_PROCESS_DOXYGEN) /** Class implementation of a pipe. * */ template<class CharT, class Traits = std::char_traits<CharT>> class basic_pipe { public: typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; typedef ::boost::detail::winapi::HANDLE_ native_handle; /// Default construct the pipe. Will be opened. basic_pipe(); ///Construct a named pipe. inline explicit basic_pipe(const std::string & name); /** Copy construct the pipe. * \note Duplicated the handles. */ inline basic_pipe(const basic_pipe& p); /** Move construct the pipe. */ basic_pipe(basic_pipe&& lhs); /** Copy assign the pipe. * \note Duplicated the handles. */ inline basic_pipe& operator=(const basic_pipe& p); /** Move assign the pipe. */ basic_pipe& operator=(basic_pipe&& lhs); /** Destructor closes the handles. */ ~basic_pipe(); /** Get the native handle of the source. */ native_handle native_source() const; /** Get the native handle of the sink. */ native_handle native_sink () const; /** Assign a new value to the source */ void assign_source(native_handle h); /** Assign a new value to the sink */ void assign_sink (native_handle h); ///Write data to the pipe. int_type write(const char_type * data, int_type count); ///Read data from the pipe. int_type read(char_type * data, int_type count); ///Check if the pipe is open. bool is_open(); ///Close the pipe void close(); }; #endif typedef basic_pipe<char> pipe; typedef basic_pipe<wchar_t> wpipe; /** Implementation of the stream buffer for a pipe. */ template< class CharT, class Traits = std::char_traits<CharT> > struct basic_pipebuf : std::basic_streambuf<CharT, Traits> { typedef basic_pipe<CharT, Traits> pipe_type; typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; constexpr static int default_buffer_size = BOOST_PROCESS_PIPE_SIZE; ///Default constructor, will also construct the pipe. basic_pipebuf() : _write(default_buffer_size), _read(default_buffer_size) { this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); this->setp(_write.data(), _write.data() + _write.size()); } ///Copy Constructor. basic_pipebuf(const basic_pipebuf & ) = default; ///Move Constructor basic_pipebuf(basic_pipebuf && ) = default; ///Destructor -> writes the frest of the data ~basic_pipebuf() { if (basic_pipebuf::is_open()) basic_pipebuf::overflow(Traits::eof()); } ///Move construct from a pipe. basic_pipebuf(pipe_type && p) : _pipe(std::move(p)), _write(default_buffer_size), _read(default_buffer_size) { this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); this->setp(_write.data(), _write.data() + _write.size()); } ///Construct from a pipe. basic_pipebuf(const pipe_type & p) : _pipe(p), _write(default_buffer_size), _read(default_buffer_size) { this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); this->setp(_write.data(), _write.data() + _write.size()); } ///Copy assign. basic_pipebuf& operator=(const basic_pipebuf & ) = delete; ///Move assign. basic_pipebuf& operator=(basic_pipebuf && ) = default; ///Move assign a pipe. basic_pipebuf& operator=(pipe_type && p) { _pipe = std::move(p); return *this; } ///Copy assign a pipe. basic_pipebuf& operator=(const pipe_type & p) { _pipe = p; return *this; } ///Writes characters to the associated output sequence from the put area int_type overflow(int_type ch = traits_type::eof()) override { if (_pipe.is_open() && (ch != traits_type::eof())) { if (this->pptr() == this->epptr()) { bool wr = this->_write_impl(); if (wr) { *this->pptr() = ch; this->pbump(1); return ch; } } else { *this->pptr() = ch; this->pbump(1); if (this->_write_impl()) return ch; } } else if (ch == traits_type::eof()) this->sync(); return traits_type::eof(); } ///Synchronizes the buffers with the associated character sequence int sync() override { return this->_write_impl() ? 0 : -1; } ///Reads characters from the associated input sequence to the get area int_type underflow() override { if (!_pipe.is_open()) return traits_type::eof(); if (this->egptr() == &_read.back()) //ok, so we're at the end of the buffer this->setg(_read.data(), _read.data()+ 10, _read.data() + 10); auto len = &_read.back() - this->egptr() ; auto res = _pipe.read( this->egptr(), static_cast<typename pipe_type::int_type>(len)); if (res == 0) return traits_type::eof(); this->setg(this->eback(), this->gptr(), this->egptr() + res); auto val = *this->gptr(); return traits_type::to_int_type(val); } ///Set the pipe of the streambuf. void pipe(pipe_type&& p) {_pipe = std::move(p); } ///Set the pipe of the streambuf. void pipe(const pipe_type& p) {_pipe = p; } ///Get a reference to the pipe. pipe_type & pipe() & {return _pipe;} ///Get a const reference to the pipe. const pipe_type &pipe() const & {return _pipe;} ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe_type && pipe() && {return std::move(_pipe);} ///Check if the pipe is open bool is_open() const {return _pipe.is_open(); } ///Open a new pipe basic_pipebuf<CharT, Traits>* open() { if (is_open()) return nullptr; _pipe = pipe(); return this; } ///Open a new named pipe basic_pipebuf<CharT, Traits>* open(const std::string & name) { if (is_open()) return nullptr; _pipe = pipe(name); return this; } ///Flush the buffer & close the pipe basic_pipebuf<CharT, Traits>* close() { if (!is_open()) return nullptr; overflow(Traits::eof()); return this; } private: pipe_type _pipe; std::vector<char_type> _write; std::vector<char_type> _read; bool _write_impl() { if (!_pipe.is_open()) return false; auto base = this->pbase(); if (base == this->pptr()) return true; std::ptrdiff_t wrt = _pipe.write(base, static_cast<typename pipe_type::int_type>(this->pptr() - base)); std::ptrdiff_t diff = this->pptr() - base; if (wrt < diff) std::move(base + wrt, base + diff, base); else if (wrt == 0) //broken pipe return false; this->pbump(-wrt); return true; } }; typedef basic_pipebuf<char> pipebuf; typedef basic_pipebuf<wchar_t> wpipebuf; /** Implementation of a reading pipe stream. * */ template< class CharT, class Traits = std::char_traits<CharT> > class basic_ipstream : public std::basic_istream<CharT, Traits> { mutable basic_pipebuf<CharT, Traits> _buf; public: typedef basic_pipe<CharT, Traits> pipe_type; typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; ///Get access to the underlying stream_buf basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;}; ///Default constructor. basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr) { std::basic_istream<CharT, Traits>::rdbuf(&_buf); }; ///Copy constructor. basic_ipstream(const basic_ipstream & ) = delete; ///Move constructor. basic_ipstream(basic_ipstream && lhs) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf)) { std::basic_istream<CharT, Traits>::rdbuf(&_buf); } ///Move construct from a pipe. basic_ipstream(pipe_type && p) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p)) { std::basic_istream<CharT, Traits>::rdbuf(&_buf); } ///Copy construct from a pipe. basic_ipstream(const pipe_type & p) : std::basic_istream<CharT, Traits>(nullptr), _buf(p) { std::basic_istream<CharT, Traits>::rdbuf(&_buf); } ///Copy assignment. basic_ipstream& operator=(const basic_ipstream & ) = delete; ///Move assignment basic_ipstream& operator=(basic_ipstream && lhs) { std::basic_istream<CharT, Traits>::operator=(std::move(lhs)); _buf = std::move(lhs._buf); std::basic_istream<CharT, Traits>::rdbuf(&_buf); return *this; }; ///Move assignment of a pipe. basic_ipstream& operator=(pipe_type && p) { _buf = std::move(p); return *this; } ///Copy assignment of a pipe. basic_ipstream& operator=(const pipe_type & p) { _buf = p; return *this; } ///Set the pipe of the streambuf. void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } ///Set the pipe of the streambuf. void pipe(const pipe_type& p) {_buf.pipe(p); } ///Get a reference to the pipe. pipe_type & pipe() & {return _buf.pipe();} ///Get a const reference to the pipe. const pipe_type &pipe() const & {return _buf.pipe();} ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe_type && pipe() && {return std::move(_buf).pipe();} ///Check if the pipe is open bool is_open() const {return _buf.is_open();} ///Open a new pipe void open() { if (_buf.open() == nullptr) this->setstate(std::ios_base::failbit); else this->clear(); } ///Open a new named pipe void open(const std::string & name) { if (_buf.open() == nullptr) this->setstate(std::ios_base::failbit); else this->clear(); } ///Flush the buffer & close the pipe void close() { if (_buf.close() == nullptr) this->setstate(std::ios_base::failbit); } }; typedef basic_ipstream<char> ipstream; typedef basic_ipstream<wchar_t> wipstream; /** Implementation of a write pipe stream. * */ template< class CharT, class Traits = std::char_traits<CharT> > class basic_opstream : public std::basic_ostream<CharT, Traits> { mutable basic_pipebuf<CharT, Traits> _buf; public: typedef basic_pipe<CharT, Traits> pipe_type; typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; ///Get access to the underlying stream_buf basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;}; ///Default constructor. basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr) { std::basic_ostream<CharT, Traits>::rdbuf(&_buf); }; ///Copy constructor. basic_opstream(const basic_opstream & ) = delete; ///Move constructor. basic_opstream(basic_opstream && lhs) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf)) { std::basic_ostream<CharT, Traits>::rdbuf(&_buf); } ///Move construct from a pipe. basic_opstream(pipe_type && p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p)) { std::basic_ostream<CharT, Traits>::rdbuf(&_buf); }; ///Copy construct from a pipe. basic_opstream(const pipe_type & p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(p) { std::basic_ostream<CharT, Traits>::rdbuf(&_buf); }; ///Copy assignment. basic_opstream& operator=(const basic_opstream & ) = delete; ///Move assignment basic_opstream& operator=(basic_opstream && lhs) { std::basic_ostream<CharT, Traits>::operator=(std::move(lhs)); _buf = std::move(lhs._buf); std::basic_ostream<CharT, Traits>::rdbuf(&_buf); return *this; }; ///Move assignment of a pipe. basic_opstream& operator=(pipe_type && p) { _buf = std::move(p); return *this; } ///Copy assignment of a pipe. basic_opstream& operator=(const pipe_type & p) { _buf = p; return *this; } ///Set the pipe of the streambuf. void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } ///Set the pipe of the streambuf. void pipe(const pipe_type& p) {_buf.pipe(p); } ///Get a reference to the pipe. pipe_type & pipe() & {return _buf.pipe();} ///Get a const reference to the pipe. const pipe_type &pipe() const & {return _buf.pipe();} ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe_type && pipe() && {return std::move(_buf).pipe();} ///Open a new pipe void open() { if (_buf.open() == nullptr) this->setstate(std::ios_base::failbit); else this->clear(); } ///Open a new named pipe void open(const std::string & name) { if (_buf.open() == nullptr) this->setstate(std::ios_base::failbit); else this->clear(); } ///Flush the buffer & close the pipe void close() { if (_buf.close() == nullptr) this->setstate(std::ios_base::failbit); } }; typedef basic_opstream<char> opstream; typedef basic_opstream<wchar_t> wopstream; /** Implementation of a read-write pipe stream. * */ template< class CharT, class Traits = std::char_traits<CharT> > class basic_pstream : public std::basic_iostream<CharT, Traits> { mutable basic_pipebuf<CharT, Traits> _buf; public: typedef basic_pipe<CharT, Traits> pipe_type; typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; ///Get access to the underlying stream_buf basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;}; ///Default constructor. basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr) { std::basic_iostream<CharT, Traits>::rdbuf(&_buf); }; ///Copy constructor. basic_pstream(const basic_pstream & ) = delete; ///Move constructor. basic_pstream(basic_pstream && lhs) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf)) { std::basic_iostream<CharT, Traits>::rdbuf(&_buf); } ///Move construct from a pipe. basic_pstream(pipe_type && p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p)) { std::basic_iostream<CharT, Traits>::rdbuf(&_buf); }; ///Copy construct from a pipe. basic_pstream(const pipe_type & p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(p) { std::basic_iostream<CharT, Traits>::rdbuf(&_buf); }; ///Copy assignment. basic_pstream& operator=(const basic_pstream & ) = delete; ///Move assignment basic_pstream& operator=(basic_pstream && lhs) { std::basic_istream<CharT, Traits>::operator=(std::move(lhs)); _buf = std::move(lhs._buf); std::basic_iostream<CharT, Traits>::rdbuf(&_buf); return *this; }; ///Move assignment of a pipe. basic_pstream& operator=(pipe_type && p) { _buf = std::move(p); return *this; } ///Copy assignment of a pipe. basic_pstream& operator=(const pipe_type & p) { _buf = p; return *this; } ///Set the pipe of the streambuf. void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } ///Set the pipe of the streambuf. void pipe(const pipe_type& p) {_buf.pipe(p); } ///Get a reference to the pipe. pipe_type & pipe() & {return _buf.pipe();} ///Get a const reference to the pipe. const pipe_type &pipe() const & {return _buf.pipe();} ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe_type && pipe() && {return std::move(_buf).pipe();} ///Open a new pipe void open() { if (_buf.open() == nullptr) this->setstate(std::ios_base::failbit); else this->clear(); } ///Open a new named pipe void open(const std::string & name) { if (_buf.open() == nullptr) this->setstate(std::ios_base::failbit); else this->clear(); } ///Flush the buffer & close the pipe void close() { if (_buf.close() == nullptr) this->setstate(std::ios_base::failbit); } }; typedef basic_pstream<char> pstream; typedef basic_pstream<wchar_t> wpstream; }} #endif cmd.hpp 0000644 00000006000 15125237361 0006021 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_CMD_LINE_HPP #define BOOST_PROCESS_DETAIL_CMD_LINE_HPP #include <boost/winapi/config.hpp> #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/traits/cmd_or_exe.hpp> #include <boost/process/detail/traits/wchar_t.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/cmd.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/cmd.hpp> #endif /** \file boost/process/cmd.hpp * * This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property. * \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>; } } </programlisting> \endxmlonly */ namespace boost { namespace process { namespace detail { struct cmd_ { constexpr cmd_() = default; template<typename Char> inline api::cmd_setter_<Char> operator()(const Char *s) const { return api::cmd_setter_<Char>(s); } template<typename Char> inline api::cmd_setter_<Char> operator= (const Char *s) const { return api::cmd_setter_<Char>(s); } template<typename Char> inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const { return api::cmd_setter_<Char>(s); } template<typename Char> inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const { return api::cmd_setter_<Char>(s); } }; template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {}; template<> struct char_converter<char, api::cmd_setter_<wchar_t>> { static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in) { return { ::boost::process::detail::convert(in.str()) }; } }; template<> struct char_converter<wchar_t, api::cmd_setter_<char>> { static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in) { return { ::boost::process::detail::convert(in.str()) }; } }; } /** The cmd property allows to explicitly set commands for the execution. The overload form applies when only one string is passed to a launching function. The string will be internally parsed and split at spaces. The following expressions are valid, with `value` being either a C-String or a `std::basic_string` with `char` or `wchar_t`. \code{.cpp} cmd="value"; cmd(value); \endcode The property can only be used for assignments. */ constexpr static ::boost::process::detail::cmd_ cmd; }} #endif error.hpp 0000644 00000015001 15125237361 0006410 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_ERROR_HPP #define BOOST_PROCESS_DETAIL_ERROR_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/traits.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/handler.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/handler.hpp> #endif #include <system_error> #include <type_traits> #include <boost/fusion/algorithm/query/find_if.hpp> #include <boost/fusion/sequence/intrinsic/begin.hpp> #include <boost/fusion/sequence/intrinsic/end.hpp> #include <boost/fusion/container/vector/convert.hpp> #include <boost/fusion/iterator/deref.hpp> #include <boost/fusion/sequence/comparison/equal_to.hpp> #include <boost/fusion/container/set/convert.hpp> #include <boost/type_index.hpp> /** \file boost/process/error.hpp * * Header which provides the error properties. It allows to explicitly set the error handling, the properties are: * \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::ignore_error">ignore_error</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::throw_on_error">throw_on_error</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::error">error</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::error_ref">error_ref</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::error_code">error_code</globalname>; } } </programlisting> \endxmlonly * For error there are two aliases: error_ref and error_code */ namespace boost { namespace process { namespace detail { struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext { constexpr throw_on_error_() = default; template <class Executor> void on_error(Executor&, const std::error_code & ec) const { throw process_error(ec, "process creation failed"); } const throw_on_error_ &operator()() const {return *this;} }; struct ignore_error_ : ::boost::process::detail::api::handler_base_ext { constexpr ignore_error_() = default; }; struct set_on_error : ::boost::process::detail::api::handler_base_ext { set_on_error(const set_on_error&) = default; explicit set_on_error(std::error_code &ec) : ec_(ec) {} template <class Executor> void on_error(Executor&, const std::error_code & ec) const noexcept { ec_ = ec; } private: std::error_code &ec_; }; struct error_ { constexpr error_() = default; set_on_error operator()(std::error_code &ec) const {return set_on_error(ec);} set_on_error operator= (std::error_code &ec) const {return set_on_error(ec);} }; template<typename T> struct is_error_handler : std::false_type {}; template<> struct is_error_handler<set_on_error> : std::true_type {}; template<> struct is_error_handler<throw_on_error_> : std::true_type {}; template<> struct is_error_handler<ignore_error_> : std::true_type {}; template<typename Iterator, typename End> struct has_error_handler_impl { typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type; typedef typename std::remove_reference<ref_type>::type res_type_; typedef typename std::remove_cv<res_type_>::type res_type; typedef typename is_error_handler<res_type>::type cond; typedef typename boost::fusion::result_of::next<Iterator>::type next_itr; typedef typename has_error_handler_impl<next_itr, End>::type next; typedef typename boost::mpl::or_<cond, next>::type type; }; template<typename Iterator> struct has_error_handler_impl<Iterator, Iterator> { typedef boost::mpl::false_ type; }; template<typename Sequence> struct has_error_handler { typedef typename boost::fusion::result_of::as_vector<Sequence>::type vector_type; typedef typename has_error_handler_impl< typename boost::fusion::result_of::begin<vector_type>::type, typename boost::fusion::result_of::end< vector_type>::type >::type type; }; template<typename Sequence> struct has_ignore_error { typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type; typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_>::type type1; typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_&>::type type2; typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type type3; typedef typename boost::mpl::or_<type1,type2, type3>::type type; }; struct error_builder { std::error_code *err; typedef set_on_error result_type; set_on_error get_initializer() {return set_on_error(*err);}; void operator()(std::error_code & ec) {err = &ec;}; }; template<> struct initializer_tag<std::error_code> { typedef error_tag type; }; template<> struct initializer_builder<error_tag> { typedef error_builder type; }; } /**The ignore_error property will disable any error handling. This can be useful on linux, where error handling will require a pipe.*/ constexpr boost::process::detail::ignore_error_ ignore_error; /**The throw_on_error property will enable the exception when launching a process. It is unnecessary by default, but may be used, when an additional error_code is provided.*/ constexpr boost::process::detail::throw_on_error_ throw_on_error; /** The error property will set the executor to handle any errors by setting an [std::error_code](http://en.cppreference.com/w/cpp/error/error_code). \code{.cpp} std::error_code ec; system("gcc", error(ec)); \endcode The following syntax is valid: \code{.cpp} error(ec); error=ec; \endcode The overload version is achieved by just passing an object of [std::error_code](http://en.cppreference.com/w/cpp/error/error_code) to the function. */ constexpr boost::process::detail::error_ error; ///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly . constexpr boost::process::detail::error_ error_ref; ///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly . constexpr boost::process::detail::error_ error_code; }} #endif exe.hpp 0000644 00000004750 15125237361 0006051 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_EXE_HPP #define BOOST_PROCESS_EXE_HPP #include <boost/process/detail/basic_cmd.hpp> /** \file boost/process/exe.hpp * * Header which provides the exe property. \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::exe">exe</globalname>; } } </programlisting> \endxmlonly */ namespace boost { namespace filesystem { class path; } namespace process { namespace detail { struct exe_ { template<typename = void> inline exe_setter_<typename boost::filesystem::path::value_type> operator()(const boost::filesystem::path & pth) const { return exe_setter_<typename boost::filesystem::path::value_type>(pth.native()); } template<typename = void> inline exe_setter_<typename boost::filesystem::path::value_type> operator=(const boost::filesystem::path & pth) const { return exe_setter_<typename boost::filesystem::path::value_type>(pth.native()); } template<typename Char> inline exe_setter_<Char> operator()(const Char *s) const { return exe_setter_<Char>(s); } template<typename Char> inline exe_setter_<Char> operator= (const Char *s) const { return exe_setter_<Char>(s); } template<typename Char> inline exe_setter_<Char> operator()(const std::basic_string<Char> &s) const { return exe_setter_<Char>(s); } template<typename Char> inline exe_setter_<Char> operator= (const std::basic_string<Char> &s) const { return exe_setter_<Char>(s); } }; } /** The exe property allows to explicitly set the executable. The overload form applies when to the first, when several strings are passed to a launching function. The following expressions are valid, with `value` being either a C-String or a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`. \code{.cpp} exe="value"; exe(value); \endcode The property can only be used for assignments. */ constexpr boost::process::detail::exe_ exe{}; }} #endif exception.hpp 0000644 00000001306 15125237361 0007260 0 ustar 00 // Copyright (c) 2016 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_EXCEPTION_HPP_ #define BOOST_PROCESS_EXCEPTION_HPP_ #include <system_error> namespace boost { namespace process { ///The exception usually thrown by boost.process. /** It merely inherits [std::system_error](http://en.cppreference.com/w/cpp/error/system_error) * but can then be distinguished in the catch-block from other system errors. * */ struct process_error : std::system_error { using std::system_error::system_error; }; } } #endif /* BOOST_PROCESS_EXCEPTION_HPP_ */ io.hpp 0000644 00000047026 15125237361 0005702 0 ustar 00 // Copyright (c) 2016 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_IO_HPP_ #define BOOST_PROCESS_IO_HPP_ #include <iosfwd> #include <cstdio> #include <functional> #include <utility> #include <boost/process/detail/config.hpp> #include <boost/process/pipe.hpp> #include <future> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/asio_fwd.hpp> #include <boost/process/detail/posix/close_in.hpp> #include <boost/process/detail/posix/close_out.hpp> #include <boost/process/detail/posix/null_in.hpp> #include <boost/process/detail/posix/null_out.hpp> #include <boost/process/detail/posix/file_in.hpp> #include <boost/process/detail/posix/file_out.hpp> #include <boost/process/detail/posix/pipe_in.hpp> #include <boost/process/detail/posix/pipe_out.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/asio_fwd.hpp> #include <boost/process/detail/windows/close_in.hpp> #include <boost/process/detail/windows/close_out.hpp> #include <boost/process/detail/windows/null_in.hpp> #include <boost/process/detail/windows/null_out.hpp> #include <boost/process/detail/windows/file_in.hpp> #include <boost/process/detail/windows/file_out.hpp> #include <boost/process/detail/windows/pipe_in.hpp> #include <boost/process/detail/windows/pipe_out.hpp> #endif /** \file boost/process/io.hpp * * Header which provides the io properties. It provides the following properties: * \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <globalname alt="boost::process::close">close</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::null">null</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_in">std_in</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_out">std_out</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_err">std_err</globalname>; } } </programlisting> \endxmlonly \par File I/O The library allows full redirection of streams to files as shown below. \code{.cpp} boost::filesystem::path log = "my_log_file.txt"; boost::filesystem::path input = "input.txt"; boost::filesystem::path output = "output.txt"; system("my_prog", std_out>output, std_in<input, std_err>log); \endcode \par Synchronous Pipe I/O Another way is to communicate through pipes. \code{.cpp} pstream str; child c("my_prog", std_out > str); int i; str >> i; \endcode Note that the pipe may also be used between several processes, like this: \code{.cpp} pipe p; child c1("nm", "a.out", std_out>p); child c2("c++filt", std_in<p); \endcode \par Asynchronous I/O Utilizing `boost.asio` asynchronous I/O is provided. \code boost::asio::io_context ios; std::future<std::string> output; system("ls", std_out > output, ios); auto res = fut.get(); \endcode \note `boost/process/async.hpp` must also be included for this to work. \par Closing Stream can be closed, so nothing can be read or written. \code{.cpp} system("foo", std_in.close()); \endcode \par Null Streams can be redirected to null, which means, that written date will be discarded and read data will only contain `EOF`. \code{.cpp} system("b2", std_out > null); \endcode * */ namespace boost { namespace process { namespace detail { template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type; template<typename T> using is_const_buffer = std::integral_constant<bool, std::is_same< boost::asio::const_buffer, T>::value | std::is_base_of<boost::asio::const_buffer, T>::value >; template<typename T> using is_mutable_buffer = std::integral_constant<bool, std::is_same< boost::asio::mutable_buffer, T>::value | std::is_base_of<boost::asio::mutable_buffer, T>::value >; struct null_t {constexpr null_t() = default;}; struct close_t; template<class> struct std_in_ { constexpr std_in_() = default; api::close_in close() const {return api::close_in(); } api::close_in operator=(const close_t &) const {return api::close_in();} api::close_in operator<(const close_t &) const {return api::close_in();} api::null_in null() const {return api::null_in();} api::null_in operator=(const null_t &) const {return api::null_in();} api::null_in operator<(const null_t &) const {return api::null_in();} api::file_in operator=(const boost::filesystem::path &p) const {return p;} api::file_in operator=(const std::string & p) const {return p;} api::file_in operator=(const std::wstring &p) const {return p;} api::file_in operator=(const char * p) const {return p;} api::file_in operator=(const wchar_t * p) const {return p;} api::file_in operator<(const boost::filesystem::path &p) const {return p;} api::file_in operator<(const std::string &p) const {return p;} api::file_in operator<(const std::wstring &p) const {return p;} api::file_in operator<(const char*p) const {return p;} api::file_in operator<(const wchar_t * p) const {return p;} api::file_in operator=(FILE * f) const {return f;} api::file_in operator<(FILE * f) const {return f;} template<typename Char, typename Traits> api::pipe_in operator=(basic_pipe<Char, Traits> & p) const {return p;} template<typename Char, typename Traits> api::pipe_in operator<(basic_pipe<Char, Traits> & p) const {return p;} template<typename Char, typename Traits> api::pipe_in operator=(basic_opstream<Char, Traits> & p) const {return p.pipe();} template<typename Char, typename Traits> api::pipe_in operator<(basic_opstream<Char, Traits> & p) const {return p.pipe();} template<typename Char, typename Traits> api::pipe_in operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();} template<typename Char, typename Traits> api::pipe_in operator<(basic_pstream <Char, Traits> & p) const {return p.pipe();} api::async_pipe_in operator=(async_pipe & p) const {return p;} api::async_pipe_in operator<(async_pipe & p) const {return p;} template<typename T, typename = typename std::enable_if< is_const_buffer<T>::value || is_mutable_buffer<T>::value >::type> api::async_in_buffer<const T> operator=(const T & buf) const {return buf;} template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type > api::async_in_buffer<T> operator=(T & buf) const {return buf;} template<typename T, typename = typename std::enable_if< is_const_buffer<T>::value || is_mutable_buffer<T>::value >::type> api::async_in_buffer<const T> operator<(const T & buf) const {return buf;} template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type > api::async_in_buffer<T> operator<(T & buf) const {return buf;} }; //-1 == empty. //1 == stdout //2 == stderr template<int p1, int p2 = -1> struct std_out_ { constexpr std_out_() = default; api::close_out<p1,p2> close() const {return api::close_out<p1,p2>(); } api::close_out<p1,p2> operator=(const close_t &) const {return api::close_out<p1,p2>();} api::close_out<p1,p2> operator>(const close_t &) const {return api::close_out<p1,p2>();} api::null_out<p1,p2> null() const {return api::null_out<p1,p2>();} api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();} api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();} api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator>(const wchar_t * p) const {return api::file_out<p1,p2>(p);} api::file_out<p1,p2> operator=(FILE * f) const {return f;} api::file_out<p1,p2> operator>(FILE * f) const {return f;} template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pipe<Char, Traits> & p) const {return p;} template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pipe<Char, Traits> & p) const {return p;} template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_ipstream<Char, Traits> & p) const {return p.pipe();} template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_ipstream<Char, Traits> & p) const {return p.pipe();} template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();} template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pstream <Char, Traits> & p) const {return p.pipe();} api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;} api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;} api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;} api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;} api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;} api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;} api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;} api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;} api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;} api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;} api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;} api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;} template<int pin, typename = typename std::enable_if< (((p1 == 1) && (pin == 2)) || ((p1 == 2) && (pin == 1))) && (p2 == -1)>::type> constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const { return std_out_<1, 2> (); } }; struct close_t { constexpr close_t() = default; template<int T, int U> api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();} }; } ///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams. constexpr boost::process::detail::close_t close; ///This constant is a utility to redirect streams to the null-device. constexpr boost::process::detail::null_t null; /** This property allows to set the input stream for the child process. \section stdin_details Details \subsection stdin_file File Input The file I/O simple redirects the stream to a file, for which the possible types are - `boost::filesystem::path` - `std::basic_string<char_type>` - `const char_type*` - `FILE*` with `char_type` being either `char` or `wchar_t`. FILE* is explicitly added, so the process can easily redirect the output stream of the child to another output stream of the process. That is: \code{.cpp} system("ls", std_in < stdin); \endcode \warning If the launching and the child process use the input, this leads to undefined behaviour. A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++ implementation not providing access to the handle. The valid expressions for this property are \code{.cpp} std_in < file; std_in = file; \endcode \subsection stdin_pipe Pipe Input As explained in the corresponding section, the boost.process library provides a @ref boost::process::async_pipe "async_pipe" class which can be used to communicate with child processes. \note Technically the @ref boost::process::async_pipe "async_pipe" works synchronous here, since no asio implementation is used by the library here. The async-operation will then however not end if the process is finished, since the pipe remains open. You can use the async_close function with on_exit to fix that. Valid expressions with pipes are these: \code{.cpp} std_in < pipe; std_in = pipe; \endcode Where the valid types for `pipe` are the following: - `basic_pipe` - `async_pipe` - `basic_opstream` - `basic_pstream` Note that the pipe may also be used between several processes, like this: \code{.cpp} pipe p; child c1("nm", "a.out", std_out>p); child c2("c++filt", std_in<p); \endcode \subsection stdin_async_pipe Asynchronous Pipe Input Asynchronous Pipe I/O classifies communication which has automatically handling of the asynchronous operations by the process library. This means, that a pipe will be constructed, the async_read/-write will be automatically started, and that the end of the child process will also close the pipe. Valid types for pipe I/O are the following: - `boost::asio::const_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly - `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly - `boost::asio::streambuf` Valid expressions with pipes are these: \code{.cpp} std_in < buffer; std_in = buffer; std_out > buffer; std_out = buffer; std_err > buffer; std_err = buffer; (std_out & std_err) > buffer; (std_out & std_err) = buffer; \endcode \note It is also possible to get a future for std_in, by chaining another `std::future<void>` onto it, so you can wait for the input to be completed. It looks like this: \code{.cpp} std::future<void> fut; boost::asio::io_context ios; std::string data; child c("prog", std_in < buffer(data) > fut, ios); fut.get(); \endcode \note `boost::asio::buffer` is also available in the `boost::process` namespace. \warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_context` to be passed to the launching function. \subsection stdin_close Close The input stream can be closed, so it cannot be read from. This will lead to an error when attempted. This can be achieved by the following syntax. \code{.cpp} std_in < close; std_in = close; std_in.close(); \endcode \subsection stdin_null Null The input stream can be redirected to read from the null-device, which means that only `EOF` is read. The syntax to achieve that has the following variants: \code{.cpp} std_in < null; std_in = null; std_in.null(); \endcode */ constexpr boost::process::detail::std_in_<void> std_in; /** This property allows to set the output stream for the child process. \note The Semantic is the same as for \xmlonly <globalname alt="boost::process::std_err">std_err</globalname> \endxmlonly \note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`. \section stdout_details Details \subsection stdout_file File Input The file I/O simple redirects the stream to a file, for which the possible types are - `boost::filesystem::path` - `std::basic_string<char_type>` - `const char_type*` - `FILE*` with `char_type` being either `char` or `wchar_t`. FILE* is explicitly added, so the process can easily redirect the output stream of the child to another output stream of the process. That is: \code{.cpp} system("ls", std_out < stdin); \endcode \warning If the launching and the child process use the input, this leads to undefined behaviour. A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++ implementation not providing access to the handle. The valid expressions for this property are \code{.cpp} std_out < file; std_out = file; \endcode \subsection stdout_pipe Pipe Output As explained in the corresponding section, the boost.process library provides a @ref boost::process::async_pipe "async_pipe" class which can be used to communicate with child processes. \note Technically the @ref boost::process::async_pipe "async_pipe" works like a synchronous pipe here, since no asio implementation is used by the library here. The asynchronous operation will then however not end if the process is finished, since the pipe remains open. You can use the async_close function with on_exit to fix that. Valid expressions with pipes are these: \code{.cpp} std_out > pipe; std_out = pipe; \endcode Where the valid types for `pipe` are the following: - `basic_pipe` - `async_pipe` - `basic_ipstream` - `basic_pstream` Note that the pipe may also be used between several processes, like this: \code{.cpp} pipe p; child c1("nm", "a.out", std_out>p); child c2("c++filt", std_in<p); \endcode \subsection stdout_async_pipe Asynchronous Pipe Output Asynchronous Pipe I/O classifies communication which has automatically handling of the async operations by the process library. This means, that a pipe will be constructed, the async_read/-write will be automatically started, and that the end of the child process will also close the pipe. Valid types for pipe I/O are the following: - `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly - `boost::asio::streambuf` - `std::future<std::vector<char>>` - `std::future<std::string>` Valid expressions with pipes are these: \code{.cpp} std_out > buffer; std_out = buffer; std_err > buffer; std_err = buffer; (std_out & std_err) > buffer; (std_out & std_err) = buffer; \endcode \note `boost::asio::buffer` is also available in the `boost::process` namespace. \warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_context` to be passed to the launching function. \subsection stdout_close Close The out stream can be closed, so it cannot be write from. This will lead to an error when attempted. This can be achieved by the following syntax. \code{.cpp} std_out > close; std_out = close; std_out.close(); \endcode \subsection stdout_null Null The output stream can be redirected to write to the null-device, which means that all output is discarded. The syntax to achieve that has the following variants: \code{.cpp} std_out > null; std_out = null; std_out.null(); \endcode */ constexpr boost::process::detail::std_out_<1> std_out; /**This property allows setting the `stderr` stream. The semantic and syntax is the same as for * \xmlonly <globalname alt="boost::process::std_out">std_out</globalname> \endxmlonly . */ constexpr boost::process::detail::std_out_<2> std_err; }} #endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */ detail/handler_base.hpp 0000644 00000002637 15125237361 0011143 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_HANDLER_BASE_HPP #define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP #include <system_error> namespace boost { namespace process { namespace detail { template<template <class> class Template> struct make_handler_t { constexpr make_handler_t() {} template<typename Handler> constexpr Template<Handler> operator()(Handler handler) const {return Template<Handler>(handler);} template<typename Handler> constexpr Template<Handler> operator= (Handler handler) const {return Template<Handler>(handler);} template<typename Handler> constexpr Template<Handler> operator+=(Handler handler) const {return Template<Handler>(handler);} }; struct handler_base { using resource_type = void; template <class Executor> void on_setup(Executor&) const {} template <class Executor> void on_error(Executor&, const std::error_code &) const {} template <class Executor> void on_success(Executor&) const {} }; }}} #endif detail/handler.hpp 0000644 00000002671 15125237361 0010147 0 ustar 00 // Copyright (c) 2016 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_HANDLER_HPP_ #define BOOST_PROCESS_DETAIL_HANDLER_HPP_ #include <boost/process/detail/config.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/handler.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/handler.hpp> #endif namespace boost { namespace process { namespace detail { //extended handler base. typedef api::handler_base_ext handler; template <class Handler> struct on_setup_ : handler { explicit on_setup_(Handler handler) : handler_(handler) {} template <class Executor> void on_setup(Executor &e) { handler_(e); } private: Handler handler_; }; template <class Handler> struct on_error_ : handler { explicit on_error_(Handler handler) : handler_(handler) {} template <class Executor> void on_error(Executor &e, const std::error_code &ec) { handler_(e, ec); } private: Handler handler_; }; template <class Handler> struct on_success_ : handler { explicit on_success_(Handler handler) : handler_(handler) {} template <class Executor> void on_success(Executor &e) { handler_(e); } private: Handler handler_; }; } }} #endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */ detail/config.hpp 0000644 00000006136 15125237361 0007777 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/config.hpp * * Defines various macros. */ #ifndef BOOST_PROCESS_DETAIL_CONFIG_HPP #define BOOST_PROCESS_DETAIL_CONFIG_HPP #include <boost/config.hpp> #include <system_error> #include <boost/system/api_config.hpp> #include <boost/process/exception.hpp> #if defined(BOOST_POSIX_API) #include <errno.h> #if defined(__GLIBC__) #include <features.h> #else extern char **environ; #endif #elif defined(BOOST_WINDOWS_API) #include <boost/winapi/get_last_error.hpp> #else #error "System API not supported by boost.process" #endif namespace boost { namespace process { namespace detail { #if !defined(BOOST_PROCESS_PIPE_SIZE) #define BOOST_PROCESS_PIPE_SIZE 1024 #endif #if defined(BOOST_POSIX_API) namespace posix {namespace extensions {}} namespace api = posix; inline std::error_code get_last_error() noexcept { return std::error_code(errno, std::system_category()); } //copied from linux spec. #if (_XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) #define BOOST_POSIX_HAS_VFORK 1 #endif #if (_POSIX_C_SOURCE >= 199309L) #define BOOST_POSIX_HAS_SIGTIMEDWAIT 1 #endif #elif defined(BOOST_WINDOWS_API) namespace windows {namespace extensions {}} namespace api = windows; inline std::error_code get_last_error() noexcept { return std::error_code(::boost::winapi::GetLastError(), std::system_category()); } #endif inline void throw_last_error(const std::string & msg) { throw process_error(get_last_error(), msg); } inline void throw_last_error(const char * msg) { throw process_error(get_last_error(), msg); } inline void throw_last_error() { throw process_error(get_last_error()); } inline void throw_error(const std::error_code& ec) { if (ec) throw process_error(ec); } inline void throw_error(const std::error_code& ec, const char* msg) { if (ec) throw process_error(ec, msg); } template<typename Char> constexpr Char null_char(); template<> constexpr char null_char<char> (){return '\0';} template<> constexpr wchar_t null_char<wchar_t> (){return L'\0';} template<typename Char> constexpr Char equal_sign(); template<> constexpr char equal_sign<char> () {return '='; } template<> constexpr wchar_t equal_sign<wchar_t> () {return L'='; } template<typename Char> constexpr Char quote_sign(); template<> constexpr char quote_sign<char> () {return '"'; } template<> constexpr wchar_t quote_sign<wchar_t> () {return L'"'; } template<typename Char> constexpr Char space_sign(); template<> constexpr char space_sign<char> () {return ' '; } template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; } }}} #endif detail/traits/group.hpp 0000644 00000001257 15125237361 0011173 0 ustar 00 // Copyright (c) 2016 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_TRAITS_GROUP_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/traits/decl.hpp> namespace boost { namespace process { struct group; namespace detail { struct group_tag {}; template<> struct make_initializer_t<group_tag>; template<> struct initializer_tag_t<::boost::process::group> { typedef group_tag type;}; }}} #endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */ detail/traits/wchar_t.hpp 0000644 00000016473 15125237361 0011474 0 ustar 00 // Copyright (c) 2016 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_TRAITS_WCHAR_T_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_ #include <boost/process/detail/traits/decl.hpp> #include <boost/process/detail/traits/cmd_or_exe.hpp> #include <boost/process/detail/traits/env.hpp> #include <boost/process/locale.hpp> namespace boost { namespace process { namespace detail { //template template<typename T> struct is_wchar_t : std::false_type {}; template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename boost::filesystem::path::value_type, wchar_t> { }; template<> struct is_wchar_t<const wchar_t* > : std::true_type {}; template<> struct is_wchar_t<wchar_t* > : std::true_type {}; template<std::size_t Size> struct is_wchar_t<const wchar_t [Size]> : std::true_type {}; template<std::size_t Size> struct is_wchar_t<const wchar_t (&)[Size]> : std::true_type {}; template<> struct is_wchar_t<std::wstring> : std::true_type {}; template<> struct is_wchar_t<std::vector<std::wstring>> : std::true_type {}; template<> struct is_wchar_t<std::initializer_list<std::wstring>> : std::true_type {}; template<> struct is_wchar_t<std::vector<wchar_t *>> : std::true_type {}; template<> struct is_wchar_t<std::initializer_list<wchar_t *>> : std::true_type {}; template<typename Char, typename T> struct char_converter { static T& conv(T & in) { return in; } static T&& conv(T&& in) { return std::move(in); } static const T& conv(const T & in) { return in; } }; template<typename Char, typename T> using char_converter_t = char_converter<Char, typename std::remove_cv<typename std::remove_reference<T>::type>::type>; template<> struct char_converter<char, const wchar_t*> { static std::string conv(const wchar_t* in) { std::size_t size = 0; while (in[size] != L'\0') size++; return ::boost::process::detail::convert(in, in + size); } }; template<> struct char_converter<char, wchar_t*> { static std::string conv(wchar_t* in) { std::size_t size = 0; while (in[size] != L'\0') size++; return ::boost::process::detail::convert(in, in + size); } }; template<std::size_t Size> struct char_converter<char, wchar_t[Size]> { static std::string conv(const wchar_t(&in)[Size]) { return ::boost::process::detail::convert(in, in + Size -1); } }; template<> struct char_converter<wchar_t, const char*> { static std::wstring conv(const char* in) { std::size_t size = 0; while (in[size] != '\0') size++; return ::boost::process::detail::convert(in, in + size); } }; template<> struct char_converter<wchar_t, char*> { static std::wstring conv(char* in) { std::size_t size = 0; while (in[size] != '\0') size++; return ::boost::process::detail::convert(in, in + size); } }; template<std::size_t Size> struct char_converter<wchar_t, char[Size]> { static std::wstring conv(const char(&in)[Size]) { return ::boost::process::detail::convert(in, in + Size -1); } }; //all the containers. template<> struct char_converter<wchar_t, std::string> { static std::wstring conv(const std::string & in) { return ::boost::process::detail::convert(in); } }; template<> struct char_converter<char, std::wstring> { static std::string conv(const std::wstring & in) { return ::boost::process::detail::convert(in); } }; template<> struct char_converter<wchar_t, std::vector<std::string>> { static std::vector<std::wstring> conv(const std::vector<std::string> & in) { std::vector<std::wstring> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const std::string & st) { return convert(st); }); return ret; } }; template<> struct char_converter<wchar_t, std::initializer_list<std::string>> { static std::vector<std::wstring> conv(const std::initializer_list<std::string> & in) { std::vector<std::wstring> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const std::string & st) { return convert(st); }); return ret; } }; template<> struct char_converter<wchar_t, std::vector<char* >> { static std::vector<std::wstring> conv(const std::vector<char* > & in) { std::vector<std::wstring> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const char* st) { std::size_t sz = 0; while (st[sz] != '\0') sz++; return convert(st, st + sz); }); return ret; } }; template<> struct char_converter<wchar_t, std::initializer_list<char *>> { static std::vector<std::wstring> conv(const std::initializer_list<char * > & in) { std::vector<std::wstring> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const char* st) { std::size_t sz = 0; while (st[sz] != '\0') sz++; return convert(st, st + sz); }); return ret; } }; template<> struct char_converter<char, std::vector<std::wstring>> { static std::vector<std::string> conv(const std::vector<std::wstring> & in) { std::vector<std::string> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const std::wstring & st) { return convert(st); }); return ret; } }; template<> struct char_converter<char, std::initializer_list<std::wstring>> { static std::vector<std::string> conv(const std::initializer_list<std::wstring> & in) { std::vector<std::string> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const std::wstring & st) { return convert(st); }); return ret; } }; template<> struct char_converter<char, std::vector<wchar_t* >> { static std::vector<std::string> conv(const std::vector<wchar_t* > & in) { std::vector<std::string> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const wchar_t* st) { std::size_t sz = 0; while (st[sz] != L'\0') sz++; return convert(st, st + sz); }); return ret; } }; template<> struct char_converter<char, std::initializer_list<wchar_t * >> { static std::vector<std::string> conv(const std::initializer_list<wchar_t *> & in) { std::vector<std::string> ret(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [](const wchar_t* st) { std::size_t sz = 0; while (st[sz] != L'\0') sz++; return convert(st, st + sz); }); return ret; } }; }}} #endif /* BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_ */ detail/traits/env.hpp 0000644 00000003021 15125237361 0010616 0 ustar 00 // Copyright (c) 2016 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_TRAITS_ENV_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_ #include <boost/process/detail/traits/decl.hpp> namespace boost { namespace process { template<typename Char> class basic_environment; template<typename Char> class basic_native_environment; namespace detail { template<typename Char> struct env_tag {}; template<typename Char> struct env_set; template<typename Char> struct env_append; template<typename Char> struct env_reset; template<typename Char> struct env_init; template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; }; template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; }; template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;}; template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;}; template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; }; template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; }; template<> struct initializer_builder<env_tag<char>>; template<> struct initializer_builder<env_tag<wchar_t>>; } }} #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */ detail/traits/error.hpp 0000644 00000001130 15125237361 0011156 0 ustar 00 // Copyright (c) 2016 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_TRAITS_ERROR_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_ #include <boost/process/detail/config.hpp> #include <system_error> #include <boost/process/detail/traits/decl.hpp> namespace boost { namespace process { namespace detail { struct error_tag; template<> struct initializer_tag<std::error_code>; }}} #endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */ detail/traits/cmd_or_exe.hpp 0000644 00000007037 15125237361 0012145 0 ustar 00 // Copyright (c) 2016 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_TRAITS_CMD_OR_EXE_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_ #include <string> #include <vector> #include <type_traits> #include <initializer_list> #include <boost/filesystem/path.hpp> #include <boost/process/detail/traits/decl.hpp> namespace boost { namespace process { namespace detail { template<typename Char> struct cmd_or_exe_tag {}; struct shell_; template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;}; template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;}; template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;}; template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;}; template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;}; template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;}; template<> struct initializer_tag<shell_> { typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type; }; template<> struct initializer_tag<boost::filesystem::path> { typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type; }; template <typename Char> struct exe_setter_; template <typename Char, bool Append = false> struct arg_setter_; template <typename Char, bool Append> struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;}; template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;}; template<> struct initializer_builder<cmd_or_exe_tag<char>>; template<> struct initializer_builder<cmd_or_exe_tag<wchar_t>>; }}} #endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */ detail/traits/decl.hpp 0000644 00000003712 15125237361 0010744 0 ustar 00 // Copyright (c) 2016 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_TRAITS_DECL_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_ #include <boost/process/detail/config.hpp> #include <boost/none.hpp> #include <type_traits> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/handler.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/handler.hpp> #endif namespace boost { namespace process { namespace detail { template<typename T> struct is_initializer : std::is_base_of<handler_base, T> {}; template<typename T> struct is_initializer<T&> : std::is_base_of<handler_base, T> {}; template<typename T> struct initializer_tag;// { typedef void type; }; //remove const template<typename T> struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; }; //remove & template<typename T> struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; }; //remove const & template<typename T> struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; }; template<typename T> struct initializer_builder; template<typename First, typename ...Args> struct valid_argument_list; template<typename First> struct valid_argument_list<First> { constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value; typedef std::integral_constant<bool, value> type; }; template<typename First, typename ...Args> struct valid_argument_list { constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value; constexpr static bool value = valid_argument_list<Args...>::value && my_value; typedef std::integral_constant<bool, value> type; }; }}} #endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */ detail/traits/async.hpp 0000644 00000001326 15125237361 0011151 0 ustar 00 // Copyright (c) 2016 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_TRAITS_ASYNC_HPP_ #define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/traits/decl.hpp> namespace boost { namespace asio { class io_context; }} namespace boost { namespace process { namespace detail { struct async_tag {}; template<> struct initializer_builder<async_tag>; template<> struct initializer_tag<::boost::asio::io_context> { typedef async_tag type;}; }}} #endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */ detail/execute_impl.hpp 0000644 00000020106 15125237361 0011206 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/execute.hpp * * Defines a function to execute a program. */ #ifndef BOOST_PROCESS_EXECUTE_HPP #define BOOST_PROCESS_EXECUTE_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/traits.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/executor.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/executor.hpp> #endif #include <boost/process/detail/basic_cmd.hpp> #include <boost/process/detail/handler.hpp> #include <boost/fusion/view.hpp> #include <boost/fusion/container.hpp> #include <boost/fusion/sequence.hpp> #include <boost/fusion/tuple.hpp> #include <boost/fusion/algorithm/transformation/filter_if.hpp> #include <boost/fusion/adapted/std_tuple.hpp> #include <boost/fusion/container/vector/convert.hpp> #include <type_traits> #include <utility> namespace boost { namespace process { class child; namespace detail { template<typename ...Args> struct has_wchar; template<typename First, typename ...Args> struct has_wchar<First, Args...> { typedef has_wchar<Args...> next; typedef typename std::remove_cv< typename std::remove_reference<First>::type>::type res_type; constexpr static bool my_value = is_wchar_t<res_type>::value; constexpr static bool value = my_value || next::value; typedef std::integral_constant<bool, value> type; }; template<typename First> struct has_wchar<First> { typedef typename std::remove_cv< typename std::remove_reference<First>::type>::type res_type; constexpr static bool value = is_wchar_t<res_type>::value; typedef std::integral_constant<bool, value> type; }; #if defined(BOOST_WINDOWS_API) //everything needs to be wchar_t #if defined(BOOST_NO_ANSI_APIS) template<bool has_wchar> struct required_char_type { typedef wchar_t type; }; #else template<bool has_wchar> struct required_char_type; template<> struct required_char_type<true> { typedef wchar_t type; }; template<> struct required_char_type<false> { typedef char type; }; #endif #elif defined(BOOST_POSIX_API) template<bool has_wchar> struct required_char_type { typedef char type; }; #endif template<typename ... Args> using required_char_type_t = typename required_char_type< has_wchar<Args...>::value>::type; template<typename Iterator, typename End, typename ...Args> struct make_builders_from_view { typedef boost::fusion::set<Args...> set; typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type; typedef typename std::remove_reference<ref_type>::type res_type; typedef typename initializer_tag<res_type>::type tag; typedef typename initializer_builder<tag>::type builder_type; typedef typename boost::fusion::result_of::has_key<set, builder_type> has_key; typedef typename boost::fusion::result_of::next<Iterator>::type next_itr; typedef typename make_builders_from_view<next_itr, End>::type next; typedef typename std::conditional<has_key::value, typename make_builders_from_view<next_itr, End, Args...>::type, typename make_builders_from_view<next_itr, End, Args..., builder_type>::type >::type type; }; template<typename Iterator, typename ...Args> struct make_builders_from_view<Iterator, Iterator, Args...> { typedef boost::fusion::set<Args...> type; }; template<typename Builders> struct builder_ref { Builders &builders; builder_ref(Builders & builders) : builders(builders) {}; template<typename T> void operator()(T && value) const { typedef typename initializer_tag<typename std::remove_reference<T>::type>::type tag; typedef typename initializer_builder<tag>::type builder_type; boost::fusion::at_key<builder_type>(builders)(std::forward<T>(value)); } }; template<typename T> struct get_initializers_result { typedef typename T::result_type type; }; template<> struct get_initializers_result<boost::fusion::void_> { typedef boost::fusion::void_ type; }; template<typename ...Args> struct helper_vector { }; template<typename T, typename ...Stack> struct invoke_get_initializer_collect_keys; template<typename ...Stack> struct invoke_get_initializer_collect_keys<boost::fusion::vector<>, Stack...> { typedef helper_vector<Stack...> type; }; template<typename First, typename ...Args, typename ...Stack> struct invoke_get_initializer_collect_keys<boost::fusion::vector<First, Args...>, Stack...> { typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>, Stack..., First>::type next; typedef helper_vector<Stack...> stack_t; typedef typename std::conditional<std::is_same<boost::fusion::void_, First>::value, stack_t, next>::type type; }; template<typename Keys> struct invoke_get_initializer; template<typename ...Args> struct invoke_get_initializer<helper_vector<Args...>> { typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> result_type; template<typename Sequence> static result_type call(Sequence & seq) { return result_type(boost::fusion::at_key<Args>(seq).get_initializer()...);; } }; template<typename ...Args> inline boost::fusion::tuple<typename get_initializers_result<Args>::type...> get_initializers(boost::fusion::set<Args...> & builders) { //typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> return_type; typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>>::type keys; return invoke_get_initializer<keys>::call(builders); } template<typename Char, typename ... Args> inline child basic_execute_impl(Args && ... args) { //create a tuple from the argument list boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...); auto inits = boost::fusion::filter_if< boost::process::detail::is_initializer< typename std::remove_reference< boost::mpl::_ >::type > >(tup); auto others = boost::fusion::filter_if< boost::mpl::not_< boost::process::detail::is_initializer< typename std::remove_reference< boost::mpl::_ >::type > > >(tup); // typename detail::make_builders_from_view<decltype(others)>::type builders; //typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type inits_t; typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t; // typedef decltype(others) others_t; typedef typename ::boost::process::detail::make_builders_from_view< typename boost::fusion::result_of::begin<others_t>::type, typename boost::fusion::result_of::end <others_t>::type>::type builder_t; builder_t builders; ::boost::process::detail::builder_ref<builder_t> builder_ref(builders); boost::fusion::for_each(others, builder_ref); auto other_inits = ::boost::process::detail::get_initializers(builders); boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits); auto exec = boost::process::detail::api::make_executor<Char>(complete_inits); return exec(); } template<typename ...Args> inline child execute_impl(Args&& ... args) { typedef required_char_type_t<Args...> req_char_type; return basic_execute_impl<req_char_type>( boost::process::detail::char_converter_t<req_char_type, Args>::conv( std::forward<Args>(args))... ); } }}} #endif detail/posix/io_context_ref.hpp 0000644 00000007704 15125237362 0012706 0 ustar 00 // Copyright (c) 2016 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_POSIX_IO_CONTEXT_REF_HPP_ #define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_ #include <boost/process/detail/posix/handler.hpp> #include <boost/process/detail/posix/async_handler.hpp> #include <boost/asio/io_context.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <boost/fusion/algorithm/transformation/filter_if.hpp> #include <boost/fusion/algorithm/transformation/transform.hpp> #include <boost/fusion/view/transform_view.hpp> #include <boost/fusion/container/vector/convert.hpp> #include <boost/process/detail/posix/sigchld_service.hpp> #include <boost/process/detail/posix/is_running.hpp> #include <functional> #include <type_traits> #include <memory> #include <vector> #include <sys/wait.h> namespace boost { namespace process { namespace detail { namespace posix { template<typename Executor> struct on_exit_handler_transformer { Executor & exec; on_exit_handler_transformer(Executor & exec) : exec(exec) {} template<typename Sig> struct result; template<typename T> struct result<on_exit_handler_transformer<Executor>(T&)> { typedef typename T::on_exit_handler_t type; }; template<typename T> auto operator()(T& t) const -> typename T::on_exit_handler_t { return t.on_exit_handler(exec); } }; template<typename Executor> struct async_handler_collector { Executor & exec; std::vector<std::function<void(int, const std::error_code & ec)>> &handlers; async_handler_collector(Executor & exec, std::vector<std::function<void(int, const std::error_code & ec)>> &handlers) : exec(exec), handlers(handlers) {} template<typename T> void operator()(T & t) const { handlers.push_back(t.on_exit_handler(exec)); } }; //Also set's up waiting for the exit, so it can close async stuff. struct io_context_ref : handler_base_ext { io_context_ref(boost::asio::io_context & ios) : ios(ios) { } boost::asio::io_context &get() {return ios;}; template <class Executor> void on_success(Executor& exec) { ios.notify_fork(boost::asio::io_context::fork_parent); //must be on the heap so I can move it into the lambda. auto asyncs = boost::fusion::filter_if< is_async_handler< typename std::remove_reference< boost::mpl::_ > ::type >>(exec.seq); //ok, check if there are actually any. if (boost::fusion::empty(asyncs)) return; std::vector<std::function<void(int, const std::error_code & ec)>> funcs; funcs.reserve(boost::fusion::size(asyncs)); boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs)); auto & es = exec.exit_status; auto wh = [funcs, es](int val, const std::error_code & ec) { es->store(val); for (auto & func : funcs) func(::boost::process::detail::posix::eval_exit_status(val), ec); }; sigchld_service.async_wait(exec.pid, std::move(wh)); } template<typename Executor> void on_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_prepare);*/} template<typename Executor> void on_exec_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_child);*/} template <class Executor> void on_error(Executor&, const std::error_code &) const {/*ios.notify_fork(boost::asio::io_context::fork_parent);*/} private: boost::asio::io_context &ios; boost::process::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::detail::posix::sigchld_service>(ios); }; }}}} #endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */ detail/posix/null_out.hpp 0000644 00000004051 15125237362 0011530 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_POSIX_PIPE_OUT_HPP #define BOOST_PROCESS_POSIX_PIPE_OUT_HPP #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, ::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<> template<typename Executor> void null_out<1,-1>::on_exec_setup(Executor &e) const { if (::dup2(sink.handle(), STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } template<> template<typename Executor> void null_out<2,-1>::on_exec_setup(Executor &e) const { if (::dup2(sink.handle(), STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } template<> template<typename Executor> void null_out<1,2>::on_exec_setup(Executor &e) const { if (::dup2(sink.handle(), STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (::dup2(sink.handle(), STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } }}}} #endif detail/posix/basic_pipe.hpp 0000644 00000013034 15125237362 0011766 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_POSIX_PIPE_HPP #define BOOST_PROCESS_POSIX_PIPE_HPP #include <boost/filesystem.hpp> #include <boost/process/detail/posix/compare_handles.hpp> #include <system_error> #include <array> #include <unistd.h> #include <fcntl.h> #include <memory> namespace boost { namespace process { namespace detail { namespace posix { template<class CharT, class Traits = std::char_traits<CharT>> class basic_pipe { int _source = -1; int _sink = -1; public: explicit basic_pipe(int source, int sink) : _source(source), _sink(sink) {} explicit basic_pipe(int source, int sink, const std::string&) : _source(source), _sink(sink) {} typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; typedef int native_handle_type; basic_pipe() { int fds[2]; if (::pipe(fds) == -1) boost::process::detail::throw_last_error("pipe(2) failed"); _source = fds[0]; _sink = fds[1]; } inline basic_pipe(const basic_pipe& rhs); explicit inline basic_pipe(const std::string& name); basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink) { lhs._source = -1; lhs._sink = -1; } inline basic_pipe& operator=(const basic_pipe& ); basic_pipe& operator=(basic_pipe&& lhs) { _source = lhs._source; _sink = lhs._sink ; lhs._source = -1; lhs._sink = -1; return *this; } ~basic_pipe() { if (_sink != -1) ::close(_sink); if (_source != -1) ::close(_source); } native_handle_type native_source() const {return _source;} native_handle_type native_sink () const {return _sink;} void assign_source(native_handle_type h) { _source = h;} void assign_sink (native_handle_type h) { _sink = h;} int_type write(const char_type * data, int_type count) { int_type write_len; while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1) { //Try again if interrupted auto err = errno; if (err != EINTR) ::boost::process::detail::throw_last_error(); } return write_len; } int_type read(char_type * data, int_type count) { int_type read_len; while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1) { //Try again if interrupted auto err = errno; if (err != EINTR) ::boost::process::detail::throw_last_error(); } return read_len; } bool is_open() const { return (_source != -1) || (_sink != -1); } void close() { if (_source != -1) ::close(_source); if (_sink != -1) ::close(_sink); _source = -1; _sink = -1; } }; template<class CharT, class Traits> basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs) { if (rhs._source != -1) { _source = ::dup(rhs._source); if (_source == -1) ::boost::process::detail::throw_last_error("dup() failed"); } if (rhs._sink != -1) { _sink = ::dup(rhs._sink); if (_sink == -1) ::boost::process::detail::throw_last_error("dup() failed"); } } template<class CharT, class Traits> basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe & rhs) { if (rhs._source != -1) { _source = ::dup(rhs._source); if (_source == -1) ::boost::process::detail::throw_last_error("dup() failed"); } if (rhs._sink != -1) { _sink = ::dup(rhs._sink); if (_sink == -1) ::boost::process::detail::throw_last_error("dup() failed"); } return *this; } template<class CharT, class Traits> basic_pipe<CharT, Traits>::basic_pipe(const std::string & name) { auto fifo = mkfifo(name.c_str(), 0666 ); if (fifo != 0) boost::process::detail::throw_last_error("mkfifo() failed"); int read_fd = open(name.c_str(), O_RDWR); if (read_fd == -1) boost::process::detail::throw_last_error(); int write_fd = dup(read_fd); if (write_fd == -1) boost::process::detail::throw_last_error(); _sink = write_fd; _source = read_fd; ::unlink(name.c_str()); } template<class Char, class Traits> inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } }}}} #endif detail/posix/search_path.hpp 0000644 00000002302 15125237362 0012145 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_POSIX_SEARCH_PATH_HPP #define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP #include <boost/process/detail/config.hpp> #include <boost/filesystem.hpp> #include <boost/tokenizer.hpp> #include <string> #include <stdexcept> #include <stdlib.h> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { inline boost::filesystem::path search_path( const boost::filesystem::path &filename, const std::vector<boost::filesystem::path> &path) { for (const boost::filesystem::path & pp : path) { auto p = pp / filename; boost::system::error_code ec; bool file = boost::filesystem::is_regular_file(p, ec); if (!ec && file && ::access(p.c_str(), X_OK) == 0) return p; } return ""; } }}}} #endif detail/posix/async_out.hpp 0000644 00000013242 15125237362 0011675 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_ASYNC_OUT_HPP #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP #include <boost/process/detail/posix/handler.hpp> #include <boost/asio/posix/stream_descriptor.hpp> #include <boost/asio/read.hpp> #include <boost/process/async_pipe.hpp> #include <istream> #include <memory> #include <exception> #include <future> #include <array> #include <boost/process/detail/used_handles.hpp> namespace boost { namespace process { namespace detail { namespace posix { inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>) { return ::dup2(handle, STDOUT_FILENO); } inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>) { return ::dup2(handle, STDERR_FILENO); } inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>) { if (::dup2(handle, STDOUT_FILENO) == -1) return -1; if (::dup2(handle, STDERR_FILENO) == -1) return -1; return 0; } 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::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) { } template <typename Executor> inline void on_success(Executor &exec) { auto pipe = this->pipe; boost::asio::async_read(*pipe, buf, [pipe](const boost::system::error_code&, std::size_t){}); this->pipe = nullptr; std::move(*pipe).sink().close(); } template<typename Executor> void on_error(Executor &, const std::error_code &) const { std::move(*pipe).sink().close(); } template<typename Executor> void on_setup(Executor & exec) { pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); } template <typename Executor> void on_exec_setup(Executor &exec) { int res = apply_out_handles(pipe->native_sink(), std::integral_constant<int, p1>(), std::integral_constant<int, p2>()); if (res == -1) exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); ::close(pipe->native_sink()); ::close(pipe->native_source()); } }; template<int p1, int p2, typename Type> struct async_out_future : ::boost::process::detail::posix::handler_base_ext, ::boost::process::detail::posix::require_io_context { std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>(); std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>(); std::shared_ptr<boost::process::async_pipe> pipe; async_out_future(std::future<Type> & fut) { fut = promise->get_future(); } template <typename Executor> inline void on_success(Executor &) { auto pipe_ = this->pipe; auto buffer_ = this->buffer; auto promise_ = this->promise; boost::asio::async_read(*pipe_, *buffer_, [pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t) { if (ec && (ec.value() != ENOENT)) { std::error_code e(ec.value(), std::system_category()); promise_->set_exception(std::make_exception_ptr(process_error(e))); } else { std::istream is (buffer_.get()); Type arg; if (buffer_->size() > 0) { arg.resize(buffer_->size()); is.read(&*arg.begin(), buffer_->size()); } promise_->set_value(std::move(arg)); } }); std::move(*pipe_).sink().close(); this->pipe = nullptr; } template<typename Executor> void on_error(Executor &, const std::error_code &) const { std::move(*pipe).sink().close(); } template<typename Executor> void on_setup(Executor & exec) { pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); } template <typename Executor> void on_exec_setup(Executor &exec) { int res = apply_out_handles(pipe->native_sink(), std::integral_constant<int, p1>(), std::integral_constant<int, p2>()); if (res == -1) exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); ::close(pipe->native_sink()); ::close(pipe->native_source()); } }; }}}} #endif detail/posix/start_dir.hpp 0000644 00000002105 15125237362 0011660 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_START_DIR_HPP #define BOOST_PROCESS_DETAIL_POSIX_START_DIR_HPP #include <boost/process/detail/posix/handler.hpp> #include <string> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { template<typename Char> struct start_dir_init : handler_base_ext { typedef Char value_type; typedef std::basic_string<value_type> string_type; start_dir_init(string_type s) : s_(std::move(s)) {} template <class PosixExecutor> void on_exec_setup(PosixExecutor&) const { ::chdir(s_.c_str()); } const string_type & str() const {return s_;} private: string_type s_; }; }}}} #endif detail/posix/pipe_out.hpp 0000644 00000006023 15125237362 0011514 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_PIPE_OUT_HPP #define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP #include <boost/process/pipe.hpp> #include <boost/process/detail/posix/handler.hpp> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { template<int p1, int p2> struct pipe_out : handler_base_ext { int sink; int source; //opposite end pipe_out(int sink, int source) : sink(sink), source(source) {} template<typename T> pipe_out(T & p) : sink(p.native_sink()), source(p.native_source()) { p.assign_sink(-1); } template<typename Executor> void on_error(Executor &, const std::error_code &) const { ::close(sink); } template<typename Executor> void on_success(Executor &) const { ::close(sink); } template <typename Executor> void on_exec_setup(Executor &e) const; }; template<> template<typename Executor> void pipe_out<1,-1>::on_exec_setup(Executor &e) const { if (::dup2(sink, STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (sink != STDOUT_FILENO) ::close(sink); ::close(source); } template<> template<typename Executor> void pipe_out<2,-1>::on_exec_setup(Executor &e) const { if (::dup2(sink, STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (sink != STDOUT_FILENO) ::close(sink); ::close(source); } template<> template<typename Executor> void pipe_out<1,2>::on_exec_setup(Executor &e) const { if (::dup2(sink, STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (::dup2(sink, STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if ((sink != STDOUT_FILENO) && (sink != STDERR_FILENO)) ::close(sink); } class async_pipe; template<int p1, int p2> struct async_pipe_out : public pipe_out<p1, p2> { async_pipe &pipe; template<typename AsyncPipe> async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p) { } template<typename Pipe, typename Executor> static void close(Pipe & pipe, Executor &) { boost::system::error_code ec; std::move(pipe).sink().close(ec); } template<typename Executor> void on_error(Executor & exec, const std::error_code &) { close(pipe, exec); } template<typename Executor> void on_success(Executor &exec) { close(pipe, exec); } }; }}}} #endif detail/posix/wait_group.hpp 0000644 00000006537 15125237362 0012062 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WAIT_GROUP_HPP #define BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/group_handle.hpp> #include <chrono> #include <system_error> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { inline void wait(const group_handle &p, std::error_code &ec) noexcept { pid_t ret; siginfo_t status; do { ret = ::waitpid(-p.grp, &status.si_status, 0); if (ret == -1) { ec = get_last_error(); return; } //ECHILD --> no child processes left. ret = ::waitid(P_PGID, p.grp, &status, WEXITED | WNOHANG); } while ((ret != -1) || (errno != ECHILD)); if (errno != ECHILD) ec = boost::process::detail::get_last_error(); else ec.clear(); } inline void wait(const group_handle &p) noexcept { std::error_code ec; wait(p, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in wait"); } template< class Clock, class Duration > inline bool wait_until( const group_handle &p, const std::chrono::time_point<Clock, Duration>& time_out, std::error_code & ec) noexcept { ::siginfo_t siginfo; bool timed_out = false; int ret; ::timespec sleep_interval; sleep_interval.tv_sec = 0; sleep_interval.tv_nsec = 100000000; while (!(timed_out = (Clock::now() > time_out))) { ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG); if (ret == -1) { if ((errno == ECHILD) || (errno == ESRCH)) { ec.clear(); return true; } ec = boost::process::detail::get_last_error(); return false; } //we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code. ::nanosleep(&sleep_interval, nullptr); } return !timed_out; } template< class Clock, class Duration > inline bool wait_until( const group_handle &p, const std::chrono::time_point<Clock, Duration>& time_out) noexcept { std::error_code ec; bool b = wait_until(p, time_out, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until"); return b; } template< class Rep, class Period > inline bool wait_for( const group_handle &p, const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept { return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec); } template< class Rep, class Period > inline bool wait_for( const group_handle &p, const std::chrono::duration<Rep, Period>& rel_time) noexcept { std::error_code ec; bool b = wait_for(p, rel_time, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for"); return b; } }}}} #endif detail/posix/close_in.hpp 0000644 00000002035 15125237362 0011462 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_CLOSE_IN_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP #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, ::boost::process::detail::uses_handles { template <class Executor> void on_exec_setup(Executor &e) const { if (::close(STDIN_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "close() failed"); } int get_used_handles() {return STDIN_FILENO;} }; }}}} #endif detail/posix/null_in.hpp 0000644 00000002431 15125237362 0011327 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_NULL_IN_HPP #define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP #include <boost/process/pipe.hpp> #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, ::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 { if (::dup2(source.handle(), STDIN_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } }; }}}} #endif detail/posix/compare_handles.hpp 0000644 00000002005 15125237362 0013010 0 ustar 00 // Copyright (c) 2016 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_COMPARE_HANDLES_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_ #include <boost/process/detail/config.hpp> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { inline bool compare_handles(int lhs, int rhs) { if ((lhs == -1) || (rhs == -1)) return false; if (lhs == rhs) return true; struct stat stat1, stat2; if(fstat(lhs, &stat1) < 0) ::boost::process::detail::throw_last_error("fstat() failed"); if(fstat(rhs, &stat2) < 0) ::boost::process::detail::throw_last_error("fstat() failed"); return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino); } }}}} #endif /* BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_ */ detail/posix/pipe_in.hpp 0000644 00000004507 15125237362 0011320 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_POSIX_PIPE_IN_HPP #define BOOST_PROCESS_POSIX_PIPE_IN_HPP #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, ::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()) { p.assign_source(-1); } template<typename Executor> void on_error(Executor &, const std::error_code &) const { ::close(source); } template<typename Executor> void on_success(Executor &) const { ::close(source); } template <class Executor> void on_exec_setup(Executor &e) const { if (::dup2(source, STDIN_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (source != STDIN_FILENO) ::close(source); ::close(sink); } }; class async_pipe; struct async_pipe_in : public pipe_in { async_pipe &pipe; template<typename AsyncPipe> async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p) { } template<typename Pipe, typename Executor> static void close(Pipe & pipe, Executor &) { boost::system::error_code ec; std::move(pipe).source().close(ec); } template<typename Executor> void on_error(Executor & exec, const std::error_code &) { close(pipe, exec); } template<typename Executor> void on_success(Executor &exec) { close(pipe, exec); } }; }}}} #endif detail/posix/handler.hpp 0000644 00000003313 15125237362 0011304 0 ustar 00 // Copyright (c) 2016 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_HANDLER_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace posix { //does not extend anything. struct handler_base_ext : handler_base { template<typename Executor> void on_fork_error (Executor &, const std::error_code&) const {} template<typename Executor> void on_exec_setup (Executor &) const {} template<typename Executor> void on_exec_error (Executor &, const std::error_code&) const {} }; template <class Handler> struct on_fork_error_ : handler_base_ext { explicit on_fork_error_(Handler handler) : handler_(handler) {} template <class Executor> void on_fork_error(Executor &e, const std::error_code &ec) const { handler_(e, ec); } private: Handler handler_; }; template <class Handler> struct on_exec_setup_ : handler_base_ext { explicit on_exec_setup_(Handler handler) : handler_(handler) {} template <class Executor> void on_exec_setup(Executor &e) const { handler_(e); } private: Handler handler_; }; template <class Handler> struct on_exec_error_ : handler_base_ext { explicit on_exec_error_(Handler handler) : handler_(handler) {} template <class Executor> void on_exec_error(Executor &e, const std::error_code &ec) const { handler_(e, ec); } private: Handler handler_; }; }}}} #endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */ detail/posix/environment.hpp 0000644 00000023350 15125237362 0012236 0 ustar 00 // Copyright (c) 2016 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_ENVIRONMENT_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_ #include <string> #include <vector> #include <unordered_map> #include <boost/process/detail/config.hpp> #include <algorithm> #include <cstdlib> #include <boost/process/locale.hpp> namespace boost { namespace process { namespace detail { namespace posix { template<typename Char> class native_environment_impl { static std::vector<std::basic_string<Char>> _load() { std::vector<std::basic_string<Char>> val; auto p = environ; while (*p != nullptr) { std::string str = *p; val.push_back(::boost::process::detail::convert(str)); p++; } return val; } static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec) { std::vector<Char*> val; val.resize(vec.size() + 1); std::transform(vec.begin(), vec.end(), val.begin(), [](std::basic_string<Char> & str) { return &str.front(); }); val.back() = nullptr; return val; } std::vector<std::basic_string<Char>> _buffer = _load(); std::vector<Char*> _impl = _load_var(_buffer); public: using char_type = Char; using pointer_type = const char_type*; using string_type = std::basic_string<char_type>; using native_handle_type = char_type **; void reload() { _buffer = _load(); _impl = _load_var(_buffer); } string_type get(const pointer_type id) { return get(string_type(id)); } void set(const pointer_type id, const pointer_type value) { set(string_type(id), string_type(value)); } void reset(const pointer_type id) { reset(string_type(id)); } string_type get(const string_type & id) { std::string id_c = ::boost::process::detail::convert(id); std::string g = ::getenv(id_c.c_str()); return ::boost::process::detail::convert(g.c_str()); } void set(const string_type & id, const string_type & value) { std::string id_c = ::boost::process::detail::convert(id.c_str()); std::string value_c = ::boost::process::detail::convert(value.c_str()); auto res = ::setenv(id_c.c_str(), value_c.c_str(), true); if (res != 0) boost::process::detail::throw_last_error(); } void reset(const string_type & id) { std::string id_c = ::boost::process::detail::convert(id.c_str()); auto res = ::unsetenv(id_c.c_str()); if (res != 0) ::boost::process::detail::throw_last_error(); } native_environment_impl() = default; native_environment_impl(const native_environment_impl& ) = delete; native_environment_impl(native_environment_impl && ) = default; native_environment_impl & operator=(const native_environment_impl& ) = delete; native_environment_impl & operator=(native_environment_impl && ) = default; native_handle_type _env_impl = _impl.data(); native_handle_type native_handle() const {return _env_impl;} }; template<> class native_environment_impl<char> { public: using char_type = char; using pointer_type = const char_type*; using string_type = std::basic_string<char_type>; using native_handle_type = char_type **; void reload() {this->_env_impl = ::environ;} string_type get(const pointer_type id) { return getenv(id); } void set(const pointer_type id, const pointer_type value) { auto res = ::setenv(id, value, 1); if (res != 0) boost::process::detail::throw_last_error(); reload(); } void reset(const pointer_type id) { auto res = ::unsetenv(id); if (res != 0) boost::process::detail::throw_last_error(); reload(); } string_type get(const string_type & id) {return get(id.c_str());} void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); } void reset(const string_type & id) {reset(id.c_str());} native_environment_impl() = default; native_environment_impl(const native_environment_impl& ) = delete; native_environment_impl(native_environment_impl && ) = default; native_environment_impl & operator=(const native_environment_impl& ) = delete; native_environment_impl & operator=(native_environment_impl && ) = default; native_handle_type _env_impl = environ; native_handle_type native_handle() const {return ::environ;} }; template<typename Char> struct basic_environment_impl { std::vector<std::basic_string<Char>> _data {}; static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data); std::vector<Char*> _env_arr{_load_var(_data)}; public: using char_type = Char; using pointer_type = const char_type*; using string_type = std::basic_string<char_type>; using native_handle_type = Char**; void reload() { _env_arr = _load_var(_data); _env_impl = _env_arr.data(); } string_type get(const pointer_type id) {return get(string_type(id));} void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);} void reset(const pointer_type id) {reset(string_type(id));} string_type get(const string_type & id); void set(const string_type & id, const string_type & value); void reset(const string_type & id); basic_environment_impl(const native_environment_impl<Char> & nei); basic_environment_impl() = default; basic_environment_impl(const basic_environment_impl& rhs) : _data(rhs._data) { } basic_environment_impl(basic_environment_impl && ) = default; basic_environment_impl & operator=(const basic_environment_impl& rhs) { _data = rhs._data; _env_arr = _load_var(_data); _env_impl = &*_env_arr.begin(); return *this; } basic_environment_impl & operator=(basic_environment_impl && ) = default; template<typename CharR> explicit inline basic_environment_impl( const basic_environment_impl<CharR>& rhs, const ::boost::process::codecvt_type & cv = ::boost::process::codecvt()) : _data(rhs._data.size()) { std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(), [&](const std::basic_string<CharR> & st) { return ::boost::process::detail::convert(st, cv); } ); reload(); } template<typename CharR> basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs) { _data = ::boost::process::detail::convert(rhs._data); _env_arr = _load_var(&*_data.begin()); _env_impl = &*_env_arr.begin(); return *this; } Char ** _env_impl = &*_env_arr.data(); native_handle_type native_handle() const {return &_data.front();} }; template<typename Char> basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei) { auto beg = nei.native_handle(); auto end = beg; while (*end != nullptr) end++; this->_data.assign(beg, end); reload(); } template<typename Char> inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type { auto itr = std::find_if(_data.begin(), _data.end(), [&](const string_type & st) -> bool { if (st.size() <= id.size()) return false; return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>()); } ); if (itr == _data.end()) { return ""; } else return itr->data() + id.size(); //id=Thingy -> +2 points to T } template<typename Char> inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value) { auto itr = std::find_if(_data.begin(), _data.end(), [&](const string_type & st) -> bool { if (st.size() <= id.size()) return false; return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>()); } ); if (itr != _data.end()) *itr = id + equal_sign<Char>() + value; else _data.push_back(id + equal_sign<Char>() + value); reload(); } template<typename Char> inline void basic_environment_impl<Char>::reset(const string_type &id) { auto itr = std::find_if(_data.begin(), _data.end(), [&](const string_type & st) -> bool { if (st.size() <= id.size()) return false; return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>()); } ); if (itr != _data.end()) { _data.erase(itr);//and remove it } reload(); } template<typename Char> std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data) { std::vector<Char*> ret; ret.reserve(data.size() +1); for (auto & val : data) { if (val.empty()) val.push_back(0); ret.push_back(&val.front()); } ret.push_back(nullptr); return ret; } template<typename T> constexpr T env_seperator(); template<> constexpr char env_seperator() {return ':'; } template<> constexpr wchar_t env_seperator() {return L':'; } typedef int native_handle_t; inline int get_id() {return getpid(); } inline int native_handle() {return getpid(); } } } } } #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */ detail/posix/asio_fwd.hpp 0000644 00000002476 15125237362 0011473 0 ustar 00 // Copyright (c) 2016 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_ASIO_FWD_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_ #include <memory> #include <boost/asio/ts/netfwd.hpp> namespace boost { namespace asio { class mutable_buffer; class mutable_buffers_1; class const_buffer; class const_buffers_1; template<typename Allocator> class basic_streambuf; typedef basic_streambuf<std::allocator<char>> streambuf; template <typename Executor> class basic_signal_set; typedef basic_signal_set<any_io_executor> signal_set; template <typename Handler> class basic_yield_context; namespace posix { template <typename Executor> class basic_stream_descriptor; typedef basic_stream_descriptor<any_io_executor> stream_descriptor; } //posix } //asio namespace process { namespace detail { namespace posix { class async_pipe; template<typename T> struct async_in_buffer; template<int p1, int p2, typename Buffer> struct async_out_buffer; template<int p1, int p2, typename Type> struct async_out_future; } // posix } // detail using ::boost::process::detail::posix::async_pipe; } // process } // boost #endif /* BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_ */ detail/posix/is_running.hpp 0000644 00000004400 15125237362 0012040 0 ustar 00 // Copyright (c) 2106 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_IS_RUNNING_HPP #define BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/child_handle.hpp> #include <system_error> #include <sys/wait.h> namespace boost { namespace process { namespace detail { namespace posix { // Use the "stopped" state (WIFSTOPPED) to indicate "not terminated". // This bit arrangement of status codes is not guaranteed by POSIX, but (according to comments in // the glibc <bits/waitstatus.h> header) is the same across systems in practice. constexpr int still_active = 0x017f; static_assert(WIFSTOPPED(still_active), "Expected still_active to indicate WIFSTOPPED"); static_assert(!WIFEXITED(still_active), "Expected still_active to not indicate WIFEXITED"); static_assert(!WIFSIGNALED(still_active), "Expected still_active to not indicate WIFSIGNALED"); static_assert(!WIFCONTINUED(still_active), "Expected still_active to not indicate WIFCONTINUED"); inline bool is_running(int code) { return !WIFEXITED(code) && !WIFSIGNALED(code); } inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept { int status; auto ret = ::waitpid(p.pid, &status, WNOHANG); if (ret == -1) { if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously. ec = ::boost::process::detail::get_last_error(); return false; } else if (ret == 0) return true; else { ec.clear(); if (!is_running(status)) exit_code = status; return false; } } inline bool is_running(const child_handle &p, int & exit_code) { std::error_code ec; bool b = is_running(p, exit_code, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in is_running"); return b; } inline int eval_exit_status(int code) { if (WIFEXITED(code)) { return WEXITSTATUS(code); } else if (WIFSIGNALED(code)) { return WTERMSIG(code); } else { return code; } } }}}} #endif detail/posix/file_in.hpp 0000644 00000002577 15125237362 0011307 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_FILE_IN_HPP #define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP #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, ::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)) {} template <class WindowsExecutor> void on_exec_setup(WindowsExecutor &e) const { if (::dup2(handle, STDIN_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } }; }}}} #endif detail/posix/file_out.hpp 0000644 00000004226 15125237362 0011501 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_POSIX_FILE_OUT_HPP #define BOOST_PROCESS_POSIX_FILE_OUT_HPP #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, ::boost::process::detail::uses_handles { file_descriptor file; int handle = file.handle(); template<typename T> 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; }; template<> template<typename Executor> void file_out<1,-1>::on_exec_setup(Executor &e) const { if (::dup2(handle, STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } template<> template<typename Executor> void file_out<2,-1>::on_exec_setup(Executor &e) const { if (::dup2(handle, STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } template<> template<typename Executor> void file_out<1,2>::on_exec_setup(Executor &e) const { if (::dup2(handle, STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (::dup2(handle, STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); } }}}} #endif detail/posix/cmd.hpp 0000644 00000004743 15125237362 0010442 0 ustar 00 // Copyright (c) 2016 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_CMD_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/handler.hpp> #include <string> #include <vector> namespace boost { namespace process { namespace detail { namespace posix { template<typename Char> inline std::vector<std::basic_string<Char>> build_cmd(const std::basic_string<Char> & value) { std::vector<std::basic_string<Char>> ret; bool in_quotes = false; auto beg = value.begin(); for (auto itr = value.begin(); itr != value.end(); itr++) { if (*itr == quote_sign<Char>()) in_quotes = !in_quotes; if (!in_quotes && (*itr == space_sign<Char>())) { if (itr != beg) { ret.emplace_back(beg, itr); beg = itr + 1; } } } if (beg != value.end()) ret.emplace_back(beg, value.end()); return ret; } template<typename Char> struct cmd_setter_ : handler_base_ext { typedef Char value_type; typedef std::basic_string<value_type> string_type; cmd_setter_(string_type && cmd_line) : _cmd_line(api::build_cmd(std::move(cmd_line))) {} cmd_setter_(const string_type & cmd_line) : _cmd_line(api::build_cmd(cmd_line)) {} template <class Executor> void on_setup(Executor& exec) { exec.exe = _cmd_impl.front(); exec.cmd_line = &_cmd_impl.front(); exec.cmd_style = true; } string_type str() const { string_type ret; std::size_t size = 0; for (auto & cmd : _cmd_line) size += cmd.size() + 1; ret.reserve(size -1); for (auto & cmd : _cmd_line) { if (!ret.empty()) ret += equal_sign<Char>(); ret += cmd; } return ret; } private: static inline std::vector<Char*> make_cmd(std::vector<string_type> & args); std::vector<string_type> _cmd_line; std::vector<Char*> _cmd_impl = make_cmd(_cmd_line); }; template<typename Char> std::vector<Char*> cmd_setter_<Char>::make_cmd(std::vector<std::basic_string<Char>> & args) { std::vector<Char*> vec; for (auto & v : args) vec.push_back(&v.front()); vec.push_back(nullptr); return vec; } }}}} #endif detail/posix/signal.hpp 0000644 00000003552 15125237362 0011151 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_POSIX_SIGNAL_HPP #define BOOST_PROCESS_POSIX_SIGNAL_HPP #include <boost/process/detail/posix/handler.hpp> #include <signal.h> namespace boost { namespace process { namespace detail { namespace posix { #if defined(__GLIBC__) using sighandler_t = ::sighandler_t; #else using sighandler_t = void(*)(int); #endif struct sig_init_ : handler_base_ext { sig_init_ (sighandler_t handler) : _handler(handler) {} template <class PosixExecutor> void on_exec_setup(PosixExecutor&) { _old = ::signal(SIGCHLD, _handler); } template <class Executor> void on_error(Executor&, const std::error_code &) { if (!_reset) { ::signal(SIGCHLD, _old); _reset = true; } } template <class Executor> void on_success(Executor&) { if (!_reset) { ::signal(SIGCHLD, _old); _reset = true; } } private: bool _reset = false; ::boost::process::detail::posix::sighandler_t _old{0}; ::boost::process::detail::posix::sighandler_t _handler{0}; }; struct sig_ { constexpr sig_() {} sig_init_ operator()(::boost::process::detail::posix::sighandler_t h) const {return h;} sig_init_ operator= (::boost::process::detail::posix::sighandler_t h) const {return h;} sig_init_ dfl() const {return SIG_DFL;} sig_init_ ign() const {return SIG_IGN;} }; }}}} #endif detail/posix/exe.hpp 0000644 00000001071 15125237362 0010447 0 ustar 00 // Copyright (c) 2016 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_EXE_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_ namespace boost { namespace process { namespace detail { namespace posix { template<class StringType, class Executor> inline void apply_exe(const StringType & exe, Executor & e) { e.exe = exe.c_str(); } } } } } #endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */ detail/posix/wait_for_exit.hpp 0000644 00000015041 15125237362 0012533 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WAIT_FOR_EXIT_HPP #define BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/child_handle.hpp> #include <system_error> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept { pid_t ret; int status; do { ret = ::waitpid(p.pid, &status, 0); } while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status))); if (ret == -1) ec = boost::process::detail::get_last_error(); else { ec.clear(); exit_code = status; } } inline void wait(const child_handle &p, int & exit_code) noexcept { std::error_code ec; wait(p, exit_code, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in wait"); } template< class Clock, class Duration > inline bool wait_until( const child_handle &p, int & exit_code, const std::chrono::time_point<Clock, Duration>& time_out, std::error_code & ec) noexcept { ::sigset_t sigset; //I need to set the signal, because it might be ignore / default, in which case sigwait might not work. using _signal_t = void(*)(int); static thread_local _signal_t sigchld_handler = SIG_DFL; struct signal_interceptor_t { static void handler_func(int val) { if ((sigchld_handler != SIG_DFL) && (sigchld_handler != SIG_IGN)) sigchld_handler(val); } signal_interceptor_t() { sigchld_handler = ::signal(SIGCHLD, &handler_func); } ~signal_interceptor_t() { ::signal(SIGCHLD, sigchld_handler); sigchld_handler = SIG_DFL;} } signal_interceptor{}; if (sigemptyset(&sigset) != 0) { ec = get_last_error(); return false; } if (sigaddset(&sigset, SIGCHLD) != 0) { ec = get_last_error(); return false; } auto get_timespec = [](const Duration & dur) { ::timespec ts; ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count(); ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000; return ts; }; int ret; int status{0}; struct ::sigaction old_sig; if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig)) { ec = get_last_error(); return false; } bool timed_out; #if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT) do { auto ts = get_timespec(time_out - Clock::now()); auto ret_sig = ::sigtimedwait(&sigset, nullptr, &ts); errno = 0; ret = ::waitpid(p.pid, &status, WNOHANG); if ((ret_sig == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN)) old_sig.sa_handler(ret); if (ret == 0) { timed_out = Clock::now() >= time_out; if (timed_out) return false; } } while ((ret == 0) || (((ret == -1) && errno == EINTR) || ((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)))); #else //if we do not have sigtimedwait, we fork off a child process to get the signal in time pid_t timeout_pid = ::fork(); if (timeout_pid == -1) { ec = boost::process::detail::get_last_error(); return true; } else if (timeout_pid == 0) { auto ts = get_timespec(time_out - Clock::now()); ::timespec rem; while (ts.tv_sec > 0 || ts.tv_nsec > 0) { if (::nanosleep(&ts, &rem) != 0) { auto err = errno; if ((err == EINVAL) || (err == EFAULT)) break; } ts = get_timespec(time_out - Clock::now()); } ::exit(0); } struct child_cleaner_t { pid_t pid; ~child_cleaner_t() { int res; ::kill(pid, SIGKILL); ::waitpid(pid, &res, WNOHANG); } }; child_cleaner_t child_cleaner{timeout_pid}; do { int sig_{0}; if ((::waitpid(timeout_pid, &status, WNOHANG) != 0) && (WIFEXITED(status) || WIFSIGNALED(status))) return false; ret = ::sigwait(&sigset, &sig_); errno = 0; if ((sig_ == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN)) old_sig.sa_handler(ret); ret = ::waitpid(p.pid, &status, WNOHANG); if (ret == 0) // == > is running { timed_out = Clock::now() >= time_out; if (timed_out) return false; } } while ((ret == 0) || (((ret == -1) && errno == EINTR) || ((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)))); #endif if (ret == -1) ec = boost::process::detail::get_last_error(); else { ec.clear(); exit_code = status; } return true; } template< class Clock, class Duration > inline bool wait_until( const child_handle &p, int & exit_code, const std::chrono::time_point<Clock, Duration>& time_out) { std::error_code ec; bool b = wait_until(p, exit_code, time_out, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until"); return b; } template< class Rep, class Period > inline bool wait_for( const child_handle &p, int & exit_code, const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept { return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec); } template< class Rep, class Period > inline bool wait_for( const child_handle &p, int & exit_code, const std::chrono::duration<Rep, Period>& rel_time) { std::error_code ec; bool b = wait_for(p, exit_code, rel_time, ec); boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for"); return b; } }}}} #endif detail/posix/file_descriptor.hpp 0000644 00000003534 15125237362 0013051 0 ustar 00 // Copyright (c) 2016 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_FILE_DESCRIPTOR_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_ #include <fcntl.h> #include <string> #include <boost/filesystem/path.hpp> namespace boost { namespace process { namespace detail { namespace posix { struct file_descriptor { enum mode_t { read = 1, write = 2, read_write = 3 }; file_descriptor() = default; explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write) : file_descriptor(p.native(), mode) { } explicit file_descriptor(const std::string & path , mode_t mode = read_write) : file_descriptor(path.c_str(), mode) {} explicit file_descriptor(const char* path, mode_t mode = read_write) : _handle(create_file(path, mode)) { } file_descriptor(const file_descriptor & ) = delete; file_descriptor(file_descriptor && ) = default; file_descriptor& operator=(const file_descriptor & ) = delete; file_descriptor& operator=(file_descriptor && ) = default; ~file_descriptor() { if (_handle != -1) ::close(_handle); } int handle() const { return _handle;} private: static int create_file(const char* name, mode_t mode ) { switch(mode) { case read: return ::open(name, O_RDONLY); case write: return ::open(name, O_WRONLY | O_CREAT, 0660); case read_write: return ::open(name, O_RDWR | O_CREAT, 0660); default: return -1; } } int _handle = -1; }; }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */ detail/posix/sigchld_service.hpp 0000644 00000010006 15125237362 0013021 0 ustar 00 // Copyright (c) 2017 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_SIGCHLD_SERVICE_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_ #include <boost/asio/dispatch.hpp> #include <boost/asio/post.hpp> #include <boost/asio/signal_set.hpp> #include <boost/asio/strand.hpp> #include <boost/optional.hpp> #include <signal.h> #include <functional> #include <sys/wait.h> namespace boost { namespace process { namespace detail { namespace posix { class sigchld_service : public boost::asio::detail::service_base<sigchld_service> { boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()}; boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD}; std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers; inline void _handle_signal(const boost::system::error_code & ec); public: sigchld_service(boost::asio::io_context & io_context) : boost::asio::detail::service_base<sigchld_service>(io_context) { } template <typename SignalHandler> BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler, void (int, std::error_code)) async_wait(::pid_t pid, SignalHandler && handler) { boost::asio::async_completion< SignalHandler, void(boost::system::error_code)> init{handler}; auto & h = init.completion_handler; boost::asio::dispatch( _strand, [this, pid, h] { //check if the child actually is running first int status; auto pid_res = ::waitpid(pid, &status, WNOHANG); if (pid_res < 0) h(-1, get_last_error()); else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status))) h(status, {}); //successfully exited already else //still running { if (_receivers.empty()) _signal_set.async_wait( [this](const boost::system::error_code &ec, int) { boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);}); }); _receivers.emplace_back(pid, h); } }); return init.result.get(); } void shutdown() override { _receivers.clear(); } void cancel() { _signal_set.cancel(); } void cancel(boost::system::error_code & ec) { _signal_set.cancel(ec); } }; void sigchld_service::_handle_signal(const boost::system::error_code & ec) { std::error_code ec_{ec.value(), std::system_category()}; if (ec_) { for (auto & r : _receivers) r.second(-1, ec_); return; } for (auto & r : _receivers) { int status; int pid = ::waitpid(r.first, &status, WNOHANG); if (pid < 0) { // error (eg: the process no longer exists) r.second(-1, get_last_error()); r.first = 0; // mark for deletion } else if (pid == r.first) { r.second(status, ec_); r.first = 0; // mark for deletion } // otherwise the process is still around } _receivers.erase(std::remove_if(_receivers.begin(), _receivers.end(), [](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p) { return p.first == 0; }), _receivers.end()); if (!_receivers.empty()) { _signal_set.async_wait( [this](const boost::system::error_code & ec, int) { boost::asio::post(_strand, [this, ec]{this->_handle_signal(ec);}); }); } } } } } } #endif detail/posix/on_exit.hpp 0000644 00000001751 15125237362 0011340 0 ustar 00 // Copyright (c) 2016 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_POSIX_ON_EXIT_HPP_ #define BOOST_PROCESS_POSIX_ON_EXIT_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/posix/async_handler.hpp> #include <system_error> #include <functional> namespace boost { namespace process { namespace detail { namespace posix { struct on_exit_ : boost::process::detail::posix::async_handler { std::function<void(int, const std::error_code&)> handler; on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler) { } template<typename Executor> std::function<void(int, const std::error_code&)> on_exit_handler(Executor&) { return handler; } }; }}}} #endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */ detail/posix/child_handle.hpp 0000644 00000002630 15125237362 0012266 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_POSIX_CHILD_HPP #define BOOST_PROCESS_POSIX_CHILD_HPP #include <utility> #include <system_error> namespace boost { namespace process { namespace detail { namespace posix { typedef ::pid_t pid_t; struct child_handle { int pid {-1}; explicit child_handle(int pid) : pid(pid) {} child_handle() = default; ~child_handle() = default; child_handle(const child_handle & c) = delete; child_handle(child_handle && c) : pid(c.pid) { c.pid = -1; } child_handle &operator=(const child_handle & c) = delete; child_handle &operator=(child_handle && c) { pid = c.pid; c.pid = -1; return *this; } int id() const { return pid; } bool in_group() const {return true;} bool in_group(std::error_code&) const noexcept {return true;} typedef int process_handle_t; process_handle_t process_handle() const { return pid; } bool valid() const { return pid != -1; } }; }}}} #endif detail/posix/executor.hpp 0000644 00000036265 15125237362 0011541 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_EXECUTOR_HPP #define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP #include <boost/process/detail/child_decl.hpp> #include <boost/process/error.hpp> #include <boost/process/pipe.hpp> #include <boost/process/detail/posix/basic_pipe.hpp> #include <boost/process/detail/posix/use_vfork.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <cstdlib> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/classification.hpp> namespace boost { namespace process { namespace detail { namespace posix { template<typename Executor> struct on_setup_t { Executor & exec; on_setup_t(Executor & exec) : exec(exec) {}; template<typename T> void operator()(T & t) const { if (!exec.error()) t.on_setup(exec); } }; template<typename Executor> struct on_error_t { Executor & exec; const std::error_code & error; on_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {}; template<typename T> void operator()(T & t) const { t.on_error(exec, error); } }; template<typename Executor> struct on_success_t { Executor & exec; on_success_t(Executor & exec) : exec(exec) {}; template<typename T> void operator()(T & t) const {t.on_success(exec);} }; template<typename Executor> struct on_fork_error_t { Executor & exec; const std::error_code & error; on_fork_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {}; template<typename T> void operator()(T & t) const { t.on_fork_error(exec, error); } }; template<typename Executor> struct on_exec_setup_t { Executor & exec; on_exec_setup_t(Executor & exec) : exec(exec) {}; template<typename T> void operator()(T & t) const { t.on_exec_setup(exec); } }; template<typename Executor> struct on_exec_error_t { Executor & exec; const std::error_code &ec; on_exec_error_t(Executor & exec, const std::error_code & error) : exec(exec), ec(error) {}; template<typename T> void operator()(T & t) const { t.on_exec_error(exec, ec); } }; template<typename Executor> struct on_fork_success_t { Executor & exec; on_fork_success_t(Executor & exec) : exec(exec) {}; template<typename T> void operator()(T & t) const { t.on_fork_success(exec); } }; template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;} template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec) { return on_error_t<Executor> (exec, ec); } template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;} template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec) { return on_fork_error_t<Executor> (exec, ec); } template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;} template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec) { return on_exec_error_t<Executor> (exec, ec); } template<typename Sequence> class executor { template<typename HasHandler, typename UseVFork> void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {} int _pipe_sink = -1; void write_error(const std::error_code & ec, const char * msg) { //I am the child int len = ec.value(); ::write(_pipe_sink, &len, sizeof(int)); len = std::strlen(msg) + 1; ::write(_pipe_sink, &len, sizeof(int)); ::write(_pipe_sink, msg, len); } void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_) { if (this->pid == 0) //on the fork. write_error(ec, msg); else { this->_ec = ec; this->_msg = msg; } } void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::false_) { if (this->pid == 0) write_error(ec, msg); else throw process_error(ec, msg); } void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::true_) { this->_ec = ec; this->_msg = msg; } void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::true_) { if (this->pid == 0) { this->_ec = ec; this->_msg = msg; } else throw process_error(ec, msg); } void check_error(boost::mpl::true_) {}; void check_error(boost::mpl::false_) { if (_ec) throw process_error(_ec, _msg); } typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler; typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error; typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork; inline child invoke(boost::mpl::true_ , boost::mpl::true_ ); inline child invoke(boost::mpl::false_, boost::mpl::true_ ); inline child invoke(boost::mpl::true_ , boost::mpl::false_ ); inline child invoke(boost::mpl::false_, boost::mpl::false_ ); void _write_error(int sink) { int data[2] = {_ec.value(),static_cast<int>(_msg.size())}; while (::write(sink, &data[0], sizeof(int) *2) == -1) { auto err = errno; if (err == EBADF) return; else if ((err != EINTR) && (err != EAGAIN)) break; } while (::write(sink, &_msg.front(), _msg.size()) == -1) { auto err = errno; if (err == EBADF) return; else if ((err != EINTR) && (err != EAGAIN)) break; } } void _read_error(int source) { int data[2]; _ec.clear(); int count = 0; while ((count = ::read(source, &data[0], sizeof(int) *2 ) ) == -1) { //actually, this should block until it's read. auto err = errno; if ((err != EAGAIN ) && (err != EINTR)) set_error(std::error_code(err, std::system_category()), "Error read pipe"); } if (count == 0) return ; std::error_code ec(data[0], std::system_category()); std::string msg(data[1], ' '); while (::read(source, &msg.front(), msg.size() ) == -1) { //actually, this should block until it's read. auto err = errno; if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return. return; //EAGAIN not yet forked, EINTR interrupted, i.e. try again else if ((err != EAGAIN ) && (err != EINTR)) set_error(std::error_code(err, std::system_category()), "Error read pipe"); } set_error(ec, std::move(msg)); } std::string prepare_cmd_style_fn; //buffer inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations. { //use my own implementation prepare_cmd_style_fn = exe; if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK)) { auto e = ::environ; while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH=")) e++; if ((e != nullptr) && (*e != nullptr)) { std::vector<std::string> path; boost::split(path, *e, boost::is_any_of(":")); for (const std::string & pp : path) { auto p = pp + "/" + exe; if (!::access(p.c_str(), X_OK)) { prepare_cmd_style_fn = p; break; } } } } exe = prepare_cmd_style_fn.c_str(); } std::error_code _ec; std::string _msg; public: executor(Sequence & seq) : seq(seq) { } child operator()() { return invoke(has_ignore_error(), shall_use_vfork()); } Sequence & seq; const char * exe = nullptr; char *const* cmd_line = nullptr; bool cmd_style = false; char **env = ::environ; pid_t pid = -1; std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); const std::error_code & error() const {return _ec;} void set_error(const std::error_code &ec, const char* msg) { internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork()); } void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());}; }; template<typename Sequence> child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore errors { boost::fusion::for_each(seq, call_on_setup(*this)); if (_ec) return child(); if (cmd_style) prepare_cmd_style(); this->pid = ::fork(); if (pid == -1) { auto ec = boost::process::detail::get_last_error(); boost::fusion::for_each(seq, call_on_fork_error(*this, ec)); return child(); } else if (pid == 0) { boost::fusion::for_each(seq, call_on_exec_setup(*this)); ::execve(exe, cmd_line, env); auto ec = boost::process::detail::get_last_error(); boost::fusion::for_each(seq, call_on_exec_error(*this, ec)); _exit(EXIT_FAILURE); } child c(child_handle(pid), exit_status); boost::fusion::for_each(seq, call_on_success(*this)); return c; } template<typename Sequence> child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_) { { struct pipe_guard { int p[2]; pipe_guard() : p{-1,-1} {} ~pipe_guard() { if (p[0] != -1) ::close(p[0]); if (p[1] != -1) ::close(p[1]); } } p{}; if (::pipe(p.p) == -1) { set_error(::boost::process::detail::get_last_error(), "pipe(2) failed"); return child(); } if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1) { auto err = ::boost::process::detail::get_last_error(); set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe. return child(); } _ec.clear(); boost::fusion::for_each(seq, call_on_setup(*this)); if (_ec) { boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } if (cmd_style) prepare_cmd_style(); this->pid = ::fork(); if (pid == -1) { _ec = boost::process::detail::get_last_error(); _msg = "fork() failed"; boost::fusion::for_each(seq, call_on_fork_error(*this, _ec)); boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } else if (pid == 0) { _pipe_sink = p.p[1]; ::close(p.p[0]); boost::fusion::for_each(seq, call_on_exec_setup(*this)); ::execve(exe, cmd_line, env); _ec = boost::process::detail::get_last_error(); _msg = "execve failed"; boost::fusion::for_each(seq, call_on_exec_error(*this, _ec)); _write_error(_pipe_sink); ::close(p.p[1]); _exit(EXIT_FAILURE); return child(); } ::close(p.p[1]); p.p[1] = -1; _read_error(p.p[0]); } if (_ec) { boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } child c(child_handle(pid), exit_status); boost::fusion::for_each(seq, call_on_success(*this)); if (_ec) { boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } return c; } #if BOOST_POSIX_HAS_VFORK template<typename Sequence> child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore errors { boost::fusion::for_each(seq, call_on_setup(*this)); if (_ec) return child(); this->pid = ::vfork(); if (pid == -1) { auto ec = boost::process::detail::get_last_error(); boost::fusion::for_each(seq, call_on_fork_error(*this, ec)); return child(); } else if (pid == 0) { boost::fusion::for_each(seq, call_on_exec_setup(*this)); ::execve(exe, cmd_line, env); auto ec = boost::process::detail::get_last_error(); boost::fusion::for_each(seq, call_on_exec_error(*this, ec)); _exit(EXIT_FAILURE); } child c(child_handle(pid), exit_status); boost::fusion::for_each(seq, call_on_success(*this)); return c; } template<typename Sequence> child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_) { boost::fusion::for_each(seq, call_on_setup(*this)); if (_ec) { boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } _ec.clear(); if (cmd_style) this->prepare_cmd_style(); this->pid = ::vfork(); if (pid == -1) { _ec = boost::process::detail::get_last_error(); _msg = "fork() failed"; boost::fusion::for_each(seq, call_on_fork_error(*this, _ec)); boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } else if (pid == 0) { boost::fusion::for_each(seq, call_on_exec_setup(*this)); ::execve(exe, cmd_line, env); _ec = boost::process::detail::get_last_error(); _msg = "execve failed"; boost::fusion::for_each(seq, call_on_exec_error(*this, _ec)); _exit(EXIT_FAILURE); return child(); } child c(child_handle(pid), exit_status); check_error(has_error_handler()); if (_ec) { boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } else boost::fusion::for_each(seq, call_on_success(*this)); if (_ec) { boost::fusion::for_each(seq, call_on_error(*this, _ec)); return child(); } return c; } #endif template<typename Char, typename Tup> inline executor<Tup> make_executor(Tup & tup) { return executor<Tup>(tup); } }}}} #endif detail/posix/handles.hpp 0000644 00000007551 15125237362 0011315 0 ustar 00 // 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 detail/posix/group_ref.hpp 0000644 00000002100 15125237362 0011650 0 ustar 00 // Copyright (c) 2016 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_GROUP_REF_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/group_handle.hpp> #include <boost/process/detail/posix/handler.hpp> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { struct group_ref : handler_base_ext { group_handle & grp; explicit group_ref(group_handle & g) : grp(g) {} template <class Executor> void on_exec_setup(Executor&) const { if (grp.grp == -1) ::setpgid(0, 0); else ::setpgid(0, grp.grp); } template <class Executor> void on_success(Executor& exec) const { if (grp.grp == -1) grp.grp = exec.pid; } }; }}}} #endif /* BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_ */ detail/posix/group_handle.hpp 0000644 00000004024 15125237362 0012336 0 ustar 00 // Copyright (c) 2016 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_GROUP_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/child_handle.hpp> #include <system_error> #include <unistd.h> namespace boost { namespace process { namespace detail { namespace posix { struct group_handle { pid_t grp = -1; typedef pid_t handle_t; handle_t handle() const { return grp; } explicit group_handle(handle_t h) : grp(h) { } group_handle() = default; ~group_handle() = default; group_handle(const group_handle & c) = delete; group_handle(group_handle && c) : grp(c.grp) { c.grp = -1; } group_handle &operator=(const group_handle & c) = delete; group_handle &operator=(group_handle && c) { grp = c.grp; c.grp = -1; return *this; } void add(handle_t proc) { if (::setpgid(proc, grp)) throw_last_error(); } void add(handle_t proc, std::error_code & ec) noexcept { if (::setpgid(proc, grp)) ec = get_last_error(); } bool has(handle_t proc) { return ::getpgid(proc) == grp; } bool has(handle_t proc, std::error_code &) noexcept { return ::getpgid(proc) == grp; } bool valid() const { return grp != -1; } }; inline void terminate(group_handle &p, std::error_code &ec) noexcept { if (::killpg(p.grp, SIGKILL) == -1) ec = boost::process::detail::get_last_error(); else ec.clear(); p.grp = -1; } inline void terminate(group_handle &p) { std::error_code ec; terminate(p, ec); boost::process::detail::throw_error(ec, "killpg(2) failed in terminate"); } inline bool in_group() { return true; } }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ detail/posix/async_in.hpp 0000644 00000006725 15125237362 0011504 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_ASYNC_IN_HPP #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/posix/async_handler.hpp> #include <boost/asio/write.hpp> #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::uses_handles { Buffer & buf; std::shared_ptr<std::promise<void>> promise; async_in_buffer operator>(std::future<void> & fut) { promise = std::make_shared<std::promise<void>>(); fut = promise->get_future(); return std::move(*this); } std::shared_ptr<boost::process::async_pipe> pipe; async_in_buffer(Buffer & buf) : buf(buf) { } template <typename Executor> inline void on_success(Executor) { auto pipe_ = this->pipe; if (this->promise) { auto promise_ = this->promise; boost::asio::async_write(*pipe_, buf, [pipe_, promise_](const boost::system::error_code & ec, std::size_t) { if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT)) { std::error_code e(ec.value(), std::system_category()); promise_->set_exception(std::make_exception_ptr(process_error(e))); } else promise_->set_value(); }); } else boost::asio::async_write(*pipe_, buf, [pipe_](const boost::system::error_code&, std::size_t){}); std::move(*pipe_).source().close(); this->pipe = nullptr; } template<typename Executor> void on_error(Executor &, const std::error_code &) const { std::move(*pipe).source().close(); } template<typename Executor> void on_setup(Executor & exec) { 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) { if (::dup2(pipe->native_source(), STDIN_FILENO) == -1) exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed"); if (pipe->native_source() != STDIN_FILENO) ::close(pipe->native_source()); ::close(pipe->native_sink()); } }; }}}} #endif detail/posix/env_init.hpp 0000644 00000001723 15125237362 0011505 0 ustar 00 // Copyright (c) 2016 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_ENV_INIT_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/handler.hpp> #include <boost/process/environment.hpp> namespace boost { namespace process { namespace detail { namespace posix { template<typename Char> struct env_init; template<> struct env_init<char> : handler_base_ext { boost::process::environment env; env_init(boost::process::environment && env) : env(std::move(env)) {}; env_init(const boost::process::environment & env) : env(env) {}; template <class Executor> void on_setup(Executor &exec) const { exec.env = env._env_impl; } }; }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */ detail/posix/close_out.hpp 0000644 00000003307 15125237362 0011666 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_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 { template<int p1, int p2> 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<> template<typename Executor> void close_out<1,-1>::on_exec_setup(Executor &e) const { if (::close(STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "close() failed"); } template<> template<typename Executor> void close_out<2,-1>::on_exec_setup(Executor &e) const { if (::close(STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "close() failed"); } template<> template<typename Executor> void close_out<1,2>::on_exec_setup(Executor &e) const { if (::close(STDOUT_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "close() failed"); if (::close(STDERR_FILENO) == -1) e.set_error(::boost::process::detail::get_last_error(), "close() failed"); } }}}} #endif detail/posix/use_vfork.hpp 0000644 00000001415 15125237362 0011673 0 ustar 00 /* * use_vfork.hpp * * Created on: 17.06.2016 * Author: klemens */ #ifndef BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_ #include <boost/process/detail/posix/handler.hpp> #include <boost/fusion/sequence/intrinsic/has_key.hpp> #include <boost/fusion/container/set/convert.hpp> namespace boost { namespace process { namespace detail { namespace posix { struct use_vfork_ : handler_base_ext { constexpr use_vfork_(){}; }; template<typename Sequence> struct shall_use_vfork { typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type; typedef typename boost::fusion::result_of::has_key<set_type, const use_vfork_&>::type type; }; }}}} #endif /* BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_ */ detail/posix/fd.hpp 0000644 00000005075 15125237362 0010267 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_FD_HPP #define BOOST_PROCESS_DETAIL_POSIX_FD_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 close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles { close_fd_(int fd) : fd_(fd) {} template <class PosixExecutor> void on_exec_setup(PosixExecutor& e) const { if (::close(fd_) == -1) 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, ::boost::process::detail::uses_handles { public: close_fds_(const Range &fds) : fds_(fds) {} template <class PosixExecutor> void on_exec_setup(PosixExecutor& e) const { for (auto & fd_ : fds_) if (::close(fd_) == -1) { e.set_error(::boost::process::detail::get_last_error(), "close() failed"); break; } } Range& get_used_handles() {return fds_;} private: Range fds_; }; template <class FileDescriptor> struct bind_fd_ : handler_base_ext, ::boost::process::detail::uses_handles { public: bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {} template <class PosixExecutor> void on_exec_setup(PosixExecutor& e) const { if (::dup2(fd_, id_) == -1) 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_; }; struct fd_ { constexpr fd_() {}; close_fd_ close(int _fd) const {return close_fd_(_fd);} close_fds_<std::vector<int>> close(const std::initializer_list<int> & vec) const {return std::vector<int>(vec);} template<typename Range> close_fds_<Range> close(const Range & r) const {return r;} template <class FileDescriptor> bind_fd_<FileDescriptor> bind(int id, const FileDescriptor & fd) const {return {id, fd};} }; }}}} #endif detail/posix/basic_cmd.hpp 0000644 00000010707 15125237362 0011600 0 ustar 00 // Copyright (c) 2016 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_BASIC_CMD_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_ #include <boost/process/detail/posix/handler.hpp> #include <boost/process/detail/posix/cmd.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/process/shell.hpp> #include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/join.hpp> #include <string> #include <vector> namespace boost { namespace process { namespace detail { namespace posix { inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data) { std::string st = exe; for (auto & arg : data) { boost::replace_all(arg, "\"", "\\\""); auto it = std::find(arg.begin(), arg.end(), ' ');//contains space? if (it != arg.end())//ok, contains spaces. { //the first one is put directly onto the output, //because then I don't have to copy the whole string arg.insert(arg.begin(), '"' ); arg += '"'; //thats the post one. } if (!st.empty())//first one does not need a preceeding space st += ' '; st += arg; } return st ; } inline std::vector<std::string> build_args(const std::string & data) { std::vector<std::string> st; typedef std::string::const_iterator itr_t; //normal quotes outside can be stripped, inside ones marked as \" will be replaced. auto make_entry = [](const itr_t & begin, const itr_t & end) { std::string data; if ((*begin == '"') && (*(end-1) == '"')) data.assign(begin+1, end-1); else data.assign(begin, end); boost::replace_all(data, "\\\"", "\""); return data; }; bool in_quote = false; auto part_beg = data.cbegin(); auto itr = data.cbegin(); for (; itr != data.cend(); itr++) { if (*itr == '"') in_quote ^= true; if (!in_quote && (*itr == ' ')) { //alright, got a space if ((itr != data.cbegin()) && (*(itr -1) != ' ' )) st.push_back(make_entry(part_beg, itr)); part_beg = itr+1; } } if (part_beg != itr) st.emplace_back(make_entry(part_beg, itr)); return st; } template<typename Char> struct exe_cmd_init; template<> struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext { exe_cmd_init(const exe_cmd_init & ) = delete; exe_cmd_init(exe_cmd_init && ) = default; exe_cmd_init(std::string && exe, std::vector<std::string> && args) : exe(std::move(exe)), args(std::move(args)) {}; template <class Executor> void on_setup(Executor& exec) { if (exe.empty()) //cmd style { exec.exe = args.front().c_str(); exec.cmd_style = true; } else exec.exe = &exe.front(); cmd_impl = make_cmd(); exec.cmd_line = cmd_impl.data(); } static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));} static exe_cmd_init cmd (std::string && cmd) { auto args = build_args(cmd); return exe_cmd_init({}, std::move(args)); } static exe_cmd_init exe_args_shell(std::string&& exe, std::vector<std::string> && args) { auto cmd = build_cmd_shell(std::move(exe), std::move(args)); std::vector<std::string> args_ = {"-c", std::move(cmd)}; std::string sh = shell().string(); return exe_cmd_init(std::move(sh), std::move(args_)); } static exe_cmd_init cmd_shell(std::string&& cmd) { std::vector<std::string> args = {"-c", "\"" + cmd + "\""}; std::string sh = shell().string(); return exe_cmd_init( std::move(sh), {std::move(args)}); } private: inline std::vector<char*> make_cmd(); std::string exe; std::vector<std::string> args; std::vector<char*> cmd_impl; }; std::vector<char*> exe_cmd_init<char>::make_cmd() { std::vector<char*> vec; if (!exe.empty()) vec.push_back(&exe.front()); if (!args.empty()) { for (auto & v : args) vec.push_back(&v.front()); } vec.push_back(nullptr); return vec; } }}}} #endif detail/posix/async_handler.hpp 0000644 00000002243 15125237362 0012502 0 ustar 00 // Copyright (c) 2016 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_POSIX_ASYNC_HANDLER_HPP_ #define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_ #include <boost/process/detail/posix/handler.hpp> #include <type_traits> namespace boost { namespace process { namespace detail { namespace posix { struct require_io_context {}; struct async_handler : handler_base_ext, require_io_context { }; template<typename T> struct is_async_handler : std::is_base_of<async_handler, T> {}; template<typename T> struct is_async_handler<T&> : std::is_base_of<async_handler, T> {}; template<typename T> struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {}; template<typename T> struct does_require_io_context : std::is_base_of<require_io_context, T> {}; template<typename T> struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {}; template<typename T> struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {}; }}}} #endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */ detail/posix/terminate.hpp 0000644 00000002257 15125237362 0011665 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_TERMINATE_HPP #define BOOST_PROCESS_DETAIL_POSIX_TERMINATE_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/posix/child_handle.hpp> #include <system_error> #include <signal.h> #include <sys/wait.h> namespace boost { namespace process { namespace detail { namespace posix { inline void terminate(const child_handle &p, std::error_code &ec) noexcept { if (::kill(p.pid, SIGKILL) == -1) ec = boost::process::detail::get_last_error(); else ec.clear(); int status; ::waitpid(p.pid, &status, WNOHANG); //just to clean it up } inline void terminate(const child_handle &p) { std::error_code ec; terminate(p, ec); boost::process::detail::throw_error(ec, "kill(2) failed"); } }}}} #endif detail/posix/async_pipe.hpp 0000644 00000026172 15125237362 0012031 0 ustar 00 // Copyright (c) 2016 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_ASYNC_PIPE_HPP_ #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_ #include <boost/process/detail/posix/basic_pipe.hpp> #include <boost/asio/posix/stream_descriptor.hpp> #include <boost/asio/post.hpp> #include <system_error> #include <string> #include <utility> namespace boost { namespace process { namespace detail { namespace posix { class async_pipe { ::boost::asio::posix::stream_descriptor _source; ::boost::asio::posix::stream_descriptor _sink ; public: typedef int native_handle_type; typedef ::boost::asio::posix::stream_descriptor handle_type; typedef typename handle_type::executor_type executor_type; inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {} inline async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink) { int fds[2]; if (::pipe(fds) == -1) boost::process::detail::throw_last_error("pipe(2) failed"); _source.assign(fds[0]); _sink .assign(fds[1]); }; inline async_pipe(boost::asio::io_context & ios, const std::string & name) : async_pipe(ios, ios, name) {} inline async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & io_sink, const std::string & name); inline async_pipe(const async_pipe& lhs); async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink)) { lhs._source.assign (-1); lhs._sink .assign (-1); } template<class CharT, class Traits = std::char_traits<CharT>> explicit async_pipe(::boost::asio::io_context & ios_source, ::boost::asio::io_context & ios_sink, const basic_pipe<CharT, Traits> & p) : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink()) { } template<class CharT, class Traits = std::char_traits<CharT>> explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p) : async_pipe(ios, ios, p) { } template<class CharT, class Traits = std::char_traits<CharT>> inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p); inline async_pipe& operator=(const async_pipe& rhs); inline async_pipe& operator=(async_pipe&& lhs); ~async_pipe() { boost::system::error_code ec; close(ec); } template<class CharT, class Traits = std::char_traits<CharT>> inline explicit operator basic_pipe<CharT, Traits>() const; void cancel() { if (_sink.is_open()) _sink.cancel(); if (_source.is_open()) _source.cancel(); } void close() { if (_sink.is_open()) _sink.close(); if (_source.is_open()) _source.close(); } void close(boost::system::error_code & ec) { if (_sink.is_open()) _sink.close(ec); if (_source.is_open()) _source.close(ec); } bool is_open() const { return _sink.is_open() || _source.is_open(); } void async_close() { if (_sink.is_open()) boost::asio::post(_sink.get_executor(), [this]{_sink.close();}); if (_source.is_open()) boost::asio::post(_source.get_executor(), [this]{_source.close();}); } template<typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence & buffers) { return _source.read_some(buffers); } template<typename MutableBufferSequence> std::size_t write_some(const MutableBufferSequence & buffers) { return _sink.write_some(buffers); } template<typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept { return _source.read_some(buffers, ec); } template<typename MutableBufferSequence> std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept { return _sink.write_some(buffers, ec); } native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();} native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();} template<typename MutableBufferSequence, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE( ReadHandler, void(boost::system::error_code, std::size_t)) async_read_some( const MutableBufferSequence & buffers, ReadHandler &&handler) { return _source.async_read_some(buffers, std::forward<ReadHandler>(handler)); } template<typename ConstBufferSequence, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE( WriteHandler, void(boost::system::error_code, std::size_t)) async_write_some( const ConstBufferSequence & buffers, WriteHandler&& handler) { return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler)); } const handle_type & sink () const & {return _sink;} const handle_type & source() const & {return _source;} handle_type && sink() && { return std::move(_sink); } handle_type && source()&& { return std::move(_source); } handle_type source(::boost::asio::io_context& ios) && { ::boost::asio::posix::stream_descriptor stolen(ios, _source.release()); return stolen; } handle_type sink (::boost::asio::io_context& ios) && { ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release()); return stolen; } handle_type source(::boost::asio::io_context& ios) const & { auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle(); return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in)); } handle_type sink (::boost::asio::io_context& ios) const & { auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle(); return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in)); } }; async_pipe::async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name) : _source(ios_source), _sink(ios_sink) { auto fifo = mkfifo(name.c_str(), 0666 ); if (fifo != 0) boost::process::detail::throw_last_error("mkfifo() failed"); int read_fd = open(name.c_str(), O_RDWR); if (read_fd == -1) boost::process::detail::throw_last_error(); int write_fd = dup(read_fd); if (write_fd == -1) boost::process::detail::throw_last_error(); _source.assign(read_fd); _sink .assign(write_fd); } async_pipe::async_pipe(const async_pipe & p) : _source(const_cast<async_pipe&>(p)._source.get_executor()), _sink( const_cast<async_pipe&>(p)._sink.get_executor()) { //cannot get the handle from a const object. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle(); auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle(); if (source_in == -1) _source.assign(-1); else { _source.assign(::dup(source_in)); if (_source.native_handle()== -1) ::boost::process::detail::throw_last_error("dup()"); } if (sink_in == -1) _sink.assign(-1); else { _sink.assign(::dup(sink_in)); if (_sink.native_handle() == -1) ::boost::process::detail::throw_last_error("dup()"); } } async_pipe& async_pipe::operator=(const async_pipe & p) { int source; int sink; //cannot get the handle from a const object. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle(); auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle(); if (source_in == -1) source = -1; else { source = ::dup(source_in); if (source == -1) ::boost::process::detail::throw_last_error("dup()"); } if (sink_in == -1) sink = -1; else { sink = ::dup(sink_in); if (sink == -1) ::boost::process::detail::throw_last_error("dup()"); } _source.assign(source); _sink. assign(sink); return *this; } async_pipe& async_pipe::operator=(async_pipe && lhs) { std::swap(_source, lhs._source); std::swap(_sink, lhs._sink); return *this; } template<class CharT, class Traits> async_pipe::operator basic_pipe<CharT, Traits>() const { int source; int sink; //cannot get the handle from a const object. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle(); auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle(); if (source_in == -1) source = -1; else { source = ::dup(source_in); if (source == -1) ::boost::process::detail::throw_last_error("dup()"); } if (sink_in == -1) sink = -1; else { sink = ::dup(sink_in); if (sink == -1) ::boost::process::detail::throw_last_error("dup()"); } return basic_pipe<CharT, Traits>{source, sink}; } inline bool operator==(const async_pipe & lhs, const async_pipe & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } }}}} #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */ detail/posix/shell_path.hpp 0000644 00000001556 15125237362 0012021 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_POSIX_SHELL_PATH_HPP #define BOOST_PROCESS_POSIX_SHELL_PATH_HPP #include <boost/process/detail/config.hpp> #include <boost/system/error_code.hpp> #include <boost/filesystem/path.hpp> namespace boost { namespace process { namespace detail { namespace posix { inline boost::filesystem::path shell_path() { return "/bin/sh"; } inline boost::filesystem::path shell_path(std::error_code &ec) { ec.clear(); return "/bin/sh"; } }}}} #endif detail/throw_on_error.hpp 0000644 00000002117 15125237362 0011576 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_INITIALIZERS_THROW_ON_ERROR_HPP #define BOOST_PROCESS_DETAIL_INITIALIZERS_THROW_ON_ERROR_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { struct throw_on_error_ : ::boost::process::detail::handler { template <class Executor> void on_error(Executor& exec, const std::error_code & ec) const { throw process_error(ec, "process creation failed"); } const throw_on_error_ &operator()() const {return *this;} }; } constexpr boost::process::detail::throw_on_error_ throw_on_error; }} #endif detail/on_exit.hpp 0000644 00000003255 15125237362 0010177 0 ustar 00 // Copyright (c) 2016 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_ON_EXIT_HPP_ #define BOOST_PROCESS_DETAIL_ON_EXIT_HPP_ #include <boost/process/detail/config.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/on_exit.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/on_exit.hpp> #endif #include <future> #include <memory> namespace boost { namespace process { namespace detail { inline std::function<void(int, const std::error_code &)> on_exit_from_future(std::future<int> &f) { std::shared_ptr<std::promise<int>> promise = std::make_shared<std::promise<int>>(); f = promise->get_future(); return [promise](int code, const std::error_code & ec) { if (ec) promise->set_exception( std::make_exception_ptr(process_error(ec, "on_exit failed with error")) ); else promise->set_value(code); }; } struct on_exit_ { api::on_exit_ operator= (const std::function<void(int, const std::error_code&)> & f) const {return f;} api::on_exit_ operator()(const std::function<void(int, const std::error_code&)> & f) const {return f;} api::on_exit_ operator= (std::future<int> &f) const {return on_exit_from_future(f);} api::on_exit_ operator()(std::future<int> &f) const {return on_exit_from_future(f);} }; } constexpr static ::boost::process::detail::on_exit_ on_exit{}; }} #endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */ detail/windows/io_context_ref.hpp 0000644 00000011663 15125237362 0013235 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_IO_CONTEXT_REF_HPP_ #define BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/windows/async_handler.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/windows/object_handle.hpp> #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <boost/fusion/algorithm/transformation/filter_if.hpp> #include <boost/fusion/algorithm/transformation/transform.hpp> #include <boost/fusion/view/transform_view.hpp> #include <boost/fusion/container/vector/convert.hpp> #include <functional> #include <type_traits> #include <memory> #include <atomic> #include <vector> #include <boost/type_index.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<typename Executor> struct on_exit_handler_transformer { Executor & exec; on_exit_handler_transformer(Executor & exec) : exec(exec) {} template<typename Sig> struct result; template<typename T> struct result<on_exit_handler_transformer<Executor>(T&)> { typedef typename T::on_exit_handler_t type; }; template<typename T> auto operator()(T& t) const -> typename T::on_exit_handler_t { return t.on_exit_handler(exec); } }; template<typename Executor> struct async_handler_collector { Executor & exec; std::vector<std::function<void(int, const std::error_code & ec)>> &handlers; async_handler_collector(Executor & exec, std::vector<std::function<void(int, const std::error_code & ec)>> &handlers) : exec(exec), handlers(handlers) {} template<typename T> void operator()(T & t) const { handlers.push_back(t.on_exit_handler(exec)); } }; //Also set's up waiting for the exit, so it can close async stuff. struct io_context_ref : boost::process::detail::handler_base { io_context_ref(boost::asio::io_context & ios) : ios(ios) { } boost::asio::io_context &get() {return ios;}; template <class Executor> void on_success(Executor& exec) const { auto asyncs = boost::fusion::filter_if< is_async_handler< typename std::remove_reference< boost::mpl::_ > ::type >>(exec.seq); //ok, check if there are actually any. if (boost::fusion::empty(asyncs)) { return; } ::boost::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info; auto this_proc = ::boost::winapi::GetCurrentProcess(); auto proc_in = proc.hProcess;; ::boost::winapi::HANDLE_ process_handle; if (!::boost::winapi::DuplicateHandle( this_proc, proc_in, this_proc, &process_handle, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) exec.set_error(::boost::process::detail::get_last_error(), "Duplicate Pipe Failed"); std::vector<std::function<void(int, const std::error_code & ec)>> funcs; funcs.reserve(boost::fusion::size(asyncs)); boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs)); wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status); auto handle_p = wh.handle.get(); handle_p->async_wait(std::move(wh)); } struct wait_handler { std::vector<std::function<void(int, const std::error_code & ec)>> funcs; std::unique_ptr<boost::asio::windows::object_handle> handle; std::shared_ptr<std::atomic<int>> exit_status; wait_handler(const wait_handler & ) = delete; wait_handler(wait_handler && ) = default; wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs, boost::asio::io_context & ios, void * handle, const std::shared_ptr<std::atomic<int>> &exit_status) : funcs(std::move(funcs)), handle(new boost::asio::windows::object_handle(ios.get_executor(), handle)), exit_status(exit_status) { } void operator()(const boost::system::error_code & ec_in) { std::error_code ec; if (ec_in) ec = std::error_code(ec_in.value(), std::system_category()); ::boost::winapi::DWORD_ code; ::boost::winapi::GetExitCodeProcess(handle->native_handle(), &code); exit_status->store(code); for (auto & func : funcs) func(code, ec); } }; private: boost::asio::io_context &ios; }; }}}} #endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */ detail/windows/null_out.hpp 0000644 00000005020 15125237362 0012055 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_NULL_OUT_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/handle_info.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/file_descriptor.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<int p1, int p2> struct null_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles { file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch. ::boost::winapi::HANDLE_ get_used_handles() const { return sink.handle(); } template <typename WindowsExecutor> void on_setup(WindowsExecutor &e) const; }; template<> template<typename WindowsExecutor> void null_out<1,-1>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(sink.handle(), boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = sink.handle(); e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<> template<typename WindowsExecutor> void null_out<2,-1>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(sink.handle(), boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdError = sink.handle(); e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<> template<typename WindowsExecutor> void null_out<1,2>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(sink.handle(), boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = sink.handle(); e.startup_info.hStdError = sink.handle(); e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } }}}} #endif detail/windows/basic_pipe.hpp 0000644 00000020403 15125237362 0012314 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_PIPE_HPP #define BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP #include <boost/winapi/basic_types.hpp> #include <boost/winapi/error_codes.hpp> #include <boost/winapi/pipes.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/file_management.hpp> #include <boost/winapi/get_last_error.hpp> #include <boost/winapi/access_rights.hpp> #include <boost/winapi/process.hpp> #include <boost/process/detail/windows/compare_handles.hpp> #include <system_error> #include <string> namespace boost { namespace process { namespace detail { namespace windows { template<class CharT, class Traits = std::char_traits<CharT>> class basic_pipe { ::boost::winapi::HANDLE_ _source = ::boost::winapi::INVALID_HANDLE_VALUE_; ::boost::winapi::HANDLE_ _sink = ::boost::winapi::INVALID_HANDLE_VALUE_; public: typedef CharT char_type ; typedef Traits traits_type; typedef typename Traits::int_type int_type ; typedef typename Traits::pos_type pos_type ; typedef typename Traits::off_type off_type ; typedef ::boost::winapi::HANDLE_ native_handle_type; explicit basic_pipe(::boost::winapi::HANDLE_ source, ::boost::winapi::HANDLE_ sink) : _source(source), _sink(sink) {} inline explicit basic_pipe(const std::string & name); inline basic_pipe(const basic_pipe& p); basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink) { lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_; lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_; } inline basic_pipe& operator=(const basic_pipe& p); inline basic_pipe& operator=(basic_pipe&& lhs); ~basic_pipe() { if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::winapi::CloseHandle(_sink); if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::winapi::CloseHandle(_source); } native_handle_type native_source() const {return _source;} native_handle_type native_sink () const {return _sink;} void assign_source(native_handle_type h) { _source = h;} void assign_sink (native_handle_type h) { _sink = h;} basic_pipe() { if (!::boost::winapi::CreatePipe(&_source, &_sink, nullptr, 0)) throw_last_error("CreatePipe() failed"); } int_type write(const char_type * data, int_type count) { ::boost::winapi::DWORD_ write_len; if (!::boost::winapi::WriteFile( _sink, data, count * sizeof(char_type), &write_len, nullptr )) { auto ec = ::boost::process::detail::get_last_error(); if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) || (ec.value() == ::boost::winapi::ERROR_NO_DATA_)) return 0; else throw process_error(ec, "WriteFile failed"); } return static_cast<int_type>(write_len); } int_type read(char_type * data, int_type count) { ::boost::winapi::DWORD_ read_len; if (!::boost::winapi::ReadFile( _source, data, count * sizeof(char_type), &read_len, nullptr )) { auto ec = ::boost::process::detail::get_last_error(); if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) || (ec.value() == ::boost::winapi::ERROR_NO_DATA_)) return 0; else throw process_error(ec, "ReadFile failed"); } return static_cast<int_type>(read_len); } bool is_open() const { return (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) || (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_); } void close() { ::boost::winapi::CloseHandle(_source); ::boost::winapi::CloseHandle(_sink); _source = ::boost::winapi::INVALID_HANDLE_VALUE_; _sink = ::boost::winapi::INVALID_HANDLE_VALUE_; } }; template<class Char, class Traits> basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p) { auto proc = ::boost::winapi::GetCurrentProcess(); if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_) _source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, p._source, proc, &_source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_) _sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, p._sink, proc, &_sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); } template<class Char, class Traits> basic_pipe<Char, Traits>::basic_pipe(const std::string & name) { static constexpr int OPEN_EXISTING_ = 3; //temporary. static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary //static constexpr int FILE_ATTRIBUTE_NORMAL_ = 0x00000080; //temporary #if BOOST_NO_ANSI_APIS std::wstring name_ = boost::process::detail::convert(name); #else auto &name_ = name; #endif ::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe( name_.c_str(), ::boost::winapi::PIPE_ACCESS_INBOUND_ | FILE_FLAG_OVERLAPPED_, //write flag 0, ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr); if (source == boost::winapi::INVALID_HANDLE_VALUE_) ::boost::process::detail::throw_last_error("create_named_pipe() failed"); ::boost::winapi::HANDLE_ sink = boost::winapi::create_file( name.c_str(), ::boost::winapi::GENERIC_WRITE_, 0, nullptr, OPEN_EXISTING_, FILE_FLAG_OVERLAPPED_, //to allow read nullptr); if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::process::detail::throw_last_error("create_file() failed"); _source = source; _sink = sink; } template<class Char, class Traits> basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe & p) { auto proc = ::boost::winapi::GetCurrentProcess(); if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_) _source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, p._source, proc, &_source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_) _sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, p._sink, proc, &_sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); return *this; } template<class Char, class Traits> basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(basic_pipe && lhs) { if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::winapi::CloseHandle(_source); if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::winapi::CloseHandle(_sink); _source = lhs._source; _sink = lhs._sink; lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_; lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_; return *this; } template<class Char, class Traits> inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } }}}} #endif detail/windows/handle_workaround.hpp 0000644 00000021334 15125237362 0013730 0 ustar 00 // Copyright (c) 2018 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_WINDOWS_HANDLE_WORKAROUND_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_HANDLE_WORKAROUND_HPP_ #include <boost/winapi/basic_types.hpp> #include <boost/winapi/dll.hpp> #include <boost/winapi/access_rights.hpp> //#define BOOST_USE_WINDOWS_H 1 #if defined( BOOST_USE_WINDOWS_H ) #include <Winternl.h> #endif namespace boost { namespace process { namespace detail { namespace windows { namespace workaround { typedef struct _SYSTEM_HANDLE_ENTRY_ { ::boost::winapi::ULONG_ OwnerPid; ::boost::winapi::BYTE_ ObjectType; ::boost::winapi::BYTE_ HandleFlags; ::boost::winapi::USHORT_ HandleValue; ::boost::winapi::PVOID_ ObjectPointer; ::boost::winapi::ULONG_ AccessMask; } SYSTEM_HANDLE_ENTRY_, *PSYSTEM_HANDLE_ENTRY_; typedef struct _SYSTEM_HANDLE_INFORMATION_ { ::boost::winapi::ULONG_ Count; SYSTEM_HANDLE_ENTRY_ Handle[1]; } SYSTEM_HANDLE_INFORMATION_, *PSYSTEM_HANDLE_INFORMATION_; #if defined( BOOST_USE_WINDOWS_H ) using UNICODE_STRING_ = ::UNICODE_STRING; using GENERIC_MAPPING_ = ::GENERIC_MAPPING; using OBJECT_INFORMATION_CLASS_ = ::OBJECT_INFORMATION_CLASS; constexpr static OBJECT_INFORMATION_CLASS_ ObjectTypeInformation = ::OBJECT_INFORMATION_CLASS::ObjectTypeInformation; typedef struct _OBJECT_TYPE_INFORMATION_ { UNICODE_STRING TypeName; ULONG TotalNumberOfObjects; ULONG TotalNumberOfHandles; ULONG TotalPagedPoolUsage; ULONG TotalNonPagedPoolUsage; ULONG TotalNamePoolUsage; ULONG TotalHandleTableUsage; ULONG HighWaterNumberOfObjects; ULONG HighWaterNumberOfHandles; ULONG HighWaterPagedPoolUsage; ULONG HighWaterNonPagedPoolUsage; ULONG HighWaterNamePoolUsage; ULONG HighWaterHandleTableUsage; ULONG InvalidAttributes; GENERIC_MAPPING GenericMapping; ULONG ValidAccessMask; BOOLEAN SecurityRequired; BOOLEAN MaintainHandleCount; UCHAR TypeIndex; CHAR ReservedByte; ULONG PoolType; ULONG DefaultPagedPoolCharge; ULONG DefaultNonPagedPoolCharge; } OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_; #else typedef enum _OBJECT_INFORMATION_CLASS_ { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllInformation, ObjectDataInformation } OBJECT_INFORMATION_CLASS_, *POBJECT_INFORMATION_CLASS_; typedef struct _UNICODE_STRING_ { ::boost::winapi::USHORT_ Length; ::boost::winapi::USHORT_ MaximumLength; ::boost::winapi::LPWSTR_ Buffer; } UNICODE_STRING_, *PUNICODE_STRING_; typedef struct _GENERIC_MAPPING_ { ::boost::winapi::ACCESS_MASK_ GenericRead; ::boost::winapi::ACCESS_MASK_ GenericWrite; ::boost::winapi::ACCESS_MASK_ GenericExecute; ::boost::winapi::ACCESS_MASK_ GenericAll; } GENERIC_MAPPING_; #endif typedef struct _OBJECT_BASIC_INFORMATION { ::boost::winapi::ULONG_ Attributes; ::boost::winapi::ACCESS_MASK_ GrantedAccess; ::boost::winapi::ULONG_ HandleCount; ::boost::winapi::ULONG_ PointerCount; ::boost::winapi::ULONG_ PagedPoolUsage; ::boost::winapi::ULONG_ NonPagedPoolUsage; ::boost::winapi::ULONG_ Reserved[3]; ::boost::winapi::ULONG_ NameInformationLength; ::boost::winapi::ULONG_ TypeInformationLength; ::boost::winapi::ULONG_ SecurityDescriptorLength; ::boost::winapi::LARGE_INTEGER_ CreateTime; } OBJECT_BASIC_INFORMATION_, *POBJECT_BASIC_INFORMATION_; typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING_ Name; } OBJECT_NAME_INFORMATION_, *POBJECT_NAME_INFORMATION_; #if defined( BOOST_USE_WINDOWS_H ) extern "C" { using SYSTEM_INFORMATION_CLASS_ = ::SYSTEM_INFORMATION_CLASS; constexpr static SYSTEM_INFORMATION_CLASS_ SystemHandleInformation_ = static_cast<SYSTEM_INFORMATION_CLASS_>(16); inline ::boost::winapi::NTSTATUS_ nt_system_query_information( SYSTEM_INFORMATION_CLASS SystemInformationClass, void * SystemInformation, ::boost::winapi::ULONG_ SystemInformationLength, ::boost::winapi::PULONG_ ReturnLength) { return ::NtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); } inline ::boost::winapi::NTSTATUS_ nt_query_object( ::boost::winapi::HANDLE_ Handle, OBJECT_INFORMATION_CLASS_ ObjectInformationClass, ::boost::winapi::PVOID_ ObjectInformation, ::boost::winapi::ULONG_ ObjectInformationLength, ::boost::winapi::PULONG_ ReturnLength ) { return ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); } } #else //this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi. extern "C" { typedef enum _SYSTEM_INFORMATION_CLASS_ { SystemBasicInformation_ = 0, SystemProcessorInformation_ = 1, SystemPerformanceInformation_ = 2, SystemTimeOfDayInformation_ = 3, SystemProcessInformation_ = 5, SystemProcessorPerformanceInformation_ = 8, SystemHandleInformation_ = 16, SystemPagefileInformation_ = 18, SystemInterruptInformation_ = 23, SystemExceptionInformation_ = 33, SystemRegistryQuotaInformation_ = 37, SystemLookasideInformation_ = 45 } SYSTEM_INFORMATION_CLASS_; typedef struct _OBJECT_TYPE_INFORMATION_ { UNICODE_STRING_ TypeName; ::boost::winapi::ULONG_ TotalNumberOfObjects; ::boost::winapi::ULONG_ TotalNumberOfHandles; ::boost::winapi::ULONG_ TotalPagedPoolUsage; ::boost::winapi::ULONG_ TotalNonPagedPoolUsage; ::boost::winapi::ULONG_ TotalNamePoolUsage; ::boost::winapi::ULONG_ TotalHandleTableUsage; ::boost::winapi::ULONG_ HighWaterNumberOfObjects; ::boost::winapi::ULONG_ HighWaterNumberOfHandles; ::boost::winapi::ULONG_ HighWaterPagedPoolUsage; ::boost::winapi::ULONG_ HighWaterNonPagedPoolUsage; ::boost::winapi::ULONG_ HighWaterNamePoolUsage; ::boost::winapi::ULONG_ HighWaterHandleTableUsage; ::boost::winapi::ULONG_ InvalidAttributes; GENERIC_MAPPING_ GenericMapping; ::boost::winapi::ULONG_ ValidAccessMask; ::boost::winapi::BOOLEAN_ SecurityRequired; ::boost::winapi::BOOLEAN_ MaintainHandleCount; ::boost::winapi::UCHAR_ TypeIndex; ::boost::winapi::CHAR_ ReservedByte; ::boost::winapi::ULONG_ PoolType; ::boost::winapi::ULONG_ DefaultPagedPoolCharge; ::boost::winapi::ULONG_ DefaultNonPagedPoolCharge; } OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_; /* __kernel_entry NTSTATUS NtQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength ); */ typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_system_query_information_p )( SYSTEM_INFORMATION_CLASS_, void *, ::boost::winapi::ULONG_, ::boost::winapi::PULONG_); /* __kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject( HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength ); */ typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_query_object_p )( ::boost::winapi::HANDLE_, OBJECT_INFORMATION_CLASS_, void *, ::boost::winapi::ULONG_, ::boost::winapi::PULONG_); } inline ::boost::winapi::NTSTATUS_ nt_system_query_information( SYSTEM_INFORMATION_CLASS_ SystemInformationClass, void *SystemInformation, ::boost::winapi::ULONG_ SystemInformationLength, ::boost::winapi::PULONG_ ReturnLength) { static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll"); static nt_system_query_information_p f = reinterpret_cast<nt_system_query_information_p>(::boost::winapi::get_proc_address(h, "NtQuerySystemInformation")); return (*f)(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); } inline ::boost::winapi::BOOL_ nt_query_object( ::boost::winapi::HANDLE_ Handle, OBJECT_INFORMATION_CLASS_ ObjectInformationClass, void *ObjectInformation, ::boost::winapi::ULONG_ ObjectInformationLength, ::boost::winapi::PULONG_ ReturnLength) { static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll"); static nt_query_object_p f = reinterpret_cast<nt_query_object_p>(::boost::winapi::get_proc_address(h, "NtQueryObject")); return (*f)(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); } #endif }}}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */ detail/windows/search_path.hpp 0000644 00000005370 15125237362 0012505 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_SEARCH_PATH_HPP #define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP #include <boost/process/detail/config.hpp> #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> #include <boost/system/error_code.hpp> #include <string> #include <stdexcept> #include <array> #include <atomic> #include <cstdlib> #include <boost/winapi/shell.hpp> #include <boost/process/environment.hpp> namespace boost { namespace process { namespace detail { namespace windows { inline boost::filesystem::path search_path( const boost::filesystem::path &filename, const std::vector<boost::filesystem::path> &path) { const ::boost::process::wnative_environment ne{}; typedef typename ::boost::process::wnative_environment::const_entry_type value_type; const auto id = L"PATHEXT"; auto itr = std::find_if(ne.cbegin(), ne.cend(), [&](const value_type & e) {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());}); auto extensions_in = itr->to_vector(); std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1); auto it_ex = extensions.begin(); it_ex++; it_ex = std::transform(extensions_in.begin(), extensions_in.end(), it_ex, [](const std::wstring & ws){return boost::to_lower_copy(ws, ::boost::process::detail::process_locale());}); std::transform(extensions_in.begin(), extensions_in.end(), it_ex, [](const std::wstring & ws){return boost::to_upper_copy(ws, ::boost::process::detail::process_locale());}); std::copy(std::make_move_iterator(extensions_in.begin()), std::make_move_iterator(extensions_in.end()), extensions.begin() + 1); for (auto & ext : extensions) boost::to_lower(ext); for (const boost::filesystem::path & pp_ : path) { auto p = pp_ / filename; for (boost::filesystem::path ext : extensions) { boost::filesystem::path pp_ext = p; pp_ext += ext; boost::system::error_code ec; bool file = boost::filesystem::is_regular_file(pp_ext, ec); if (!ec && file && ::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_)) { return pp_ext; } } } return ""; } }}}} #endif detail/windows/async_out.hpp 0000644 00000013677 15125237362 0012241 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/handle_info.hpp> #include <boost/winapi/error_codes.hpp> #include <boost/asio/read.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/asio_fwd.hpp> #include <istream> #include <memory> #include <exception> #include <future> namespace boost { namespace process { namespace detail { namespace windows { template <typename Executor> inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>) { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template <typename Executor> inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>) { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdError = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template <typename Executor> inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>) { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = handle; e.startup_info.hStdError = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<int p1, int p2, typename Buffer> struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext, ::boost::process::detail::windows::require_io_context { Buffer & buf; std::shared_ptr<boost::process::async_pipe> pipe; async_out_buffer(Buffer & buf) : buf(buf) { } template <typename Executor> inline void on_success(Executor&) { auto pipe_ = this->pipe; boost::asio::async_read(*pipe_, buf, [pipe_](const boost::system::error_code&, std::size_t){}); std::move(*pipe_).sink().close(); this->pipe = nullptr; } template<typename Executor> void on_error(Executor &, const std::error_code &) const { std::move(*pipe).sink().close(); } template <typename WindowsExecutor> void on_setup(WindowsExecutor &exec) { if (!pipe) pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); apply_out_handles(exec, std::move(*pipe).sink().native_handle(), std::integral_constant<int, p1>(), std::integral_constant<int, p2>()); } }; template<int p1, int p2, typename Type> struct async_out_future : ::boost::process::detail::windows::handler_base_ext, ::boost::process::detail::windows::require_io_context, ::boost::process::detail::uses_handles { std::shared_ptr<boost::process::async_pipe> pipe; std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>(); std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>(); ::boost::winapi::HANDLE_ get_used_handles() const { return std::move(*pipe).sink().native_handle(); } async_out_future(std::future<Type> & fut) { fut = promise->get_future(); } template <typename Executor> inline void on_success(Executor&) { auto pipe_ = this->pipe; auto buffer_ = this->buffer; auto promise_ = this->promise; std::move(*pipe_).sink().close(); boost::asio::async_read(*pipe_, *buffer_, [pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t) { if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_)) { std::error_code e(ec.value(), std::system_category()); promise_->set_exception(std::make_exception_ptr(process_error(e))); } else { std::istream is (buffer_.get()); Type arg; if (buffer_->size() > 0) { arg.resize(buffer_->size()); is.read(&*arg.begin(), buffer_->size()); } promise_->set_value(std::move(arg)); } }); this->pipe = nullptr; this->buffer = nullptr; this->promise = nullptr; } template<typename Executor> void on_error(Executor &, const std::error_code &) const { std::move(*pipe).sink().close(); } template <typename WindowsExecutor> void on_setup(WindowsExecutor &exec) { if (!pipe) pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); apply_out_handles(exec, std::move(*pipe).sink().native_handle(), std::integral_constant<int, p1>(), std::integral_constant<int, p2>()); } }; }}}} #endif detail/windows/start_dir.hpp 0000644 00000002002 15125237362 0012204 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_START_DIR_HPP #define BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP #include <string> #include <boost/process/detail/windows/handler.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<typename Char> struct start_dir_init : handler_base_ext { start_dir_init(const std::basic_string<Char> &s) : s_(s) {} template <class Executor> void on_setup(Executor& exec) const { exec.work_dir = s_.c_str(); } const std::basic_string<Char> &str() const {return s_;} private: std::basic_string<Char> s_; }; }}}} #endif detail/windows/pipe_out.hpp 0000644 00000006717 15125237362 0012056 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_WINDOWS_PIPE_OUT_HPP #define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<int p1, int p2> struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles { ::boost::winapi::HANDLE_ handle; ::boost::winapi::HANDLE_ get_used_handles() const { return handle; } pipe_out(::boost::winapi::HANDLE_ handle) : handle(handle) {} template<typename T> pipe_out(T & p) : handle(p.native_sink()) { p.assign_sink(::boost::winapi::INVALID_HANDLE_VALUE_); } template<typename WindowsExecutor> void on_setup(WindowsExecutor &e) const; template<typename WindowsExecutor> void on_error(WindowsExecutor &, const std::error_code &) const { ::boost::winapi::CloseHandle(handle); } template<typename WindowsExecutor> void on_success(WindowsExecutor &) const { ::boost::winapi::CloseHandle(handle); } }; template<> template<typename WindowsExecutor> void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<> template<typename WindowsExecutor> void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdError = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<> template<typename WindowsExecutor> void pipe_out<1,2>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = handle; e.startup_info.hStdError = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<int p1, int p2> struct async_pipe_out : public pipe_out<p1, p2> { async_pipe &pipe; template<typename AsyncPipe> async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink()), pipe(p) { } template<typename Pipe, typename Executor> static void close(Pipe & pipe, Executor &) { boost::system::error_code ec; std::move(pipe).sink().close(ec); } template<typename Executor> void on_error(Executor & exec, const std::error_code &) { close(pipe, exec); } template<typename Executor> void on_success(Executor &exec) { close(pipe, exec); } }; }}}} #endif detail/windows/wait_group.hpp 0000644 00000010361 15125237362 0012400 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_WAIT_GROUP_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/windows/group_handle.hpp> #include <boost/winapi/jobs.hpp> #include <boost/winapi/wait.hpp> #include <chrono> namespace boost { namespace process { namespace detail { namespace windows { struct group_handle; inline bool wait_impl(const group_handle & p, std::error_code & ec, std::chrono::system_clock::rep wait_time) { ::boost::winapi::DWORD_ completion_code; ::boost::winapi::ULONG_PTR_ completion_key; ::boost::winapi::LPOVERLAPPED_ overlapped; auto start_time = std::chrono::system_clock::now(); while (workaround::get_queued_completion_status( p._io_port, &completion_code, &completion_key, &overlapped, static_cast<::boost::winapi::DWORD_>(wait_time))) { if (reinterpret_cast<::boost::winapi::HANDLE_>(completion_key) == p._job_object && completion_code == workaround::JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_) { //double check, could be a different handle from a child workaround::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ info; if (!workaround::query_information_job_object( p._job_object, workaround::JobObjectBasicAccountingInformation_, static_cast<void *>(&info), sizeof(info), nullptr)) { ec = get_last_error(); return false; } else if (info.ActiveProcesses == 0) return false; //correct, nothing left. } //reduce the remaining wait time -> in case interrupted by something else if (wait_time != static_cast<int>(::boost::winapi::infinite)) { auto now = std::chrono::system_clock::now(); auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); wait_time -= static_cast<std::chrono::system_clock::rep>(diff.count()); start_time = now; if (wait_time <= 0) return true; //timeout with other source } } auto ec_ = get_last_error(); if (ec_.value() == ::boost::winapi::wait_timeout) return true; //timeout ec = ec_; return false; } inline void wait(const group_handle &p, std::error_code &ec) { wait_impl(p, ec, ::boost::winapi::infinite); } inline void wait(const group_handle &p) { std::error_code ec; wait(p, ec); boost::process::detail::throw_error(ec, "wait error"); } template< class Clock, class Duration > inline bool wait_until( const group_handle &p, const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code &ec) { std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>( timeout_time - Clock::now()); auto timeout = wait_impl(p, ec, ms.count()); return !ec && !timeout; } template< class Clock, class Duration > inline bool wait_until( const group_handle &p, const std::chrono::time_point<Clock, Duration>& timeout_time) { std::error_code ec; bool b = wait_until(p, timeout_time, ec); boost::process::detail::throw_error(ec, "wait_until error"); return b; } template< class Rep, class Period > inline bool wait_for( const group_handle &p, const std::chrono::duration<Rep, Period>& rel_time, std::error_code &ec) { auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); auto timeout = wait_impl(p, ec, ms.count()); return !ec && !timeout; } template< class Rep, class Period > inline bool wait_for( const group_handle &p, const std::chrono::duration<Rep, Period>& rel_time) { std::error_code ec; bool b = wait_for(p, rel_time, ec); boost::process::detail::throw_error(ec, "wait_for error"); return b; } }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_ */ detail/windows/close_in.hpp 0000644 00000002020 15125237362 0012004 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_CLOSE_IN_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace windows { struct close_in : public ::boost::process::detail::handler_base { template <class WindowsExecutor> void on_setup(WindowsExecutor &e) const { e.startup_info.hStdInput = boost::winapi::INVALID_HANDLE_VALUE_; e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_; } }; }}}} #endif detail/windows/null_in.hpp 0000644 00000003027 15125237362 0011661 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_NULL_IN_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/handle_info.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/file_descriptor.hpp> namespace boost { namespace process { namespace detail { namespace windows { struct null_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles { file_descriptor source{"NUL", file_descriptor::read}; ::boost::winapi::HANDLE_ get_used_handles() const { return source.handle(); } public: template <class WindowsExecutor> void on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(source.handle(), boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdInput = source.handle(); e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } }; }}}} #endif detail/windows/compare_handles.hpp 0000644 00000002720 15125237362 0013344 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_COMPARE_HANDLES_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_ #include <boost/winapi/handles.hpp> #include <boost/winapi/file_management.hpp> #include <boost/process/detail/config.hpp> namespace boost { namespace process { namespace detail { namespace windows { inline bool compare_handles(boost::winapi::HANDLE_ lhs, boost::winapi::HANDLE_ rhs) { if ( (lhs == ::boost::winapi::INVALID_HANDLE_VALUE_) || (rhs == ::boost::winapi::INVALID_HANDLE_VALUE_)) return false; if (lhs == rhs) return true; ::boost::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0}; ::boost::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0}; if (!::boost::winapi::GetFileInformationByHandle(lhs, &lhs_info)) ::boost::process::detail::throw_last_error("GetFileInformationByHandle"); if (!::boost::winapi::GetFileInformationByHandle(rhs, &rhs_info)) ::boost::process::detail::throw_last_error("GetFileInformationByHandle"); return (lhs_info.nFileIndexHigh == rhs_info.nFileIndexHigh) && (lhs_info.nFileIndexLow == rhs_info.nFileIndexLow); } }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_ */ detail/windows/pipe_in.hpp 0000644 00000005013 15125237362 0011641 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_PIPE_IN_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace windows { struct pipe_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles { ::boost::winapi::HANDLE_ handle; ::boost::winapi::HANDLE_ get_used_handles() const { return handle; } pipe_in(::boost::winapi::HANDLE_ handle) : handle(handle) {} template<typename T> //async_pipe pipe_in(T & p) : handle(p.native_source()) { p.assign_source(::boost::winapi::INVALID_HANDLE_VALUE_); } template <class WindowsExecutor> void on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdInput = handle; e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<typename WindowsExecutor> void on_error(WindowsExecutor &, const std::error_code &) const { ::boost::winapi::CloseHandle(handle); } template<typename WindowsExecutor> void on_success(WindowsExecutor &) const { ::boost::winapi::CloseHandle(handle); } }; class async_pipe; struct async_pipe_in : public pipe_in { async_pipe &pipe; template<typename AsyncPipe> async_pipe_in(AsyncPipe & p) : pipe_in(p.native_source()), pipe(p) { } template<typename Pipe, typename Executor> static void close(Pipe & pipe, Executor &) { boost::system::error_code ec; std::move(pipe).source().close(ec); } template<typename Executor> void on_error(Executor & exec, const std::error_code &) { close(pipe, exec); } template<typename Executor> void on_success(Executor &exec) { close(pipe, exec); } }; }}}} #endif detail/windows/handler.hpp 0000644 00000001066 15125237362 0011637 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_HANDLER_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace windows { //does not extend anything. struct handler_base_ext : handler_base {}; }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */ detail/windows/environment.hpp 0000644 00000025340 15125237362 0012567 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_ENV_STORAGE_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ #include <string> #include <vector> #include <unordered_map> #include <boost/winapi/error_codes.hpp> #include <boost/winapi/environment.hpp> #include <boost/winapi/get_current_process.hpp> #include <boost/winapi/get_current_process_id.hpp> #include <boost/process/detail/config.hpp> #include <algorithm> #include <boost/process/locale.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<typename Char> class native_environment_impl { static void _deleter(Char* p) {boost::winapi::free_environment_strings(p);}; std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter}; static inline std::vector<Char*> _load_var(Char* p); std::vector<Char*> _env_arr{_load_var(_buf.get())}; public: using char_type = Char; using pointer_type = const char_type*; using string_type = std::basic_string<char_type>; using native_handle_type = pointer_type; void reload() { _buf.reset(boost::winapi::get_environment_strings<Char>()); _env_arr = _load_var(_buf.get()); _env_impl = &*_env_arr.begin(); } string_type get(const pointer_type id); void set(const pointer_type id, const pointer_type value); void reset(const pointer_type id); string_type get(const string_type & id) {return get(id.c_str());} void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); } void reset(const string_type & id) {reset(id.c_str());} native_environment_impl() = default; native_environment_impl(const native_environment_impl& ) = delete; native_environment_impl(native_environment_impl && ) = default; native_environment_impl & operator=(const native_environment_impl& ) = delete; native_environment_impl & operator=(native_environment_impl && ) = default; Char ** _env_impl = &*_env_arr.begin(); native_handle_type native_handle() const {return _buf.get();} }; template<typename Char> inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type { Char buf[4096]; auto size = boost::winapi::get_environment_variable(id, buf, sizeof(buf)); if (size == 0) //failed { auto err = ::boost::winapi::GetLastError(); if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value return ""; else throw process_error(std::error_code(err, std::system_category()), "GetEnvironmentVariable() failed"); } if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong { /*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx * but I used 32768 so it is a multiple of 4096. */ constexpr static std::size_t max_size = 32768; //Handle variables longer then buf. std::size_t buf_size = sizeof(buf); while (buf_size <= max_size) { std::vector<Char> buf(buf_size); auto size = boost::winapi::get_environment_variable(id, buf.data(), buf.size()); if (size == buf_size) //buffer to small buf_size *= 2; else if (size == 0) ::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed"); else return std::basic_string<Char>( buf.data(), buf.data()+ size + 1); } } return std::basic_string<Char>(buf, buf+size+1); } template<typename Char> inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value) { boost::winapi::set_environment_variable(id, value); } template<typename Char> inline void native_environment_impl<Char>::reset(const pointer_type id) { boost::winapi::set_environment_variable(id, nullptr); } template<typename Char> std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p) { std::vector<Char*> ret; if (*p != null_char<Char>()) { ret.push_back(p); while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>())) { if (*p==null_char<Char>()) { p++; ret.push_back(p); } else p++; } } p++; ret.push_back(nullptr); return ret; } template<typename Char> struct basic_environment_impl { std::vector<Char> _data = {null_char<Char>()}; static std::vector<Char*> _load_var(Char* p); std::vector<Char*> _env_arr{_load_var(_data.data())}; public: using char_type = Char; using pointer_type = const char_type*; using string_type = std::basic_string<char_type>; using native_handle_type = pointer_type; std::size_t size() const { return _data.size();} void reload() { _env_arr = _load_var(_data.data()); _env_impl = _env_arr.data(); } string_type get(const pointer_type id) {return get(string_type(id));} void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);} void reset(const pointer_type id) {reset(string_type(id));} string_type get(const string_type & id); void set(const string_type & id, const string_type & value); void reset(const string_type & id); inline basic_environment_impl(const native_environment_impl<Char> & nei); basic_environment_impl() = default; basic_environment_impl(const basic_environment_impl& rhs) : _data(rhs._data) { } basic_environment_impl(basic_environment_impl && rhs) : _data(std::move(rhs._data)), _env_arr(std::move(rhs._env_arr)), _env_impl(_env_arr.data()) { } basic_environment_impl &operator=(basic_environment_impl && rhs) { _data = std::move(rhs._data); //reload(); _env_arr = std::move(rhs._env_arr); _env_impl = _env_arr.data(); return *this; } basic_environment_impl & operator=(const basic_environment_impl& rhs) { _data = rhs._data; reload(); return *this; } template<typename CharR> explicit inline basic_environment_impl( const basic_environment_impl<CharR>& rhs, const ::boost::process::codecvt_type & cv = ::boost::process::codecvt()) : _data(::boost::process::detail::convert(rhs._data, cv)) { } template<typename CharR> basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs) { _data = ::boost::process::detail::convert(rhs._data); _env_arr = _load_var(&*_data.begin()); _env_impl = &*_env_arr.begin(); return *this; } Char ** _env_impl = &*_env_arr.begin(); native_handle_type native_handle() const {return &*_data.begin();} }; template<typename Char> basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei) { auto beg = nei.native_handle(); auto p = beg; while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>())) p++; p++; //pointing to the second nullchar p++; //to get the pointer behing the second nullchar, so it's end. this->_data.assign(beg, p); this->reload(); } template<typename Char> inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type { if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>())) return string_type(_data.data()); //null-char is handled by the string. std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars seq.insert(seq.end(), id.begin(), id.end()); seq.push_back('='); auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end()); if (itr == _data.end()) //not found return ""; itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char. return string_type(&*itr); } template<typename Char> inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value) { reset(id); std::vector<Char> insertion; insertion.insert(insertion.end(), id.begin(), id.end()); insertion.push_back('='); insertion.insert(insertion.end(), value.begin(), value.end()); insertion.push_back('\0'); _data.insert(_data.end() -1, insertion.begin(), insertion.end()); reload(); } template<typename Char> inline void basic_environment_impl<Char>::reset(const string_type &id) { //ok, we need to check the size of data first if (id.size() >= _data.size()) //ok, so it's impossible id is in there. return; //check if it's the first one, spares us the search. if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>())) { auto beg = _data.begin(); auto end = beg; while (*end != '\0') end++; end++; //to point behind the last null-char _data.erase(beg, end); //and remove the thingy } std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars seq.insert(seq.end(), id.begin(), id.end()); seq.push_back('='); auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end()); if (itr == _data.end()) return;//nothing to return if it's empty anyway... auto end = itr; while (*++end != '\0'); _data.erase(itr, end);//and remove it reload(); } template<typename Char> std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p) { std::vector<Char*> ret; if (*p != null_char<Char>()) { ret.push_back(p); while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>())) { if (*p==null_char<Char>()) { p++; ret.push_back(p); } else p++; } } p++; ret.push_back(nullptr); return ret; } template<typename T> constexpr T env_seperator(); template<> constexpr char env_seperator() {return ';'; } template<> constexpr wchar_t env_seperator() {return L';'; } inline int get_id() {return boost::winapi::GetCurrentProcessId();} inline void* native_handle() {return boost::winapi::GetCurrentProcess(); } typedef void* native_handle_t; } } } } #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */ detail/windows/asio_fwd.hpp 0000644 00000002512 15125237362 0012012 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_ASIO_FWD_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_ #include <memory> #include <boost/asio/ts/netfwd.hpp> namespace boost { namespace asio { class mutable_buffer; class mutable_buffers_1; class const_buffer; class const_buffers_1; template<typename Allocator> class basic_streambuf; typedef basic_streambuf<std::allocator<char>> streambuf; template <typename Handler> class basic_yield_context; namespace windows { template <typename Executor> class basic_stream_handle; typedef basic_stream_handle<any_io_executor> stream_handle; template <typename Executor> class basic_object_handle; typedef basic_object_handle<any_io_executor> object_handle; } //windows } //asio namespace process { namespace detail { namespace windows { class async_pipe; template<typename T> struct async_in_buffer; template<int p1, int p2, typename Buffer> struct async_out_buffer; template<int p1, int p2, typename Type> struct async_out_future; } // windows } // detail using ::boost::process::detail::windows::async_pipe; } // process } // boost #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_ */ detail/windows/is_running.hpp 0000644 00000002603 15125237362 0012373 0 ustar 00 // Copyright (c) 2106 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_WINDOWS_IS_RUNNING_HPP #define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP #include <boost/process/detail/config.hpp> #include <system_error> #include <cstdlib> #include <boost/winapi/process.hpp> namespace boost { namespace process { namespace detail { namespace windows { constexpr static ::boost::winapi::DWORD_ still_active = 259; struct child_handle; inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept { ::boost::winapi::DWORD_ code; //single value, not needed in the winapi. if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code)) ec = ::boost::process::detail::get_last_error(); else ec.clear(); if (code == still_active) return true; else { exit_code = code; return false; } } inline bool is_running(const child_handle &p, int & exit_code) { std::error_code ec; bool b = is_running(p, exit_code, ec); boost::process::detail::throw_error(ec, "GetExitCodeProcess() failed in is_running"); return b; } inline bool is_running(int code) { return code == still_active; } inline int eval_exit_status(int in ) {return in;} }}}} #endif detail/windows/file_in.hpp 0000644 00000003307 15125237362 0011627 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_FILE_IN_HPP #define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/file_descriptor.hpp> #include <io.h> namespace boost { namespace process { namespace detail { namespace windows { struct file_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles { file_descriptor file; ::boost::winapi::HANDLE_ handle = file.handle(); ::boost::winapi::HANDLE_ get_used_handles() const { return handle; } template<typename T> file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {} file_in(FILE * f) : handle(reinterpret_cast<::boost::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {} template <class WindowsExecutor> void on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdInput = handle; e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } }; }}}} #endif detail/windows/file_out.hpp 0000644 00000005203 15125237362 0012025 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_FILE_OUT_HPP #define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/handle_info.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/file_descriptor.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<int p1, int p2> struct file_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles { file_descriptor file; ::boost::winapi::HANDLE_ handle = file.handle(); ::boost::winapi::HANDLE_ get_used_handles() const { return handle; } template<typename T> file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {} file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {} template <typename WindowsExecutor> inline void on_setup(WindowsExecutor &e) const; }; template<> template<typename WindowsExecutor> void file_out<1,-1>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<> template<typename WindowsExecutor> void file_out<2,-1>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdError = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } template<> template<typename WindowsExecutor> void file_out<1,2>::on_setup(WindowsExecutor &e) const { boost::winapi::SetHandleInformation(handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); e.startup_info.hStdOutput = handle; e.startup_info.hStdError = handle; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; e.inherit_handles = true; } }}}} #endif detail/windows/cmd.hpp 0000644 00000001741 15125237362 0010765 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_CMD_HPP_ #define BOOST_PROCESS_WINDOWS_CMD_HPP_ #include <string> namespace boost { namespace process { namespace detail { namespace windows { template<typename CharType> struct cmd_setter_ : ::boost::process::detail::handler_base { typedef CharType value_type; typedef std::basic_string<value_type> string_type; cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {} cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {} template <class Executor> void on_setup(Executor& exec) { exec.cmd_line = _cmd_line.c_str(); } const string_type & str() const {return _cmd_line;} private: string_type _cmd_line; }; } } } } #endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */ detail/windows/job_workaround.hpp 0000644 00000022771 15125237362 0013255 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_JOB_WORKAROUND_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ #include <boost/winapi/config.hpp> #include <boost/winapi/basic_types.hpp> #include <boost/winapi/dll.hpp> #include <boost/winapi/overlapped.hpp> #if defined( BOOST_USE_WINDOWS_H ) #include <windows.h> #else extern "C" { BOOST_SYMBOL_IMPORT ::boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC CreateIoCompletionPort( ::boost::winapi::HANDLE_ FileHandle, ::boost::winapi::HANDLE_ ExistingCompletionPort, ::boost::winapi::ULONG_PTR_ CompletionKey, ::boost::winapi::DWORD_ NumberOfConcurrentThreads ); BOOST_SYMBOL_IMPORT ::boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC GetQueuedCompletionStatus( ::boost::winapi::HANDLE_ CompletionPort, ::boost::winapi::LPDWORD_ lpNumberOfBytes, ::boost::winapi::ULONG_PTR_ *lpCompletionKey, _OVERLAPPED **lpOverlapped, ::boost::winapi::DWORD_ dwMilliseconds ); } #endif namespace boost { namespace process { namespace detail { namespace windows { namespace workaround { extern "C" { struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ { ::boost::winapi::PVOID_ CompletionKey; ::boost::winapi::HANDLE_ CompletionPort; }; constexpr static int JOB_OBJECT_MSG_END_OF_JOB_TIME_ = 1; constexpr static int JOB_OBJECT_MSG_END_OF_PROCESS_TIME_ = 2; constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT_ = 3; constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_ = 4; constexpr static int JOB_OBJECT_MSG_NEW_PROCESS_ = 6; constexpr static int JOB_OBJECT_MSG_EXIT_PROCESS_ = 7; constexpr static int JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS_ = 8; constexpr static int JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT_ = 9; constexpr static int JOB_OBJECT_MSG_JOB_MEMORY_LIMIT_ = 10; constexpr static int JOB_OBJECT_MSG_NOTIFICATION_LIMIT_ = 11; constexpr static int JOB_OBJECT_MSG_JOB_CYCLE_TIME_LIMIT_ = 12; constexpr static int JOB_OBJECT_MSG_SILO_TERMINATED_ = 13; } BOOST_FORCEINLINE ::boost::winapi::BOOL_ get_queued_completion_status( ::boost::winapi::HANDLE_ CompletionPort, ::boost::winapi::LPDWORD_ lpNumberOfBytes, ::boost::winapi::ULONG_PTR_ *lpCompletionKey, ::boost::winapi::LPOVERLAPPED_ *lpOverlapped, ::boost::winapi::DWORD_ dwMilliseconds) { return ::GetQueuedCompletionStatus( CompletionPort, lpNumberOfBytes, lpCompletionKey, reinterpret_cast<::_OVERLAPPED**>(lpOverlapped), dwMilliseconds); } #if defined( BOOST_USE_WINDOWS_H ) constexpr auto static JobObjectExtendedLimitInformation_ = ::JobObjectExtendedLimitInformation; constexpr auto static JobObjectAssociateCompletionPortInformation_ = ::JobObjectAssociateCompletionPortInformation; constexpr auto static JobObjectBasicAccountingInformation_ = ::JobObjectBasicAccountingInformation; using JOBOBJECT_BASIC_LIMIT_INFORMATION_ = ::JOBOBJECT_BASIC_LIMIT_INFORMATION; using JOBOBJECTINFOCLASS_ = ::JOBOBJECTINFOCLASS; using IO_COUNTERS_ = ::IO_COUNTERS; using JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ = ::JOBOBJECT_EXTENDED_LIMIT_INFORMATION; using JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ = ::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION; inline ::boost::winapi::BOOL_ query_information_job_object( ::boost::winapi::HANDLE_ hJob, JOBOBJECTINFOCLASS_ JobObjectInfoClass, void * lpJobObjectInfo, ::boost::winapi::DWORD_ cbJobObjectInfoLength, ::boost::winapi::DWORD_ *lpReturnLength) { return ::QueryInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength); } inline ::boost::winapi::BOOL_ set_information_job_object( ::boost::winapi::HANDLE_ hJob, JOBOBJECTINFOCLASS_ JobObjectInfoClass, void * lpJobObjectInfo, ::boost::winapi::DWORD_ cbJobObjectInfoLength) { return ::SetInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength); } #else //this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi. extern "C" { typedef enum _JOBOBJECTINFOCLASS_ { JobObjectBasicAccountingInformation_ = 1, JobObjectBasicLimitInformation_, JobObjectBasicProcessIdList_, JobObjectBasicUIRestrictions_, JobObjectSecurityLimitInformation_, JobObjectEndOfJobTimeInformation_, JobObjectAssociateCompletionPortInformation_, JobObjectBasicAndIoAccountingInformation_, JobObjectExtendedLimitInformation_, JobObjectJobSetInformation_, JobObjectGroupInformation_, JobObjectNotificationLimitInformation_, JobObjectLimitViolationInformation_, JobObjectGroupInformationEx_, JobObjectCpuRateControlInformation_, JobObjectCompletionFilter_, JobObjectCompletionCounter_, JobObjectReserved1Information_ = 18, JobObjectReserved2Information_, JobObjectReserved3Information_, JobObjectReserved4Information_, JobObjectReserved5Information_, JobObjectReserved6Information_, JobObjectReserved7Information_, JobObjectReserved8Information_, MaxJobObjectInfoClass_ } JOBOBJECTINFOCLASS_; typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_ { ::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit; ::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit; ::boost::winapi::DWORD_ LimitFlags; ::boost::winapi::SIZE_T_ MinimumWorkingSetSize; ::boost::winapi::SIZE_T_ MaximumWorkingSetSize; ::boost::winapi::DWORD_ ActiveProcessLimit; ::boost::winapi::ULONG_PTR_ Affinity; ::boost::winapi::DWORD_ PriorityClass; ::boost::winapi::DWORD_ SchedulingClass; } JOBOBJECT_BASIC_LIMIT_INFORMATION_; typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ { ::boost::winapi::LARGE_INTEGER_ TotalUserTime; ::boost::winapi::LARGE_INTEGER_ TotalKernelTime; ::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalUserTime; ::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalKernelTime; ::boost::winapi::DWORD_ TotalPageFaultCount; ::boost::winapi::DWORD_ TotalProcesses; ::boost::winapi::DWORD_ ActiveProcesses; ::boost::winapi::DWORD_ TotalTerminatedProcesses; } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_; typedef struct _IO_COUNTERS_ { ::boost::winapi::ULONGLONG_ ReadOperationCount; ::boost::winapi::ULONGLONG_ WriteOperationCount; ::boost::winapi::ULONGLONG_ OtherOperationCount; ::boost::winapi::ULONGLONG_ ReadTransferCount; ::boost::winapi::ULONGLONG_ WriteTransferCount; ::boost::winapi::ULONGLONG_ OtherTransferCount; } IO_COUNTERS_; typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ { JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation; IO_COUNTERS_ IoInfo; ::boost::winapi::SIZE_T_ ProcessMemoryLimit; ::boost::winapi::SIZE_T_ JobMemoryLimit; ::boost::winapi::SIZE_T_ PeakProcessMemoryUsed; ::boost::winapi::SIZE_T_ PeakJobMemoryUsed; } JOBOBJECT_EXTENDED_LIMIT_INFORMATION_; /*BOOL WINAPI QueryInformationJobObject( _In_opt_ HANDLE hJob, _In_ JOBOBJECTINFOCLASS JobObjectInfoClass, _Out_ LPVOID lpJobObjectInfo, _In_ DWORD cbJobObjectInfoLength, _Out_opt_ LPDWORD lpReturnLength ); */ typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *query_information_job_object_p)( ::boost::winapi::HANDLE_, JOBOBJECTINFOCLASS_, void *, ::boost::winapi::DWORD_, ::boost::winapi::DWORD_ *); inline ::boost::winapi::BOOL_ query_information_job_object( ::boost::winapi::HANDLE_ hJob, JOBOBJECTINFOCLASS_ JobObjectInfoClass, void *lpJobObjectInfo, ::boost::winapi::DWORD_ cbJobObjectInfoLength, ::boost::winapi::DWORD_ *lpReturnLength) { static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle( L"Kernel32.dll"); static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address( h, "QueryInformationJobObject")); return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength); } /*BOOL WINAPI SetInformationJobObject( _In_ HANDLE hJob, _In_ JOBOBJECTINFOCLASS JobObjectInfoClass, _In_ LPVOID lpJobObjectInfo, _In_ DWORD cbJobObjectInfoLength );*/ typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *set_information_job_object_p)( ::boost::winapi::HANDLE_, JOBOBJECTINFOCLASS_, void *, ::boost::winapi::DWORD_); } inline ::boost::winapi::BOOL_ set_information_job_object( ::boost::winapi::HANDLE_ hJob, JOBOBJECTINFOCLASS_ JobObjectInfoClass, void *lpJobObjectInfo, ::boost::winapi::DWORD_ cbJobObjectInfoLength) { static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle( L"Kernel32.dll"); static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address( h, "SetInformationJobObject")); return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength); } #endif constexpr static ::boost::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800; }}}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */ detail/windows/wait_for_exit.hpp 0000644 00000007720 15125237362 0013070 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_WINDOWS_WAIT_FOR_EXIT_HPP #define BOOST_PROCESS_WINDOWS_WAIT_FOR_EXIT_HPP #include <boost/process/detail/config.hpp> #include <system_error> #include <boost/winapi/synchronization.hpp> #include <boost/winapi/process.hpp> #include <boost/process/detail/windows/child_handle.hpp> #include <chrono> namespace boost { namespace process { namespace detail { namespace windows { inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept { ::boost::winapi::DWORD_ _exit_code = 1; if (::boost::winapi::WaitForSingleObject(p.process_handle(), ::boost::winapi::infinite) == ::boost::winapi::wait_failed) ec = std::error_code( ::boost::winapi::GetLastError(), std::system_category()); else if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) ec = std::error_code( ::boost::winapi::GetLastError(), std::system_category()); else ec.clear(); ::boost::winapi::CloseHandle(p.proc_info.hProcess); p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_; exit_code = static_cast<int>(_exit_code); } inline void wait(child_handle &p, int & exit_code) { std::error_code ec; wait(p, exit_code, ec); boost::process::detail::throw_error(ec, "wait error"); } template< class Clock, class Duration > inline bool wait_until( child_handle &p, int & exit_code, const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code &ec) noexcept { std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>( timeout_time - Clock::now()); ::boost::winapi::DWORD_ wait_code; wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(), static_cast<::boost::winapi::DWORD_>(ms.count())); if (wait_code == ::boost::winapi::wait_failed) ec = std::error_code( ::boost::winapi::GetLastError(), std::system_category()); else if (wait_code == ::boost::winapi::wait_timeout) return false; ::boost::winapi::DWORD_ _exit_code; if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) ec = std::error_code( ::boost::winapi::GetLastError(), std::system_category()); else ec.clear(); exit_code = static_cast<int>(_exit_code); ::boost::winapi::CloseHandle(p.proc_info.hProcess); p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_; return true; } template< class Clock, class Duration > inline bool wait_until( child_handle &p, int & exit_code, const std::chrono::time_point<Clock, Duration>& timeout_time) { std::error_code ec; bool b = wait_until(p, exit_code, timeout_time, ec); boost::process::detail::throw_error(ec, "wait_until error"); return b; } template< class Rep, class Period > inline bool wait_for( child_handle &p, int & exit_code, const std::chrono::duration<Rep, Period>& rel_time, std::error_code &ec) noexcept { return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec); } template< class Rep, class Period > inline bool wait_for( child_handle &p, int & exit_code, const std::chrono::duration<Rep, Period>& rel_time) { std::error_code ec; bool b = wait_for(p, exit_code, rel_time, ec); boost::process::detail::throw_error(ec, "wait_for error"); return b; } }}}} #endif detail/windows/file_descriptor.hpp 0000644 00000007243 15125237362 0013402 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_FILE_DESCRIPTOR_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ #include <boost/winapi/basic_types.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/file_management.hpp> #include <string> #include <boost/filesystem/path.hpp> #include <boost/core/exchange.hpp> namespace boost { namespace process { namespace detail { namespace windows { struct file_descriptor { enum mode_t { read = 1, write = 2, read_write = 3 }; static ::boost::winapi::DWORD_ desired_access(mode_t mode) { switch(mode) { case read: return ::boost::winapi::GENERIC_READ_; case write: return ::boost::winapi::GENERIC_WRITE_; case read_write: return ::boost::winapi::GENERIC_READ_ | ::boost::winapi::GENERIC_WRITE_; default: return 0u; } } file_descriptor() = default; file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write) : file_descriptor(p.native(), mode) { } file_descriptor(const std::string & path , mode_t mode = read_write) #if defined(BOOST_NO_ANSI_APIS) : file_descriptor(::boost::process::detail::convert(path), mode) #else : file_descriptor(path.c_str(), mode) #endif {} file_descriptor(const std::wstring & path, mode_t mode = read_write) : file_descriptor(path.c_str(), mode) {} file_descriptor(const char* path, mode_t mode = read_write) #if defined(BOOST_NO_ANSI_APIS) : file_descriptor(std::string(path), mode) #else : _handle( ::boost::winapi::create_file( path, desired_access(mode), ::boost::winapi::FILE_SHARE_READ_ | ::boost::winapi::FILE_SHARE_WRITE_, nullptr, ::boost::winapi::OPEN_ALWAYS_, ::boost::winapi::FILE_ATTRIBUTE_NORMAL_, nullptr )) #endif { } file_descriptor(const wchar_t * path, mode_t mode = read_write) : _handle( ::boost::winapi::create_file( path, desired_access(mode), ::boost::winapi::FILE_SHARE_READ_ | ::boost::winapi::FILE_SHARE_WRITE_, nullptr, ::boost::winapi::OPEN_ALWAYS_, ::boost::winapi::FILE_ATTRIBUTE_NORMAL_, nullptr )) { } file_descriptor(const file_descriptor & ) = delete; file_descriptor(file_descriptor &&other) : _handle( boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_) ) { } file_descriptor& operator=(const file_descriptor & ) = delete; file_descriptor& operator=(file_descriptor &&other) { if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::winapi::CloseHandle(_handle); _handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_); } ~file_descriptor() { if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::winapi::CloseHandle(_handle); } ::boost::winapi::HANDLE_ handle() const { return _handle;} private: ::boost::winapi::HANDLE_ _handle = ::boost::winapi::INVALID_HANDLE_VALUE_; }; }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */ detail/windows/on_exit.hpp 0000644 00000002262 15125237362 0011666 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_ON_EXIT_HPP_ #define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/windows/async_handler.hpp> #include <system_error> #include <functional> namespace boost { namespace process { namespace detail { namespace windows { struct on_exit_ : boost::process::detail::windows::async_handler { std::function<void(int, const std::error_code&)> handler; on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler) { } template<typename Executor> std::function<void(int, const std::error_code&)> on_exit_handler(Executor&) { auto handler_ = this->handler; return [handler_](int exit_code, const std::error_code & ec) { handler_(static_cast<int>(exit_code), ec); }; } }; }}}} #endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */ detail/windows/child_handle.hpp 0000644 00000006161 15125237362 0012621 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_CHILD_HPP #define BOOST_PROCESS_WINDOWS_CHILD_HPP #include <boost/move/move.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/process.hpp> #include <boost/winapi/jobs.hpp> namespace boost { namespace process { namespace detail { namespace windows { typedef ::boost::winapi::DWORD_ pid_t; struct child_handle { ::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0}; explicit child_handle(const ::boost::winapi::PROCESS_INFORMATION_ &pi) : proc_info(pi) {} explicit child_handle(pid_t pid) : proc_info{nullptr, nullptr, 0,0} { auto h = ::boost::winapi::OpenProcess( ::boost::winapi::PROCESS_ALL_ACCESS_, static_cast<::boost::winapi::BOOL_>(0), pid); if (h == nullptr) throw_last_error("OpenProcess() failed"); proc_info.hProcess = h; proc_info.dwProcessId = pid; } child_handle() = default; ~child_handle() { ::boost::winapi::CloseHandle(proc_info.hProcess); ::boost::winapi::CloseHandle(proc_info.hThread); } child_handle(const child_handle & c) = delete; child_handle(child_handle && c) : proc_info(c.proc_info) { c.proc_info.hProcess = ::boost::winapi::invalid_handle_value; c.proc_info.hThread = ::boost::winapi::invalid_handle_value; } child_handle &operator=(const child_handle & c) = delete; child_handle &operator=(child_handle && c) { ::boost::winapi::CloseHandle(proc_info.hProcess); ::boost::winapi::CloseHandle(proc_info.hThread); proc_info = c.proc_info; c.proc_info.hProcess = ::boost::winapi::invalid_handle_value; c.proc_info.hThread = ::boost::winapi::invalid_handle_value; return *this; } pid_t id() const { return static_cast<pid_t>(proc_info.dwProcessId); } typedef ::boost::winapi::HANDLE_ process_handle_t; process_handle_t process_handle() const { return proc_info.hProcess; } bool valid() const { return (proc_info.hProcess != nullptr) && (proc_info.hProcess != ::boost::winapi::INVALID_HANDLE_VALUE_); } bool in_group() const { ::boost::winapi::BOOL_ value; if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value)) throw_last_error("IsProcessinJob Failed"); return value!=0; } bool in_group(std::error_code &ec) const noexcept { ::boost::winapi::BOOL_ value; if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value)) ec = get_last_error(); return value!=0; } }; }}}} #endif detail/windows/executor.hpp 0000644 00000017555 15125237362 0012072 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_WINDOWS_EXECUTOR_HPP #define BOOST_PROCESS_WINDOWS_EXECUTOR_HPP #include <boost/process/detail/child_decl.hpp> #include <boost/process/detail/windows/is_running.hpp> #include <boost/process/detail/traits.hpp> #include <boost/process/error.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/process.hpp> #include <boost/none.hpp> #include <system_error> #include <memory> #include <atomic> #include <cstring> namespace boost { namespace process { namespace detail { namespace windows { template<typename CharType> struct startup_info; #if !defined( BOOST_NO_ANSI_APIS ) template<> struct startup_info<char> { typedef ::boost::winapi::STARTUPINFOA_ type; }; #endif template<> struct startup_info<wchar_t> { typedef ::boost::winapi::STARTUPINFOW_ type; }; #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 template<typename CharType> struct startup_info_ex; #if !defined( BOOST_NO_ANSI_APIS ) template<> struct startup_info_ex<char> { typedef ::boost::winapi::STARTUPINFOEXA_ type; }; #endif template<> struct startup_info_ex<wchar_t> { typedef ::boost::winapi::STARTUPINFOEXW_ type; }; #endif #if ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 ) template<typename CharT> struct startup_info_impl { ::boost::winapi::DWORD_ creation_flags = 0; typedef typename startup_info_ex<CharT>::type startup_info_ex_t; typedef typename startup_info<CharT>::type startup_info_t; startup_info_ex_t startup_info_ex {startup_info_t {sizeof(startup_info_t), nullptr, nullptr, nullptr, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr, ::boost::winapi::invalid_handle_value, ::boost::winapi::invalid_handle_value, ::boost::winapi::invalid_handle_value}, nullptr }; startup_info_t & startup_info = startup_info_ex.StartupInfo; void set_startup_info_ex() { startup_info.cb = sizeof(startup_info_ex_t); creation_flags |= ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_; } }; #else template<typename CharT> struct startup_info_impl { typedef typename startup_info<CharT>::type startup_info_t; ::boost::winapi::DWORD_ creation_flags = 0; startup_info_t startup_info {sizeof(startup_info_t), nullptr, nullptr, nullptr, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr, ::boost::winapi::invalid_handle_value, ::boost::winapi::invalid_handle_value, ::boost::winapi::invalid_handle_value}; }; #endif template<typename Char, typename Sequence> class executor : public startup_info_impl<Char> { void internal_error_handle(const std::error_code &, const char*, boost::mpl::false_, boost::mpl::true_) {} void internal_error_handle(const std::error_code &, const char*, boost::mpl::true_, boost::mpl::true_) {} void internal_error_handle(const std::error_code &ec, const char*, boost::mpl::true_, boost::mpl::false_ ) { this->_ec = ec; } void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_ ) { throw process_error(ec, msg); } struct on_setup_t { executor & exec; on_setup_t(executor & exec) : exec(exec) {}; template<typename T> void operator()(T & t) const { if (!exec.error()) t.on_setup(exec); } }; struct on_error_t { executor & exec; const std::error_code & error; on_error_t(executor & exec, const std::error_code & error) : exec(exec), error(error) {}; template<typename T> void operator()(T & t) const { t.on_error(exec, error); } }; struct on_success_t { executor & exec; on_success_t(executor & exec) : exec(exec) {}; template<typename T> void operator()(T & t) const { if (!exec.error()) t.on_success(exec); } }; typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler; typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error; std::error_code _ec{0, std::system_category()}; public: std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); executor(Sequence & seq) : seq(seq) { } child operator()() { on_setup_t on_setup_fn(*this); boost::fusion::for_each(seq, on_setup_fn); if (_ec) { on_error_t on_error_fn(*this, _ec); boost::fusion::for_each(seq, on_error_fn); return child(); } //NOTE: The non-cast cmd-line string can only be modified by the wchar_t variant which is currently disabled. int err_code = ::boost::winapi::create_process( exe, // LPCSTR_ lpApplicationName, const_cast<Char*>(cmd_line), // LPSTR_ lpCommandLine, proc_attrs, // LPSECURITY_ATTRIBUTES_ lpProcessAttributes, thread_attrs, // LPSECURITY_ATTRIBUTES_ lpThreadAttributes, inherit_handles, // INT_ bInheritHandles, this->creation_flags, // DWORD_ dwCreationFlags, reinterpret_cast<void*>(const_cast<Char*>(env)), // LPVOID_ lpEnvironment, work_dir, // LPCSTR_ lpCurrentDirectory, &this->startup_info, // LPSTARTUPINFOA_ lpStartupInfo, &proc_info); // LPPROCESS_INFORMATION_ lpProcessInformation) child c{child_handle(proc_info), exit_status}; if (err_code != 0) { _ec.clear(); on_success_t on_success_fn(*this); boost::fusion::for_each(seq, on_success_fn); } else set_error(::boost::process::detail::get_last_error(), " CreateProcess failed"); if ( _ec) { on_error_t on_err(*this, _ec); boost::fusion::for_each(seq, on_err); return child(); } else return c; } void set_error(const std::error_code & ec, const char* msg = "Unknown Error.") { internal_error_handle(ec, msg, has_error_handler(), has_ignore_error()); } void set_error(const std::error_code & ec, const std::string msg = "Unknown Error.") { internal_error_handle(ec, msg.c_str(), has_error_handler(), has_ignore_error()); } const std::error_code& error() const {return _ec;} ::boost::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr; ::boost::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr; ::boost::winapi::BOOL_ inherit_handles = false; const Char * work_dir = nullptr; const Char * cmd_line = nullptr; const Char * exe = nullptr; const Char * env = nullptr; Sequence & seq; ::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0}; }; template<typename Char, typename Tup> executor<Char, Tup> make_executor(Tup & tup) { return executor<Char, Tup>(tup); } }}}} #endif detail/windows/handles.hpp 0000644 00000013162 15125237362 0011640 0 ustar 00 // 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_WINDOWS_HANDLES_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_ #include <vector> #include <system_error> #include <boost/process/detail/windows/handle_workaround.hpp> #include <boost/process/detail/windows/handler.hpp> #include <boost/winapi/get_current_process_id.hpp> namespace boost { namespace process { namespace detail { template<typename Executor, typename Function> void foreach_used_handle(Executor &exec, Function &&func); namespace windows { using native_handle_type = ::boost::winapi::HANDLE_ ; inline std::vector<native_handle_type> get_handles(std::error_code & ec) { auto pid = ::boost::winapi::GetCurrentProcessId(); std::vector<char> buffer(2048); constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l); auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data()); ::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_; for (; nt_status == STATUS_INFO_LENGTH_MISMATCH_; nt_status = workaround::nt_system_query_information( workaround::SystemHandleInformation_, info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()), nullptr)) { buffer.resize(buffer.size() * 2); info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data()); } if (nt_status < 0 || nt_status > 0x7FFFFFFF) { ec = ::boost::process::detail::get_last_error(); return {}; } else ec.clear(); std::vector<native_handle_type> res; for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++) { if (itr->OwnerPid == pid) res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue))); } 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, "NtQuerySystemInformation failed"); return res; } inline bool is_stream_handle(native_handle_type handle, std::error_code & ec) { ::boost::winapi::ULONG_ actual_size; auto nt_status = workaround::nt_query_object( handle, workaround::ObjectTypeInformation, NULL, 0, &actual_size); std::vector<char> vec; vec.resize(actual_size); workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data()); nt_status = workaround::nt_query_object( handle, workaround::ObjectTypeInformation, type_info_p, actual_size, &actual_size); if (nt_status < 0 || nt_status > 0x7FFFFFFF) { ec = ::boost::process::detail::get_last_error(); return false; } else ec.clear(); auto &nm = type_info_p->TypeName.Buffer; return type_info_p->TypeName.Length >= 5 && nm[0] == L'F' && nm[1] == L'i' && nm[2] == L'l' && nm[3] == L'e' && nm[4] == L'\0'; } 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, "NtQueryObject failed"); return res; } struct limit_handles_ : handler_base_ext { mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag; template<typename Executor> void on_setup(Executor & exec) const { auto all_handles = get_handles(); foreach_used_handle(exec, [&](::boost::winapi::HANDLE_ handle) { auto itr = std::find(all_handles.begin(), all_handles .end(), handle); DWORD flags = 0u; if (itr != all_handles.end()) *itr = ::boost::winapi::INVALID_HANDLE_VALUE_; else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0) &&((flags & ::boost::winapi::HANDLE_FLAG_INHERIT_) == 0)) //it is NOT inherited anyhow, so ignore too *itr = ::boost::winapi::INVALID_HANDLE_VALUE_; }); auto part_itr = std::partition(all_handles.begin(), all_handles.end(), [](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;}); all_handles.erase(part_itr, all_handles.end()); //remove invalid handles handles_with_inherit_flag = std::move(all_handles); for (auto handle : handles_with_inherit_flag) ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0); } template<typename Executor> void on_error(Executor & exec, const std::error_code & ec) const { for (auto handle : handles_with_inherit_flag) ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_); } template<typename Executor> void on_sucess(Executor & exec) const { for (auto handle : handles_with_inherit_flag) ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_); } }; }}}} #endif //PROCESS_HANDLES_HPP detail/windows/show_window.hpp 0000644 00000002434 15125237362 0012571 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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_WINDOWS_SHOW_WINDOW_HPP #define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/show_window.hpp> #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<::boost::winapi::WORD_ Flags> struct show_window : ::boost::process::detail::handler_base { template <class WindowsExecutor> void on_setup(WindowsExecutor &e) const { e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESHOWWINDOW_; e.startup_info.wShowWindow |= Flags; } }; struct create_no_window_ : public ::boost::process::detail::handler_base { template <class Executor> void on_setup(Executor &exec) const { exec.creation_flags |= ::boost::winapi::CREATE_NO_WINDOW_; } }; }}}} #endif detail/windows/locale.hpp 0000644 00000006122 15125237362 0011457 0 ustar 00 // Copyright (c) 2016 Klemens D. Morgenstern // Copyright (c) 2008 Beman Dawes // // 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_WINDOWS_LOCALE_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_ #include <locale> #include <boost/core/ignore_unused.hpp> #include <boost/winapi/file_management.hpp> #include <boost/winapi/character_code_conversion.hpp> namespace boost { namespace process { namespace detail { namespace windows { //copied from boost.filesystem class windows_file_codecvt : public std::codecvt< wchar_t, char, std::mbstate_t > { public: explicit windows_file_codecvt(std::size_t refs = 0) : std::codecvt<wchar_t, char, std::mbstate_t>(refs) {} protected: bool do_always_noconv() const noexcept override { return false; } // seems safest to assume variable number of characters since we don't // actually know what codepage is active int do_encoding() const noexcept override { return 0; } std::codecvt_base::result do_in(std::mbstate_t& state, const char* from, const char* from_end, const char*& from_next, wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override { boost::ignore_unused(state); auto codepage = #if !defined(BOOST_NO_ANSI_APIS) ::boost::winapi::AreFileApisANSI() ? ::boost::winapi::CP_ACP_ : #endif ::boost::winapi::CP_OEMCP_; int count = 0; if ((count = ::boost::winapi::MultiByteToWideChar(codepage, ::boost::winapi::MB_PRECOMPOSED_, from, static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0) { return error; // conversion failed } from_next = from_end; to_next = to + count; *to_next = L'\0'; return ok; } std::codecvt_base::result do_out(std::mbstate_t & state, const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, char* to, char* to_end, char*& to_next) const override { boost::ignore_unused(state); auto codepage = #if !defined(BOOST_NO_ANSI_APIS) ::boost::winapi::AreFileApisANSI() ? ::boost::winapi::CP_ACP_ : #endif ::boost::winapi::CP_OEMCP_; int count = 0; if ((count = ::boost::winapi::WideCharToMultiByte(codepage, ::boost::winapi::WC_NO_BEST_FIT_CHARS_, from, static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0) { return error; // conversion failed } from_next = from_end; to_next = to + count; *to_next = '\0'; return ok; } std::codecvt_base::result do_unshift(std::mbstate_t&, char* /*from*/, char* /*to*/, char* & /*next*/) const override { return ok; } int do_length(std::mbstate_t&, const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const override { return 0; } int do_max_length() const noexcept override { return 0; } }; } } } } #endif /* BOOST_PROCESS_LOCALE_HPP_ */ detail/windows/group_ref.hpp 0000644 00000003044 15125237362 0012210 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_GROUP_REF_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_ #include <boost/winapi/process.hpp> #include <boost/process/detail/config.hpp> #include <boost/process/detail/windows/group_handle.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/handler.hpp> namespace boost { namespace process { namespace detail { namespace windows { struct group_ref : handler_base_ext, ::boost::process::detail::uses_handles { ::boost::winapi::HANDLE_ handle; ::boost::winapi::HANDLE_ get_used_handles() const { return handle; } explicit group_ref(group_handle &g) : handle(g.handle()) {} template <class Executor> void on_setup(Executor& exec) const { //I can only enable this if the current process supports breakaways. if (in_group() && break_away_enabled(nullptr)) exec.creation_flags |= boost::winapi::CREATE_BREAKAWAY_FROM_JOB_; } template <class Executor> void on_success(Executor& exec) const { if (!::boost::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess)) exec.set_error(::boost::process::detail::get_last_error(), "AssignProcessToJobObject() failed."); } }; }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ detail/windows/group_handle.hpp 0000644 00000014577 15125237362 0012704 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_GROUP_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ #include <boost/process/detail/windows/handler.hpp> #include <boost/winapi/jobs.hpp> #include <boost/process/detail/windows/child_handle.hpp> #include <boost/process/detail/windows/job_workaround.hpp> #include <system_error> namespace boost { namespace process { namespace detail { namespace windows { inline bool break_away_enabled(::boost::winapi::HANDLE_ h) { workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; if (!workaround::query_information_job_object( h, workaround::JobObjectExtendedLimitInformation_, static_cast<void*>(&info), sizeof(info), nullptr)) throw_last_error("QueryInformationJobObject() failed"); return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0; } inline void enable_break_away(::boost::winapi::HANDLE_ h) { workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; if (!workaround::query_information_job_object( h, workaround::JobObjectExtendedLimitInformation_, static_cast<void*>(&info), sizeof(info), nullptr)) throw_last_error("QueryInformationJobObject() failed"); if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0) return; info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_; if (!workaround::set_information_job_object( h, workaround::JobObjectExtendedLimitInformation_, static_cast<void*>(&info), sizeof(info))) throw_last_error("SetInformationJobObject() failed"); } inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec) { workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; if (!workaround::query_information_job_object( h, workaround::JobObjectExtendedLimitInformation_, static_cast<void*>(&info), sizeof(info), nullptr)) { ec = get_last_error(); return; } if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0) return; info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_; if (!workaround::set_information_job_object( h, workaround::JobObjectExtendedLimitInformation_, static_cast<void*>(&info), sizeof(info))) { ec = get_last_error(); return; } } inline void associate_completion_port(::boost::winapi::HANDLE_ job, ::boost::winapi::HANDLE_ io_port) { workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port; port.CompletionKey = job; port.CompletionPort = io_port; if (!workaround::set_information_job_object( job, workaround::JobObjectAssociateCompletionPortInformation_, static_cast<void*>(&port), sizeof(port))) throw_last_error("SetInformationJobObject() failed"); } struct group_handle { ::boost::winapi::HANDLE_ _job_object; ::boost::winapi::HANDLE_ _io_port; typedef ::boost::winapi::HANDLE_ handle_t; handle_t handle() const { return _job_object; } explicit group_handle(handle_t h) : _job_object(h), _io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1)) { enable_break_away(_job_object); associate_completion_port(_job_object, _io_port); } group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr)) { } ~group_handle() { ::boost::winapi::CloseHandle(_job_object); ::boost::winapi::CloseHandle(_io_port); } group_handle(const group_handle & c) = delete; group_handle(group_handle && c) : _job_object(c._job_object), _io_port(c._io_port) { c._job_object = ::boost::winapi::invalid_handle_value; c._io_port = ::boost::winapi::invalid_handle_value; } group_handle &operator=(const group_handle & c) = delete; group_handle &operator=(group_handle && c) { ::boost::winapi::CloseHandle(_io_port); _io_port = c._io_port; c._io_port = ::boost::winapi::invalid_handle_value; ::boost::winapi::CloseHandle(_job_object); _job_object = c._job_object; c._job_object = ::boost::winapi::invalid_handle_value; return *this; } void add(handle_t proc) { if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc)) throw_last_error(); } void add(handle_t proc, std::error_code & ec) noexcept { if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc)) ec = get_last_error(); } bool has(handle_t proc) { ::boost::winapi::BOOL_ is; if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is)) throw_last_error(); return is!=0; } bool has(handle_t proc, std::error_code & ec) noexcept { ::boost::winapi::BOOL_ is; if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is)) ec = get_last_error(); return is!=0; } bool valid() const { return _job_object != nullptr; } }; inline void terminate(const group_handle &p) { if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE)) boost::process::detail::throw_last_error("TerminateJobObject() failed"); } inline void terminate(const group_handle &p, std::error_code &ec) noexcept { if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE)) ec = boost::process::detail::get_last_error(); else ec.clear(); } inline bool in_group() { ::boost::winapi::BOOL_ res; if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res)) throw_last_error("IsProcessInJob failed"); return res!=0; } }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ detail/windows/async_in.hpp 0000644 00000006745 15125237362 0012036 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_ASYNC_IN_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/handle_info.hpp> #include <boost/winapi/error_codes.hpp> #include <boost/asio/write.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/used_handles.hpp> #include <boost/process/detail/windows/async_handler.hpp> #include <boost/process/detail/windows/asio_fwd.hpp> #include <boost/process/async_pipe.hpp> #include <memory> #include <future> namespace boost { namespace process { namespace detail { namespace windows { template<typename Buffer> struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext, ::boost::process::detail::windows::require_io_context, ::boost::process::detail::uses_handles { Buffer & buf; std::shared_ptr<std::promise<void>> promise; async_in_buffer operator>(std::future<void> & fut) { promise = std::make_shared<std::promise<void>>(); fut = promise->get_future(); return std::move(*this); } std::shared_ptr<boost::process::async_pipe> pipe; ::boost::winapi::HANDLE_ get_used_handles() const { return std::move(*pipe).source().native_handle(); } async_in_buffer(Buffer & buf) : buf(buf) { } template <typename Executor> inline void on_success(Executor&) { auto pipe_ = this->pipe; if (this->promise) { auto promise_ = this->promise; boost::asio::async_write(*pipe_, buf, [promise_](const boost::system::error_code & ec, std::size_t) { if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_)) { std::error_code e(ec.value(), std::system_category()); promise_->set_exception(std::make_exception_ptr(process_error(e))); } promise_->set_value(); }); } else boost::asio::async_write(*pipe_, buf, [pipe_](const boost::system::error_code&, std::size_t){}); std::move(*pipe_).source().close(); this->pipe = nullptr; } template<typename Executor> void on_error(Executor &, const std::error_code &) const { ::boost::winapi::CloseHandle(pipe->native_source()); } template <typename WindowsExecutor> void on_setup(WindowsExecutor &exec) { if (!pipe) pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq)); ::boost::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle(); boost::winapi::SetHandleInformation(source_handle, boost::winapi::HANDLE_FLAG_INHERIT_, boost::winapi::HANDLE_FLAG_INHERIT_); exec.startup_info.hStdInput = source_handle; exec.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_; exec.inherit_handles = true; } }; }}}} #endif detail/windows/env_init.hpp 0000644 00000003117 15125237362 0012034 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_ENV_INIT_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ #include <boost/winapi/error_codes.hpp> #include <boost/winapi/process.hpp> #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/environment.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<typename Char> struct env_init : public ::boost::process::detail::handler_base { boost::process::basic_environment<Char> env; env_init(boost::process::basic_environment<Char> && env) : env(std::move(env)) {}; env_init(const boost::process::basic_environment<Char> & env) : env(env) {}; constexpr static ::boost::winapi::DWORD_ creation_flag(char) {return 0u;} constexpr static ::boost::winapi::DWORD_ creation_flag(wchar_t) { return ::boost::winapi::CREATE_UNICODE_ENVIRONMENT_; } template <class WindowsExecutor> void on_setup(WindowsExecutor &exec) const { auto e = env.native_handle(); if (*e == null_char<char>()) { exec.set_error(std::error_code(::boost::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()), "Empty Environment"); } exec.env = e; exec.creation_flags |= creation_flag(Char()); } }; }}}} #endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_ */ detail/windows/close_out.hpp 0000644 00000003317 15125237362 0012217 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP #define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP #include <boost/winapi/process.hpp> #include <boost/winapi/handles.hpp> #include <boost/process/detail/handler_base.hpp> namespace boost { namespace process { namespace detail { namespace windows { template<int p1, int p2> struct close_out : public ::boost::process::detail::handler_base { template <class WindowsExecutor> inline void on_setup(WindowsExecutor &e) const; }; template<> template<typename WindowsExecutor> void close_out<1,-1>::on_setup(WindowsExecutor &e) const { e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; } template<> template<typename WindowsExecutor> void close_out<2,-1>::on_setup(WindowsExecutor &e) const { e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; } template<> template<typename WindowsExecutor> void close_out<1,2>::on_setup(WindowsExecutor &e) const { e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_; e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_; e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_; } }}}} #endif detail/windows/basic_cmd.hpp 0000644 00000011720 15125237362 0012124 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_BASIC_CMD_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_ #include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/process/shell.hpp> #include <boost/process/detail/windows/handler.hpp> #include <vector> #include <string> #include <iterator> namespace boost { namespace process { namespace detail { namespace windows { inline std::string build_args(const std::string & exe, std::vector<std::string> && data) { std::string st = exe; //put in quotes if it has spaces or double quotes if(!exe.empty()) { auto it = st.find_first_of(" \""); if(it != st.npos)//contains spaces. { // double existing quotes boost::replace_all(st, "\"", "\"\""); // surround with quotes st.insert(st.begin(), '"'); st += '"'; } } for (auto & arg : data) { if(!arg.empty()) { auto it = arg.find_first_of(" \"");//contains space or double quotes? if(it != arg.npos)//yes { // double existing quotes boost::replace_all(arg, "\"", "\"\""); // surround with quotes arg.insert(arg.begin(), '"'); arg += '"'; } } if (!st.empty())//first one does not need a preceeding space st += ' '; st += arg; } return st; } inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data) { std::wstring st = exe; //put in quotes if it has spaces or double quotes if(!exe.empty()) { auto it = st.find_first_of(L" \""); if(it != st.npos)//contains spaces or double quotes. { // double existing quotes boost::replace_all(st, L"\"", L"\"\""); // surround with quotes st.insert(st.begin(), L'"'); st += L'"'; } } for(auto & arg : data) { if(!arg.empty()) { auto it = arg.find_first_of(L" \"");//contains space or double quotes? if(it != arg.npos)//yes { // double existing quotes boost::replace_all(arg, L"\"", L"\"\""); // surround with quotes arg.insert(arg.begin(), L'"'); arg += '"'; } } if (!st.empty())//first one does not need a preceeding space st += L' '; st += arg; } return st; } template<typename Char> struct exe_cmd_init : handler_base_ext { using value_type = Char; using string_type = std::basic_string<value_type>; static const char* c_arg(char) { return "/c";} static const wchar_t* c_arg(wchar_t) { return L"/c";} exe_cmd_init(const string_type & exe, bool cmd_only = false) : exe(exe), args({}), cmd_only(cmd_only) {}; exe_cmd_init(string_type && exe, bool cmd_only = false) : exe(std::move(exe)), args({}), cmd_only(cmd_only) {}; exe_cmd_init(string_type && exe, std::vector<string_type> && args) : exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {}; template <class Executor> void on_setup(Executor& exec) const { if (cmd_only && args.empty()) exec.cmd_line = exe.c_str(); else { exec.exe = exe.c_str(); exec.cmd_line = args.c_str(); } } static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args) { return exe_cmd_init<Char>(std::move(exe), std::move(args)); } static exe_cmd_init<Char> cmd(string_type&& cmd) { return exe_cmd_init<Char>(std::move(cmd), true); } static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args) { std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)}; args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end())); string_type sh = get_shell(Char()); return exe_cmd_init<Char>(std::move(sh), std::move(args_)); } static std:: string get_shell(char) {return shell(). string(codecvt()); } static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());} static exe_cmd_init<Char> cmd_shell(string_type&& cmd) { std::vector<string_type> args = {c_arg(Char()), std::move(cmd)}; string_type sh = get_shell(Char()); return exe_cmd_init<Char>( std::move(sh), std::move(args)); } private: string_type exe; string_type args; bool cmd_only; }; } } } } #endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */ detail/windows/async_handler.hpp 0000644 00000002253 15125237362 0013033 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_ASYNC_HANDLER_HPP_ #define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ #include <boost/process/detail/windows/handler.hpp> #include <type_traits> namespace boost { namespace process { namespace detail { namespace windows { struct require_io_context {}; struct async_handler : handler_base_ext, require_io_context { }; template<typename T> struct is_async_handler : std::is_base_of<async_handler, T> {}; template<typename T> struct is_async_handler<T&> : std::is_base_of<async_handler, T> {}; template<typename T> struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {}; template<typename T> struct does_require_io_context : std::is_base_of<require_io_context, T> {}; template<typename T> struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {}; template<typename T> struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {}; }}}} #endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */ detail/windows/terminate.hpp 0000644 00000002461 15125237362 0012212 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_TERMINATE_HPP #define BOOST_PROCESS_WINDOWS_TERMINATE_HPP #include <boost/process/detail/config.hpp> #include <system_error> #include <cstdlib> #include <boost/winapi/process.hpp> #include <boost/winapi/get_last_error.hpp> namespace boost { namespace process { namespace detail { namespace windows { struct child_handle; inline void terminate(child_handle &p, std::error_code &ec) noexcept { if (!::boost::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE)) ec = boost::process::detail::get_last_error(); else { ec.clear(); ::boost::winapi::CloseHandle(p.proc_info.hProcess); p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_; } } inline void terminate(child_handle &p) { std::error_code ec; terminate(p, ec); boost::process::detail::throw_error(ec, "TerminateProcess() failed in terminate"); } }}}} #endif detail/windows/async_pipe.hpp 0000644 00000042313 15125237362 0012354 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_ASYNC_PIPE_HPP_ #define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ #include <boost/winapi/basic_types.hpp> #include <boost/winapi/pipes.hpp> #include <boost/winapi/handles.hpp> #include <boost/winapi/file_management.hpp> #include <boost/winapi/get_last_error.hpp> #include <boost/winapi/access_rights.hpp> #include <boost/winapi/process.hpp> #include <boost/process/detail/windows/basic_pipe.hpp> #include <boost/asio/post.hpp> #include <boost/asio/windows/stream_handle.hpp> #include <atomic> #include <system_error> #include <string> namespace boost { namespace process { namespace detail { namespace windows { inline std::string make_pipe_name() { std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_"; auto pid = ::boost::winapi::GetCurrentProcessId(); static std::atomic_size_t cnt{0}; name += std::to_string(pid); name += "_"; name += std::to_string(cnt++); return name; } class async_pipe { ::boost::asio::windows::stream_handle _source; ::boost::asio::windows::stream_handle _sink ; inline async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name, bool private_); public: typedef ::boost::winapi::HANDLE_ native_handle_type; typedef ::boost::asio::windows::stream_handle handle_type; typedef typename handle_type::executor_type executor_type; async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {} async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink) : async_pipe(ios_source, ios_sink, make_pipe_name(), true) {} async_pipe(boost::asio::io_context & ios, const std::string & name) : async_pipe(ios, ios, name, false) {} async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name) : async_pipe(ios_source, ios_sink, name, false) {} inline async_pipe(const async_pipe& rhs); async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink)) { } template<class CharT, class Traits = std::char_traits<CharT>> explicit async_pipe(::boost::asio::io_context & ios_source, ::boost::asio::io_context & ios_sink, const basic_pipe<CharT, Traits> & p) : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink()) { } template<class CharT, class Traits = std::char_traits<CharT>> explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p) : async_pipe(ios, ios, p) { } template<class CharT, class Traits = std::char_traits<CharT>> inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p); inline async_pipe& operator=(const async_pipe& rhs); inline async_pipe& operator=(async_pipe&& rhs); ~async_pipe() { boost::system::error_code ec; close(ec); } template<class CharT, class Traits = std::char_traits<CharT>> inline explicit operator basic_pipe<CharT, Traits>() const; void cancel() { if (_sink.is_open()) _sink.cancel(); if (_source.is_open()) _source.cancel(); } void close() { if (_sink.is_open()) { _sink.close(); _sink = handle_type(_sink.get_executor()); } if (_source.is_open()) { _source.close(); _source = handle_type(_source.get_executor()); } } void close(boost::system::error_code & ec) { if (_sink.is_open()) { _sink.close(ec); _sink = handle_type(_sink.get_executor()); } if (_source.is_open()) { _source.close(ec); _source = handle_type(_source.get_executor()); } } bool is_open() const { return _sink.is_open() || _source.is_open(); } void async_close() { if (_sink.is_open()) boost::asio::post(_sink.get_executor(), [this]{_sink.close();}); if (_source.is_open()) boost::asio::post(_source.get_executor(), [this]{_source.close();}); } template<typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence & buffers) { return _source.read_some(buffers); } template<typename MutableBufferSequence> std::size_t write_some(const MutableBufferSequence & buffers) { return _sink.write_some(buffers); } template<typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept { return _source.read_some(buffers, ec); } template<typename MutableBufferSequence> std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept { return _sink.write_some(buffers, ec); } native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native_handle();} native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native_handle();} template<typename MutableBufferSequence, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE( ReadHandler, void(boost::system::error_code, std::size_t)) async_read_some( const MutableBufferSequence & buffers, ReadHandler &&handler) { return _source.async_read_some(buffers, std::forward<ReadHandler>(handler)); } template<typename ConstBufferSequence, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE( WriteHandler, void(boost::system::error_code, std::size_t)) async_write_some( const ConstBufferSequence & buffers, WriteHandler && handler) { return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler)); } const handle_type & sink () const & {return _sink;} const handle_type & source() const & {return _source;} handle_type && source() && { return std::move(_source); } handle_type && sink() && { return std::move(_sink); } handle_type source(::boost::asio::io_context& ios) && { ::boost::asio::windows::stream_handle stolen(ios.get_executor(), _source.native_handle()); boost::system::error_code ec; _source.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec); return stolen; } handle_type sink (::boost::asio::io_context& ios) && { ::boost::asio::windows::stream_handle stolen(ios.get_executor(), _sink.native_handle()); boost::system::error_code ec; _sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec); return stolen; } handle_type source(::boost::asio::io_context& ios) const & { auto proc = ::boost::winapi::GetCurrentProcess(); ::boost::winapi::HANDLE_ source; auto source_in = const_cast<handle_type&>(_source).native_handle(); if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_) source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, source_in, proc, &source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); return ::boost::asio::windows::stream_handle(ios.get_executor(), source); } handle_type sink (::boost::asio::io_context& ios) const & { auto proc = ::boost::winapi::GetCurrentProcess(); ::boost::winapi::HANDLE_ sink; auto sink_in = const_cast<handle_type&>(_sink).native_handle(); if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_) sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, sink_in, proc, &sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); return ::boost::asio::windows::stream_handle(ios.get_executor(), sink); } }; async_pipe::async_pipe(const async_pipe& p) : _source(const_cast<handle_type&>(p._source).get_executor()), _sink (const_cast<handle_type&>(p._sink).get_executor()) { auto proc = ::boost::winapi::GetCurrentProcess(); ::boost::winapi::HANDLE_ source; ::boost::winapi::HANDLE_ sink; //cannot get the handle from a const object. auto source_in = const_cast<handle_type&>(p._source).native_handle(); auto sink_in = const_cast<handle_type&>(p._sink).native_handle(); if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_) source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, source_in, proc, &source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_) sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, sink_in, proc, &sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (source != ::boost::winapi::INVALID_HANDLE_VALUE_) _source.assign(source); if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_) _sink. assign(sink); } async_pipe::async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink) { static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary ::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe( #if defined(BOOST_NO_ANSI_APIS) ::boost::process::detail::convert(name).c_str(), #else name.c_str(), #endif ::boost::winapi::PIPE_ACCESS_INBOUND_ | FILE_FLAG_OVERLAPPED_, //write flag 0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr); if (source == boost::winapi::INVALID_HANDLE_VALUE_) ::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed"); _source.assign(source); ::boost::winapi::HANDLE_ sink = boost::winapi::create_file( #if defined(BOOST_NO_ANSI_APIS) ::boost::process::detail::convert(name).c_str(), #else name.c_str(), #endif ::boost::winapi::GENERIC_WRITE_, 0, nullptr, ::boost::winapi::OPEN_EXISTING_, FILE_FLAG_OVERLAPPED_, //to allow read nullptr); if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_) ::boost::process::detail::throw_last_error("create_file() failed"); _sink.assign(sink); } template<class CharT, class Traits> async_pipe& async_pipe::operator=(const basic_pipe<CharT, Traits> & p) { auto proc = ::boost::winapi::GetCurrentProcess(); ::boost::winapi::HANDLE_ source; ::boost::winapi::HANDLE_ sink; //cannot get the handle from a const object. auto source_in = p.native_source(); auto sink_in = p.native_sink(); if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_) source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, source_in.native_handle(), proc, &source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_) sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, sink_in.native_handle(), proc, &sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); //so we also assign the io_context if (source != ::boost::winapi::INVALID_HANDLE_VALUE_) _source.assign(source); if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_) _sink.assign(sink); return *this; } async_pipe& async_pipe::operator=(const async_pipe & p) { auto proc = ::boost::winapi::GetCurrentProcess(); ::boost::winapi::HANDLE_ source; ::boost::winapi::HANDLE_ sink; //cannot get the handle from a const object. auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source); auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink); source_in.get_executor(); if (source_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_) source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, source_in.native_handle(), proc, &source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (sink_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_) sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, sink_in.native_handle(), proc, &sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); //so we also assign the io_context if (source != ::boost::winapi::INVALID_HANDLE_VALUE_) _source = ::boost::asio::windows::stream_handle(source_in.get_executor(), source); else _source = ::boost::asio::windows::stream_handle(source_in.get_executor()); if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_) _sink = ::boost::asio::windows::stream_handle(source_in.get_executor(), sink); else _sink = ::boost::asio::windows::stream_handle(source_in.get_executor()); return *this; } async_pipe& async_pipe::operator=(async_pipe && rhs) { _source = std::move(rhs._source); _sink = std::move(rhs._sink); return *this; } template<class CharT, class Traits> async_pipe::operator basic_pipe<CharT, Traits>() const { auto proc = ::boost::winapi::GetCurrentProcess(); ::boost::winapi::HANDLE_ source; ::boost::winapi::HANDLE_ sink; //cannot get the handle from a const object. auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native_handle(); auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native_handle(); if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_) source = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, source_in, proc, &source, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_) sink = ::boost::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::winapi::DuplicateHandle( proc, sink_in, proc, &sink, 0, static_cast<::boost::winapi::BOOL_>(true), ::boost::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); return basic_pipe<CharT, Traits>{source, sink}; } inline bool operator==(const async_pipe & lhs, const async_pipe & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs) { return compare_handles(lhs.native_source(), rhs.native_source()) && compare_handles(lhs.native_sink(), rhs.native_sink()); } template<class Char, class Traits> inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs) { return !compare_handles(lhs.native_source(), rhs.native_source()) || !compare_handles(lhs.native_sink(), rhs.native_sink()); } }}}} #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */ detail/windows/shell_path.hpp 0000644 00000003040 15125237362 0012337 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_WINDOWS_SHELL_PATH_HPP #define BOOST_PROCESS_WINDOWS_SHELL_PATH_HPP #include <boost/process/detail/config.hpp> #include <system_error> #include <boost/filesystem/path.hpp> #include <boost/winapi/basic_types.hpp> #include <boost/winapi/get_system_directory.hpp> namespace boost { namespace process { namespace detail { namespace windows { inline boost::filesystem::path shell_path() { ::boost::winapi::WCHAR_ sysdir[260]; unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir)); if (!size) throw_last_error("GetSystemDirectory() failed"); boost::filesystem::path p = sysdir; return p / "cmd.exe"; } inline boost::filesystem::path shell_path(std::error_code &ec) noexcept { ::boost::winapi::WCHAR_ sysdir[260]; unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir)); boost::filesystem::path p; if (!size) ec = std::error_code( ::boost::winapi::GetLastError(), std::system_category()); else { ec.clear(); p = sysdir; p /= "cmd.exe"; } return p; } }}}} #endif detail/used_handles.hpp 0000644 00000004512 15125237362 0011165 0 ustar 00 // Copyright (c) 2016 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_USED_HANDLES_HPP_ #define BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_ #include <type_traits> #include <boost/fusion/include/filter_if.hpp> #include <boost/fusion/include/for_each.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/handles.hpp> #include <boost/process/detail/posix/asio_fwd.hpp> #else #include <boost/process/detail/windows/handles.hpp> #include <boost/process/detail/windows/asio_fwd.hpp> #endif namespace boost { namespace process { namespace detail { struct uses_handles { //If you get an error here, you must add a `get_handles` function that returns a range or a single handle value void get_used_handles() const; }; template<typename T> struct does_use_handle: std::is_base_of<uses_handles, T> {}; template<typename T> struct does_use_handle<T&> : std::is_base_of<uses_handles, T> {}; template<typename T> struct does_use_handle<const T&> : std::is_base_of<uses_handles, T> {}; template<typename Char, typename Sequence> class executor; template<typename Func> struct foreach_handle_invocator { Func & func; foreach_handle_invocator(Func & func) : func(func) {} template<typename Range> void invoke(const Range & range) const { for (auto handle_ : range) func(handle_); } void invoke(::boost::process::detail::api::native_handle_type handle) const {func(handle);}; template<typename T> void operator()(T & val) const {invoke(val.get_used_handles());} }; template<typename Executor, typename Function> void foreach_used_handle(Executor &exec, Function &&func) { boost::fusion::for_each(boost::fusion::filter_if<does_use_handle<boost::mpl::_>>(exec.seq), foreach_handle_invocator<Function>(func)); } template<typename Executor> std::vector<::boost::process::detail::api::native_handle_type> get_used_handles(Executor &exec) { std::vector<::boost::process::detail::api::native_handle_type> res; foreach_used_handle(exec, [&](::boost::process::detail::api::native_handle_type handle){res.push_back(handle);}); return res; } }}} #endif /* BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_ */ detail/child_decl.hpp 0000644 00000014675 15125237362 0010614 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/child.hpp * * Defines a child process class. */ #ifndef BOOST_PROCESS_CHILD_DECL_HPP #define BOOST_PROCESS_CHILD_DECL_HPP #include <boost/process/detail/config.hpp> #include <chrono> #include <memory> #include <boost/none.hpp> #include <atomic> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/child_handle.hpp> #include <boost/process/detail/posix/terminate.hpp> #include <boost/process/detail/posix/wait_for_exit.hpp> #include <boost/process/detail/posix/is_running.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/child_handle.hpp> #include <boost/process/detail/windows/terminate.hpp> #include <boost/process/detail/windows/wait_for_exit.hpp> #include <boost/process/detail/windows/is_running.hpp> #endif namespace boost { namespace process { using ::boost::process::detail::api::pid_t; class child { ::boost::process::detail::api::child_handle _child_handle; std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active); bool _attached = true; bool _terminated = false; bool _exited() { return _terminated || !::boost::process::detail::api::is_running(_exit_status->load()); }; public: typedef ::boost::process::detail::api::child_handle child_handle; typedef child_handle::process_handle_t native_handle_t; explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {} explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {}; child(const child&) = delete; child(child && lhs) noexcept : _child_handle(std::move(lhs._child_handle)), _exit_status(std::move(lhs._exit_status)), _attached (lhs._attached), _terminated (lhs._terminated) { lhs._attached = false; } template<typename ...Args> explicit child(Args&&...args); child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113 child& operator=(const child&) = delete; child& operator=(child && lhs) { _child_handle= std::move(lhs._child_handle); _exit_status = std::move(lhs._exit_status); _attached = lhs._attached; _terminated = lhs._terminated; lhs._attached = false; return *this; }; void detach() {_attached = false; } void join() {wait();} bool joinable() { return _attached;} ~child() { std::error_code ec; if (_attached && !_exited() && running(ec)) terminate(ec); } native_handle_t native_handle() const { return _child_handle.process_handle(); } int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());} pid_t id() const {return _child_handle.id(); } int native_exit_code() const {return _exit_status->load();} bool running() { std::error_code ec; bool b = running(ec); boost::process::detail::throw_error(ec, "running error"); return b; } void terminate() { std::error_code ec; terminate(ec); boost::process::detail::throw_error(ec, "terminate error"); } void wait() { std::error_code ec; wait(ec); boost::process::detail::throw_error(ec, "wait error"); } template< class Rep, class Period > bool wait_for (const std::chrono::duration<Rep, Period>& rel_time) { std::error_code ec; bool b = wait_for(rel_time, ec); boost::process::detail::throw_error(ec, "wait_for error"); return b; } template< class Clock, class Duration > bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) { std::error_code ec; bool b = wait_until(timeout_time, ec); boost::process::detail::throw_error(ec, "wait_until error"); return b; } bool running(std::error_code & ec) noexcept { ec.clear(); if (valid() && !_exited() && !ec) { int exit_code = 0; auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec); if (!ec && !res && !_exited()) _exit_status->store(exit_code); return res; } return false; } void terminate(std::error_code & ec) noexcept { if (valid() && running(ec) && !ec) boost::process::detail::api::terminate(_child_handle, ec); if (!ec) _terminated = true; } void wait(std::error_code & ec) noexcept { if (!_exited() && valid()) { int exit_code = 0; boost::process::detail::api::wait(_child_handle, exit_code, ec); if (!ec) _exit_status->store(exit_code); } } template< class Rep, class Period > bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept { return wait_until(std::chrono::steady_clock::now() + rel_time, ec); } template< class Clock, class Duration > bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept { if (!_exited()) { int exit_code = 0; auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec); if (!b || ec) return false; _exit_status->store(exit_code); } return true; } bool valid() const { return _child_handle.valid(); } operator bool() const {return valid();} bool in_group() const { return _child_handle.in_group(); } bool in_group(std::error_code &ec) const noexcept { return _child_handle.in_group(ec); } }; }} #endif detail/traits.hpp 0000644 00000001142 15125237362 0010031 0 ustar 00 // Copyright (c) 2016 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_TRAITS_HPP_ #define BOOST_PROCESS_TRAITS_HPP_ #include <boost/process/detail/traits/decl.hpp> #include <boost/process/detail/traits/async.hpp> #include <boost/process/detail/traits/cmd_or_exe.hpp> #include <boost/process/detail/traits/env.hpp> #include <boost/process/detail/traits/error.hpp> #include <boost/process/detail/traits/wchar_t.hpp> #endif /* BOOST_PROCESS_TRAITS_HPP_ */ detail/basic_cmd.hpp 0000644 00000017612 15125237362 0010440 0 ustar 00 // Copyright (c) 2016 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_BASIC_CMD_HPP_ #define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_ #include <boost/process/detail/config.hpp> #include <boost/process/detail/handler_base.hpp> #include <boost/process/detail/traits/cmd_or_exe.hpp> #include <boost/process/detail/traits/wchar_t.hpp> #if defined( BOOST_WINDOWS_API ) #include <boost/process/detail/windows/basic_cmd.hpp> #include <boost/process/detail/windows/cmd.hpp> #elif defined( BOOST_POSIX_API ) #include <boost/process/detail/posix/basic_cmd.hpp> #include <boost/process/detail/posix/cmd.hpp> #endif #include <boost/process/shell.hpp> #include <iterator> namespace boost { namespace process { namespace detail { template<typename Char> struct exe_setter_ { typedef Char value_type; typedef std::basic_string<Char> string_type; string_type exe_; exe_setter_(string_type && str) : exe_(std::move(str)) {} exe_setter_(const string_type & str) : exe_(str) {} }; template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {}; template<> struct char_converter<char, exe_setter_<wchar_t>> { static exe_setter_<char> conv(const exe_setter_<wchar_t> & in) { return {::boost::process::detail::convert(in.exe_)}; } }; template<> struct char_converter<wchar_t, exe_setter_<char>> { static exe_setter_<wchar_t> conv(const exe_setter_<char> & in) { return {::boost::process::detail::convert(in.exe_)}; } }; template <typename Char, bool Append > struct arg_setter_ { using value_type = Char; using string_type = std::basic_string<value_type>; std::vector<string_type> _args; typedef typename std::vector<string_type>::iterator iterator; typedef typename std::vector<string_type>::const_iterator const_iterator; template<typename Iterator> arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {} template<typename Range> arg_setter_(Range && str) : _args(std::begin(str), std::end(str)) {} iterator begin() {return _args.begin();} iterator end() {return _args.end();} const_iterator begin() const {return _args.begin();} const_iterator end() const {return _args.end();} arg_setter_(string_type & str) : _args{{str}} {} arg_setter_(string_type && s) : _args({std::move(s)}) {} arg_setter_(const string_type & s) : _args({s}) {} arg_setter_(const value_type* s) : _args({std::move(s)}) {} template<std::size_t Size> arg_setter_(const value_type (&s) [Size]) : _args({s}) {} }; template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {}; template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {}; template<> struct char_converter<char, arg_setter_<wchar_t, true>> { static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in) { std::vector<std::string> vec(in._args.size()); std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::wstring & ws) { return ::boost::process::detail::convert(ws); }); return {vec}; } }; template<> struct char_converter<wchar_t, arg_setter_<char, true>> { static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in) { std::vector<std::wstring> vec(in._args.size()); std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::string & ws) { return ::boost::process::detail::convert(ws); }); return {vec}; } }; template<> struct char_converter<char, arg_setter_<wchar_t, false>> { static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in) { std::vector<std::string> vec(in._args.size()); std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::wstring & ws) { return ::boost::process::detail::convert(ws); }); return {vec}; } }; template<> struct char_converter<wchar_t, arg_setter_<char, false>> { static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in) { std::vector<std::wstring> vec(in._args.size()); std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::string & ws) { return ::boost::process::detail::convert(ws); }); return {vec}; } }; using api::exe_cmd_init; template<typename Char> struct exe_builder { //set by path, because that will not be interpreted as a cmd bool not_cmd = false; bool shell = false; using string_type = std::basic_string<Char>; string_type exe; std::vector<string_type> args; void operator()(const boost::filesystem::path & data) { not_cmd = true; if (exe.empty()) exe = data.native(); else args.push_back(data.native()); } void operator()(const string_type & data) { if (exe.empty()) exe = data; else args.push_back(data); } void operator()(const Char* data) { if (exe.empty()) exe = data; else args.push_back(data); } void operator()(shell_) {shell = true;} void operator()(std::vector<string_type> && data) { if (data.empty()) return; auto itr = std::make_move_iterator(data.begin()); auto end = std::make_move_iterator(data.end()); if (exe.empty()) { exe = *itr; itr++; } args.insert(args.end(), itr, end); } void operator()(const std::vector<string_type> & data) { if (data.empty()) return; auto itr = data.begin(); auto end = data.end(); if (exe.empty()) { exe = *itr; itr++; } args.insert(args.end(), itr, end); } void operator()(exe_setter_<Char> && data) { not_cmd = true; exe = std::move(data.exe_); } void operator()(const exe_setter_<Char> & data) { not_cmd = true; exe = data.exe_; } void operator()(arg_setter_<Char, false> && data) { args.assign( std::make_move_iterator(data._args.begin()), std::make_move_iterator(data._args.end())); } void operator()(arg_setter_<Char, true> && data) { args.insert(args.end(), std::make_move_iterator(data._args.begin()), std::make_move_iterator(data._args.end())); } void operator()(const arg_setter_<Char, false> & data) { args.assign(data._args.begin(), data._args.end()); } void operator()(const arg_setter_<Char, true> & data) { args.insert(args.end(), data._args.begin(), data._args.end()); } api::exe_cmd_init<Char> get_initializer() { if (not_cmd || !args.empty()) { if (shell) return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args)); else return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args)); } else if (shell) return api::exe_cmd_init<Char>::cmd_shell(std::move(exe)); else return api::exe_cmd_init<Char>::cmd(std::move(exe)); } typedef api::exe_cmd_init<Char> result_type; }; template<> struct initializer_builder<cmd_or_exe_tag<char>> { typedef exe_builder<char> type; }; template<> struct initializer_builder<cmd_or_exe_tag<wchar_t>> { typedef exe_builder<wchar_t> type; }; }}} #endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */ detail/async_handler.hpp 0000644 00000005466 15125237362 0011352 0 ustar 00 /* * async_handler.hpp * * Created on: 12.06.2016 * Author: Klemens */ #ifndef BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ #define BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ #include <type_traits> #if defined(BOOST_POSIX_API) #include <boost/process/posix.hpp> #include <boost/process/detail/posix/async_handler.hpp> #include <boost/process/detail/posix/asio_fwd.hpp> #else #include <boost/process/detail/windows/async_handler.hpp> #include <boost/process/detail/windows/asio_fwd.hpp> #endif namespace boost { namespace process { namespace detail { #if defined(BOOST_POSIX_API) using ::boost::process::detail::posix::is_async_handler; using ::boost::process::detail::posix::does_require_io_context; #else using ::boost::process::detail::windows::is_async_handler; using ::boost::process::detail::windows::does_require_io_context; #endif template<typename ...Args> struct has_io_context; template<typename T, typename ...Args> struct has_io_context<T, Args...> { typedef typename has_io_context<Args...>::type next; typedef typename std::is_same< typename std::remove_reference<T>::type, boost::asio::io_context>::type is_ios; typedef typename std::conditional<is_ios::value, std::true_type, next>::type type; }; template<typename T> struct has_io_context<T> { typedef typename std::is_same< typename std::remove_reference<T>::type, boost::asio::io_context>::type type; }; template<typename ...Args> using has_io_context_t = typename has_io_context<Args...>::type; template<typename ...Args> struct has_async_handler; template<typename T, typename ...Args> struct has_async_handler<T, Args...> { typedef typename has_async_handler<Args...>::type next; typedef typename is_async_handler<T>::type is_ios; typedef typename std::conditional<is_ios::value, std::true_type, next>::type type; }; template<typename T> struct has_async_handler<T> { typedef typename is_async_handler<T>::type type; }; template<typename ...Args> struct needs_io_context; template<typename T, typename ...Args> struct needs_io_context<T, Args...> { typedef typename needs_io_context<Args...>::type next; typedef typename does_require_io_context<T>::type is_ios; typedef typename std::conditional<is_ios::value, std::true_type, next>::type type; }; template<typename T> struct needs_io_context<T> { typedef typename does_require_io_context<T>::type type; }; template<typename ...Args> boost::asio::io_context &get_io_context_var(boost::asio::io_context & f, Args&...) { return f; } template<typename First, typename ...Args> boost::asio::io_context &get_io_context_var(First&, Args&...args) { return get_io_context_var(args...); } } } } #endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */ handles.hpp 0000644 00000005736 15125237362 0006714 0 ustar 00 // 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_HANDLES_HPP_ #define BOOST_PROCESS_HANDLES_HPP_ /** * \file boost/process/handles.hpp * * Defines functions to obtain handles of the current process and limit the amount for inherited ones. */ #include <boost/process/detail/config.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/handles.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/handles.hpp> #endif #include <boost/process/detail/used_handles.hpp> namespace boost { namespace this_process { ///The native type for handles using native_handle_type = ::boost::process::detail::api::native_handle_type; /** * Get a snapshot of all handles of the process (i.e. file descriptors on posix and handles on windows) of the current process. * * \note This function might not work on certain posix systems. * * \note On Windows version older than windows 8 this function will iterate all the system handles, meaning it might be quite slow. * * \warning This functionality is utterly prone to race conditions, since other threads might open or close handles. * * \return The list of all open handles of the current process */ inline std::vector<native_handle_type> get_handles() { return ::boost::process::detail::api::get_handles(); } /** \overload std::vector<native_handle_type> get_handles() */ inline std::vector<native_handle_type> get_handles(std::error_code &ec) { return ::boost::process::detail::api::get_handles(ec); } /** Determines if a given handle is a a stream-handle, i.e. any handle that can be used with read and write functions. * Stream handles include pipes, regular files and sockets. * * \return Indicates if it's a stream handle. */ inline bool is_stream_handle(native_handle_type handle) { return ::boost::process::detail::api::is_stream_handle(handle); } /** \overload bool is_stream_handle(native_handle_type handle) */ inline bool is_stream_handle(native_handle_type handle, std::error_code &ec) { return ::boost::process::detail::api::is_stream_handle(handle, ec); } } namespace process { namespace detail { 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 * */ const static ::boost::process::detail::api::limit_handles_ limit_handles; } } #endif //BOOST_PROCESS_HANDLES_HPP_ locale.hpp 0000644 00000015470 15125237362 0006531 0 ustar 00 // Copyright (c) 2016 Klemens D. Morgenstern // Copyright (c) 2008 Beman Dawes // 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_LOCALE_HPP_ #define BOOST_PROCESS_LOCALE_HPP_ #include <system_error> #include <boost/process/detail/config.hpp> #if defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/locale.hpp> # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) #include <codecvt> #endif #include <locale> namespace boost { namespace process { namespace detail { class codecvt_category_t : public std::error_category { public: codecvt_category_t() = default; const char* name() const noexcept override {return "codecvt";} std::string message(int ev) const override { std::string str; switch (ev) { case std::codecvt_base::ok: str = "ok"; break; case std::codecvt_base::partial: str = "partial"; break; case std::codecvt_base::error: str = "error"; break; case std::codecvt_base::noconv: str = "noconv"; break; default: str = "unknown error"; } return str; } }; } ///Internally used error cateory for code conversion. inline const std::error_category& codecvt_category() { static const ::boost::process::detail::codecvt_category_t cat; return cat; } namespace detail { //copied from boost.filesystem inline std::locale default_locale() { # if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::process::detail::windows::windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) std::locale global_loc = std::locale(); return std::locale(global_loc, new std::codecvt_utf8<wchar_t>); # else // Other POSIX // ISO C calls std::locale("") "the locale-specific native environment", and this // locale is the default for many POSIX-based operating systems such as Linux. return std::locale(""); # endif } inline std::locale& process_locale() { static std::locale loc(default_locale()); return loc; } } ///The internally used type for code conversion. typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type; ///Get a reference to the currently used code converter. inline const codecvt_type& codecvt() { return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>( detail::process_locale()); } ///Set the locale of the library. inline std::locale imbue(const std::locale& loc) { std::locale temp(detail::process_locale()); detail::process_locale() = loc; return temp; } namespace detail { inline std::size_t convert(const char* from, const char* from_end, wchar_t* to, wchar_t* to_end, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports const char* from_next; wchar_t* to_next; auto res = cvt.in(state, from, from_end, from_next, to, to_end, to_next); if (res != std::codecvt_base::ok) throw process_error(res, ::boost::process::codecvt_category(), "boost::process codecvt to wchar_t"); return to_next - to; } inline std::size_t convert(const wchar_t* from, const wchar_t* from_end, char* to, char* to_end, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports const wchar_t* from_next; char* to_next; std::codecvt_base::result res; if ((res=cvt.out(state, from, from_end, from_next, to, to_end, to_next)) != std::codecvt_base::ok) throw process_error(res, ::boost::process::codecvt_category(), "boost::process codecvt to char"); return to_next - to; } inline std::wstring convert(const std::string & st, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { std::wstring out(st.size() + 10, ' '); //just to be sure auto sz = convert(st.c_str(), st.c_str() + st.size(), &out.front(), &out.back(), cvt); out.resize(sz); return out; } inline std::string convert(const std::wstring & st, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { std::string out(st.size() * 2, ' '); //just to be sure auto sz = convert(st.c_str(), st.c_str() + st.size(), &out.front(), &out.back(), cvt); out.resize(sz); return out; } inline std::vector<wchar_t> convert(const std::vector<char> & st, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { std::vector<wchar_t> out(st.size() + 10); //just to be sure auto sz = convert(st.data(), st.data() + st.size(), &out.front(), &out.back(), cvt); out.resize(sz); return out; } inline std::vector<char> convert(const std::vector<wchar_t> & st, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { std::vector<char> out(st.size() * 2); //just to be sure auto sz = convert(st.data(), st.data() + st.size(), &out.front(), &out.back(), cvt); out.resize(sz); return out; } inline std::wstring convert(const char *begin, const char* end, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { auto size = end-begin; std::wstring out(size + 10, ' '); //just to be sure using namespace std; auto sz = convert(begin, end, &out.front(), &out.back(), cvt); out.resize(sz); return out; } inline std::string convert(const wchar_t * begin, const wchar_t *end, const ::boost::process::codecvt_type & cvt = ::boost::process::codecvt()) { auto size = end-begin; std::string out(size * 2, ' '); //just to be sure auto sz = convert(begin, end , &out.front(), &out.back(), cvt); out.resize(sz); return out; } } } } #endif /* BOOST_PROCESS_LOCALE_HPP_ */ posix.hpp 0000644 00000005440 15125237362 0006430 0 ustar 00 // Copyright (c) 2016 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_POSIX_HPP_ #define BOOST_PROCESS_POSIX_HPP_ #include <boost/process/detail/posix/fd.hpp> #include <boost/process/detail/posix/handler.hpp> #include <boost/process/detail/posix/use_vfork.hpp> #include <boost/process/detail/posix/signal.hpp> /** \file boost/process/posix.hpp * * Header which provides the posix extensions. \xmlonly <programlisting> namespace boost { namespace process { namespace posix { <emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::fd">fd</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::sig">sig</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::use_vfork">use_vfork</globalname>; } } } </programlisting> * \endxmlonly * \warning Only available on posix. See the documentation of [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), * [execve](http://pubs.opengroup.org/onlinepubs/009695399/functions/execve.html) and * [vfork](http://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html). * */ namespace boost { namespace process { ///Namespace containing the posix exensions. namespace posix { /** This property lets you modify file-descriptors other than the standard ones (0,1,2). * * It provides the functions `bind`, which implements [dup2](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html) * and [close](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). * * Close can also be called with a range of file-descriptors to be closed. * */ constexpr ::boost::process::detail::posix::fd_ fd; /** This property lets you modify the handling of `SIGCHLD` for this call. It will be reset afterwards. It can be set to default, by the expression `sig.dfl()`, set to ignore with `sig.ign()` or assigned a custom handler. A custom handler must have the type `sighandler_t`and can be assigned with the following syntax: \code{.cpp} sig = handler; sig(handler); \endcode \warning @ref spawn will automatically use `sig.ign()`, which will override if you pass a custom handler. */ constexpr ::boost::process::detail::posix::sig_ sig; /** This property will replace the usage of [fork](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html) by [vfork](http://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html). \note `vfork` is no longer an official part of the posix standard. */ constexpr ::boost::process::detail::posix::use_vfork_ use_vfork; using ::boost::process::detail::posix::sighandler_t; }}} #endif /* BOOST_PROCESS_POSIX_HPP_ */ windows.hpp 0000644 00000007133 15125237362 0006761 0 ustar 00 // Copyright (c) 2016 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_WINDOWS_HPP_ #define BOOST_PROCESS_WINDOWS_HPP_ #include <boost/process/detail/windows/show_window.hpp> /** \file boost/process/windows.hpp * * Header which provides the windows extensions. \xmlonly <programlisting> namespace boost { namespace process { namespace windows { <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::hide">hide</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::maximized">maximized</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::minimized">minimized</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::minimized_not_active">minimized_not_active</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::not_active">not_active</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::show">show</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::show_normal">show_normal</globalname>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::create_no_window">create_no_window</globalname>; } } } </programlisting> * \endxmlonly * \warning Only available on windows. * See the parameter documentation of [ShowWindow](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548.aspx) for more details. */ namespace boost { namespace process { ///Namespace containing the windows extensions. namespace windows { ///Hides the window and activates another window. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_HIDE_ > hide; ///Activates the window and displays it as a maximized window. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWMAXIMIZED_ > maximized; ///Activates the window and displays it as a minimized window. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWMINIMIZED_ > minimized; ///Displays the window as a minimized window. This value is similar to `minimized`, except the window is not activated. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWMINNOACTIVE_> minimized_not_active; ///Displays a window in its most recent size and position. This value is similar to show_normal`, except that the window is not activated. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWNOACTIVATE_ > not_active; ///Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWNORMAL_ > show; ///Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time. constexpr ::boost::process::detail::windows::show_window<::boost::winapi::SW_SHOWNORMAL_ > show_normal; ///Adds the [CREATE_NO_WINDOW](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx) flag. constexpr ::boost::process::detail::windows::create_no_window_ create_no_window; }}} #endif /* BOOST_PROCESS_WINDOWS_HPP_ */ spawn.hpp 0000644 00000003611 15125237362 0006414 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/spawn.hpp * * Defines the spawn function. */ #ifndef BOOST_PROCESS_SPAWN_HPP #define BOOST_PROCESS_SPAWN_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/child_decl.hpp> #include <boost/process/detail/execute_impl.hpp> #include <boost/process/detail/async_handler.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/posix.hpp> #endif namespace boost { namespace process { namespace detail { } /** Launch a process and detach it. Returns no handle. This function starts a process and immediately detaches it. It thereby prevents the system from creating a zombie process, but will also cause the system to be unable to wait for the child to exit. \note This will set `SIGCHLD` to `SIGIGN` on posix. \warning This function does not allow asynchronous operations, since it cannot wait for the end of the process. It will fail to compile if a reference to `boost::asio::io_context` is passed. */ template<typename ...Args> inline void spawn(Args && ...args) { typedef typename ::boost::process::detail::has_async_handler<Args...>::type has_async; static_assert( !has_async::value, "Spawn cannot wait for exit, so async properties cannot be used"); auto c = ::boost::process::detail::execute_impl( #if defined(BOOST_POSIX_API) ::boost::process::posix::sig.ign(), #endif std::forward<Args>(args)...); c.detach(); } }} #endif async_pipe.hpp 0000644 00000017016 15125237362 0007422 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // // 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_ASYNC_PIPE_HPP #define BOOST_PROCESS_ASYNC_PIPE_HPP #include <boost/config.hpp> #include <boost/process/detail/config.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/async_pipe.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/async_pipe.hpp> #endif namespace boost { namespace process { #if defined(BOOST_PROCESS_DOXYGEN) /** Class implementing and asnychronous I/O-Object for use with boost.asio. * It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or * boost::asio::posix::stream_descriptor. * * It can be used directly with boost::asio::async_read or async_write. * * \note The object is copyable, but that does invoke a handle duplicate. */ class async_pipe { public: /** Typedef for the native handle representation. * \note This is the handle on the system, not the boost.asio class. * */ typedef platform_specific native_handle_type; /** Typedef for the handle representation of boost.asio. * */ typedef platform_specific handle_type; typedef typename handle_type::executor_type executor_type; /** Construct a new async_pipe, does automatically open the pipe. * Initializes source and sink with the same io_context. * @note Windows creates a named pipe here, where the name is automatically generated. */ inline async_pipe(boost::asio::io_context & ios); /** Construct a new async_pipe, does automatically open the pipe. * @note Windows creates a named pipe here, where the name is automatically generated. */ inline async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink); /** Construct a new async_pipe, does automatically open. * Initializes source and sink with the same io_context. * * @note Windows restricts possible names. */ inline async_pipe(boost::asio::io_context & ios, const std::string & name); /** Construct a new async_pipe, does automatically open. * * @note Windows restricts possible names. */ inline async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name); /** Copy-Constructor of the async pipe. * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. * */ async_pipe(const async_pipe& lhs); /** Move-Constructor of the async pipe. */ async_pipe(async_pipe&& lhs); /** Construct the async-pipe from a pipe. * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. * */ template<class CharT, class Traits = std::char_traits<CharT>> explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p); /** Construct the async-pipe from a pipe, with two different io_context objects. * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. * */ template<class CharT, class Traits = std::char_traits<CharT>> explicit async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const basic_pipe<CharT, Traits> & p); /** Assign a basic_pipe. * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. * */ template<class CharT, class Traits = std::char_traits<CharT>> inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p); /** Copy Assign a pipe. * @note Duplicates the handles. */ async_pipe& operator=(const async_pipe& lhs); /** Move assign a pipe */ async_pipe& operator=(async_pipe&& lhs); /** Destructor. Closes the pipe handles. */ ~async_pipe(); /** Explicit cast to basic_pipe. */ template<class CharT, class Traits = std::char_traits<CharT>> inline explicit operator basic_pipe<CharT, Traits>() const; /** Cancel the current asynchronous operations. */ void cancel(); /** Close the pipe handles. */ void close(); /** Close the pipe handles. While passing an error_code * */ void close(std::error_code & ec); /** Check if the pipes are open. */ bool is_open() const; /** Async close, i.e. close after current operation is completed. * * \note There is no guarantee that this will indeed read the entire pipe-buffer */ void async_close(); /** Read some data from the handle. * See the boost.asio documentation for more details. */ template<typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence & buffers); /** Write some data to the handle. * See the boost.asio documentation for more details. */ template<typename MutableBufferSequence> std::size_t write_some(const MutableBufferSequence & buffers); /** Get the native handle of the source. */ native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();} /** Get the native handle of the sink. */ native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();} /** Start an asynchronous read. * * See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details. */ template<typename MutableBufferSequence, typename ReadHandler> detail::dummy async_read_some( const MutableBufferSequence & buffers, ReadHandler &&handler); /** Start an asynchronous write. * See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details. */ template<typename ConstBufferSequence, typename WriteHandler> detail::dummy async_write_some( const ConstBufferSequence & buffers, WriteHandler && handler); ///Get the asio handle of the pipe sink. const handle_type & sink () const &; ///Get the asio handle of the pipe source. const handle_type & source() const &; ///Get the asio handle of the pipe sink. Qualified as rvalue handle_type && sink () &&; ///Get the asio handle of the pipe source. Qualified as rvalue handle_type && source() &&; /// Move the source out of this class and change the io_context. Qualified as rvalue. \attention Will always move. handle_type source(::boost::asio::io_context& ios) &&; /// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move handle_type sink (::boost::asio::io_context& ios) &&; /// Copy the source out of this class and change the io_context. \attention Will always copy. handle_type source(::boost::asio::io_context& ios) const &; /// Copy the sink out of this class and change the io_context. \attention Will always copy handle_type sink (::boost::asio::io_context& ios) const &; }; #else using ::boost::process::detail::api::async_pipe; #endif }} #endif async.hpp 0000644 00000007143 15125237362 0006405 0 ustar 00 // Copyright (c) 2016 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) /** \file boost/process/async.hpp The header which provides the basic asynchrounous features. It provides the on_exit property, which allows callbacks when the process exits. It also implements the necessary traits for passing an boost::asio::io_context, which is needed for asynchronous communication. It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html) into the boost::process namespace for convenience. \xmlonly <programlisting> namespace boost { namespace process { <emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>; <emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>; } } </programlisting> \endxmlonly */ #ifndef BOOST_PROCESS_ASYNC_HPP_ #define BOOST_PROCESS_ASYNC_HPP_ #include <boost/process/detail/traits.hpp> #include <boost/process/detail/on_exit.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/streambuf.hpp> #include <boost/asio/buffer.hpp> #include <type_traits> #include <boost/fusion/iterator/deref.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/detail/posix/io_context_ref.hpp> #include <boost/process/detail/posix/async_in.hpp> #include <boost/process/detail/posix/async_out.hpp> #include <boost/process/detail/posix/on_exit.hpp> #elif defined(BOOST_WINDOWS_API) #include <boost/process/detail/windows/io_context_ref.hpp> #include <boost/process/detail/windows/async_in.hpp> #include <boost/process/detail/windows/async_out.hpp> #include <boost/process/detail/windows/on_exit.hpp> #endif namespace boost { namespace process { namespace detail { struct async_tag; template<typename T> struct is_io_context : std::false_type {}; template<> struct is_io_context<api::io_context_ref> : std::true_type {}; template<typename Tuple> inline asio::io_context& get_io_context(const Tuple & tup) { auto& ref = *boost::fusion::find_if<is_io_context<boost::mpl::_>>(tup); return ref.get(); } struct async_builder { boost::asio::io_context * ios; void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;}; typedef api::io_context_ref result_type; api::io_context_ref get_initializer() {return api::io_context_ref (*ios);}; }; template<> struct initializer_builder<async_tag> { typedef async_builder type; }; } using ::boost::asio::buffer; #if defined(BOOST_PROCESS_DOXYGEN) /** When an io_context is passed, the on_exit property can be used, to be notified when the child process exits. The following syntax is valid \code{.cpp} on_exit=function; on_exit(function); \endcode with `function` being a callable object with the signature `(int, const std::error_code&)` or an `std::future<int>`. \par Example \code{.cpp} io_context ios; child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){}); std::future<int> exit_code; chlid c2("ls", ios, on_exit=exit_code); \endcode \note The handler is not invoked when the launch fails. \warning When used \ref ignore_error it might get invoked on error. \warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the same restrictions as that class (do not register a handler for `SIGCHLD` except by using `boost::asio::signal_set`). */ constexpr static ::boost::process::detail::on_exit_ on_exit{}; #endif }} #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */ child.hpp 0000644 00000012275 15125237362 0006355 0 ustar 00 // Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 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) /** * \file boost/process/child.hpp * * Defines a child process class. */ #ifndef BOOST_PROCESS_CHILD_HPP #define BOOST_PROCESS_CHILD_HPP #include <boost/process/detail/config.hpp> #include <boost/process/detail/child_decl.hpp> #include <boost/process/detail/execute_impl.hpp> #if defined(BOOST_POSIX_API) #include <boost/process/posix.hpp> #endif namespace boost { ///The main namespace of boost.process. namespace process { template<typename ...Args> child::child(Args&&...args) : child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {} ///Typedef for the type of an pid_t typedef ::boost::process::detail::api::pid_t pid_t; #if defined(BOOST_PROCESS_DOXYGEN) /** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread), * in that it has a join and detach function. * * @attention The destructor will call terminate on the process if not joined or detached without any warning. * */ class child { /** Type definition for the native process handle. */ typedef platform_specific native_handle_t; /** Construct the child from a pid. * * @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific. */ explicit child(pid_t & pid) : _child_handle(pid) {}; /** Move-Constructor.*/ child(child && lhs); /** Construct a child from a property list and launch it * The standard version is to create a subprocess, which will spawn the process. */ template<typename ...Args> explicit child(Args&&...args); /** Construct an empty child. */ child() = default; /** Move assign. */ child& operator=(child && lhs); /** Detach the child, i.e. let it run after this handle dies. */ void detach(); /** Join the child. This just calls wait, but that way the naming is similar to std::thread */ void join(); /** Check if the child is joinable. */ bool joinable(); /** Destructor. * @attention Will call terminate (without warning) when the child was neither joined nor detached. */ ~child(); /** Get the native handle for the child process. */ native_handle_t native_handle() const; /** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */ int exit_code() const; /** Get the Process Identifier. */ pid_t id() const; /** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited * for or if it was terminated. */ int native_exit_code() const; /** Check if the child process is running. */ bool running(); /** \overload void running() */ bool running(std::error_code & ec) noexcept; /** Wait for the child process to exit. */ void wait(); /** \overload void wait() */ void wait(std::error_code & ec) noexcept; /** Wait for the child process to exit for a period of time. * \return True if child exited while waiting. */ template< class Rep, class Period > bool wait_for (const std::chrono::duration<Rep, Period>& rel_time); /** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */ bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept; /** Wait for the child process to exit until a point in time. * \return True if child exited while waiting.*/ template< class Clock, class Duration > bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ); /** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/ bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept; /** Check if this handle holds a child process. * @note That does not mean, that the process is still running. It only means, that the handle does or did exist. */ bool valid() const; /** Same as valid, for convenience. */ explicit operator bool() const; /** Check if the the chlid process is in any process group. */ bool in_group() const; /** \overload bool in_group() const */ bool in_group(std::error_code & ec) const noexcept; /** Terminate the child process. * * This function will cause the child process to unconditionally and immediately exit. * It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix * and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows. * */ void terminate(); /** \overload void terminate() */ void terminate(std::error_code & ec) noexcept; }; #endif }} #endif
| ver. 1.6 |
Github
|
.
| PHP 8.2.30 | ??????????? ?????????: 0.01 |
proxy
|
phpinfo
|
???????????