diff options
Diffstat (limited to 'boost/process/detail/posix')
38 files changed, 4076 insertions, 0 deletions
diff --git a/boost/process/detail/posix/asio_fwd.hpp b/boost/process/detail/posix/asio_fwd.hpp new file mode 100644 index 0000000000..06d5c19214 --- /dev/null +++ b/boost/process/detail/posix/asio_fwd.hpp @@ -0,0 +1,79 @@ +// 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> + +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; +class io_service; + + +class signal_set_service; +template <typename SignalSetService> + +class basic_signal_set; +typedef basic_signal_set<signal_set_service> signal_set; + +template <typename Handler> +class basic_yield_context; + +namespace posix { + +class stream_descriptor_service; + +template <typename StreamDesscriptorService> +class basic_stream_descriptor; +typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor; + + + +class object_handle_service; + +template <typename ObjectHandleService> +class basic_object_handle; + +typedef basic_object_handle<object_handle_service> object_handle; + +} //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_ */ diff --git a/boost/process/detail/posix/async_handler.hpp b/boost/process/detail/posix/async_handler.hpp new file mode 100644 index 0000000000..a61cff3372 --- /dev/null +++ b/boost/process/detail/posix/async_handler.hpp @@ -0,0 +1,40 @@ +// 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_service {};
+ +struct async_handler : handler_base_ext, require_io_service
+{
+};
+ +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_service : std::is_base_of<require_io_service, T> {};
+ +template<typename T>
+struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
+ +template<typename T>
+struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
+ + +}}}}
+ +#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
diff --git a/boost/process/detail/posix/async_in.hpp b/boost/process/detail/posix/async_in.hpp new file mode 100644 index 0000000000..9814c593f2 --- /dev/null +++ b/boost/process/detail/posix/async_in.hpp @@ -0,0 +1,95 @@ +// 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>
+ +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_service
+{
+ 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 &exec)
+ {
+ 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&ec, std::size_t size){});
+ + 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)
+ {
+ pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
+ }
+ + 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");
+ + ::close(pipe->native_source());
+ }
+};
+ + +}}}}
+ +#endif
diff --git a/boost/process/detail/posix/async_out.hpp b/boost/process/detail/posix/async_out.hpp new file mode 100644 index 0000000000..b0f7876714 --- /dev/null +++ b/boost/process/detail/posix/async_out.hpp @@ -0,0 +1,170 @@ +// 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>
+ +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_service
+{
+ 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 &exec)
+ {
+ auto pipe = this->pipe;
+ boost::asio::async_read(*pipe, buf,
+ [pipe](const boost::system::error_code&, std::size_t size){});
+ + 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_service(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());
+ }
+};
+ + + + +template<int p1, int p2, typename Type>
+struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
+ ::boost::process::detail::posix::require_io_service
+{
+ 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 &exec)
+ {
+ 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 size)
+ {
+ 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;
+ 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_service(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());
+ }
+ +};
+ +}}}}
+ +#endif
diff --git a/boost/process/detail/posix/async_pipe.hpp b/boost/process/detail/posix/async_pipe.hpp new file mode 100644 index 0000000000..d849559c20 --- /dev/null +++ b/boost/process/detail/posix/async_pipe.hpp @@ -0,0 +1,355 @@ +// 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 <system_error> +#include <string> + +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; + + inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {} + + inline async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & 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_service & ios, const std::string & name) + : async_pipe(ios, ios, name) {} + + inline async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & 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_service & ios_source, + ::boost::asio::io_service & 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_service & 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() + { + if (_sink .native() != -1) + ::close(_sink.native()); + if (_source.native() != -1) + ::close(_source.native()); + } + + 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()) + _sink.get_io_service(). post([this]{_sink.close();}); + if (_source.is_open()) + _source.get_io_service().post([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); + } + + native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();} + native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();} + + 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) + { + _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) + { + _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_service& ios) && + { + ::boost::asio::posix::stream_descriptor stolen(ios, _source.release()); + return stolen; + } + handle_type sink (::boost::asio::io_service& ios) && + { + ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release()); + return stolen; + } + + handle_type source(::boost::asio::io_service& ios) const & + { + auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native(); + return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in)); + } + handle_type sink (::boost::asio::io_service& ios) const & + { + auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native(); + return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in)); + } +}; + + +async_pipe::async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & 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_io_service()), + _sink( const_cast<async_pipe&>(p)._sink.get_io_service()) +{ + + //cannot get the handle from a const object. + auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native(); + auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native(); + if (source_in == -1) + _source.assign(-1); + else + { + _source.assign(::dup(source_in)); + if (_source.native()== -1) + ::boost::process::detail::throw_last_error("dup()"); + } + + if (sink_in == -1) + _sink.assign(-1); + else + { + _sink.assign(::dup(sink_in)); + if (_sink.native() == -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 &>(_source).native(); + auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native(); + 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) +{ + if (_source.native_handle() == -1) + ::close(_source.native()); + + if (_sink.native_handle() == -1) + ::close(_sink.native()); + + _source.assign(lhs._source.native_handle()); + _sink .assign(lhs._sink .native_handle()); + lhs._source.assign(-1); + lhs._sink .assign(-1); + 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(); + auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native(); + + + 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_ */ diff --git a/boost/process/detail/posix/basic_cmd.hpp b/boost/process/detail/posix/basic_cmd.hpp new file mode 100644 index 0000000000..eefcc5c53f --- /dev/null +++ b/boost/process/detail/posix/basic_cmd.hpp @@ -0,0 +1,177 @@ +// 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(); + + + if (!args.empty()) + { + 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()); + + for (auto & v : args) + vec.push_back(&v.front()); + + vec.push_back(nullptr); + + return vec; +} + + +}}}} + +#endif diff --git a/boost/process/detail/posix/basic_pipe.hpp b/boost/process/detail/posix/basic_pipe.hpp new file mode 100644 index 0000000000..77fc90a4c1 --- /dev/null +++ b/boost/process/detail/posix/basic_pipe.hpp @@ -0,0 +1,193 @@ +// 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 & name) : _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) + { + auto write_len = ::write(_sink, data, count * sizeof(char_type)); + if (write_len == -1) + ::boost::process::detail::throw_last_error(); + + return write_len; + } + int_type read(char_type * data, int_type count) + { + auto read_len = ::read(_source, data, count * sizeof(char_type)); + if (read_len == -1) + ::boost::process::detail::throw_last_error(); + + return read_len; + } + + bool is_open() + { + return (_source != -1) || + (_sink != -1); + } + + void close() + { + ::close(_source); + ::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 diff --git a/boost/process/detail/posix/child_handle.hpp b/boost/process/detail/posix/child_handle.hpp new file mode 100644 index 0000000000..44ec43ea68 --- /dev/null +++ b/boost/process/detail/posix/child_handle.hpp @@ -0,0 +1,60 @@ +// 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 &ec) const noexcept {return true;} + + typedef int process_handle_t; + process_handle_t process_handle() const { return pid; } + + bool valid() const + { + return pid != -1; + } +}; + +}}}} + +#endif diff --git a/boost/process/detail/posix/close_in.hpp b/boost/process/detail/posix/close_in.hpp new file mode 100644 index 0000000000..74cffd6729 --- /dev/null +++ b/boost/process/detail/posix/close_in.hpp @@ -0,0 +1,30 @@ +// 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> + +namespace boost { namespace process { namespace detail { namespace posix { + +struct close_in : handler_base_ext +{ + 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"); + } +}; + +}}}} + +#endif diff --git a/boost/process/detail/posix/close_out.hpp b/boost/process/detail/posix/close_out.hpp new file mode 100644 index 0000000000..f3659f5544 --- /dev/null +++ b/boost/process/detail/posix/close_out.hpp @@ -0,0 +1,55 @@ +// 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/posix/handler.hpp> + +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; +}; + +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 diff --git a/boost/process/detail/posix/cmd.hpp b/boost/process/detail/posix/cmd.hpp new file mode 100644 index 0000000000..ab4f4fb066 --- /dev/null +++ b/boost/process/detail/posix/cmd.hpp @@ -0,0 +1,104 @@ +// 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 diff --git a/boost/process/detail/posix/compare_handles.hpp b/boost/process/detail/posix/compare_handles.hpp new file mode 100644 index 0000000000..634757215f --- /dev/null +++ b/boost/process/detail/posix/compare_handles.hpp @@ -0,0 +1,42 @@ +// 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_ */ diff --git a/boost/process/detail/posix/env_init.hpp b/boost/process/detail/posix/env_init.hpp new file mode 100644 index 0000000000..4d01cdad11 --- /dev/null +++ b/boost/process/detail/posix/env_init.hpp @@ -0,0 +1,41 @@ +// 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_ */ diff --git a/boost/process/detail/posix/environment.hpp b/boost/process/detail/posix/environment.hpp new file mode 100644 index 0000000000..1011c03a9d --- /dev/null +++ b/boost/process/detail/posix/environment.hpp @@ -0,0 +1,322 @@ +// 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 environ;}
+};
+ +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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ 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_ */
diff --git a/boost/process/detail/posix/exe.hpp b/boost/process/detail/posix/exe.hpp new file mode 100644 index 0000000000..9de68acc4e --- /dev/null +++ b/boost/process/detail/posix/exe.hpp @@ -0,0 +1,36 @@ +// 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_ */ diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp new file mode 100644 index 0000000000..5d03fd184e --- /dev/null +++ b/boost/process/detail/posix/executor.hpp @@ -0,0 +1,547 @@ +// 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> + +#if !defined(__GLIBC__) +#include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> +#endif + +namespace boost { namespace process { namespace detail { namespace posix { + +inline int execvpe(const char* filename, char * const arg_list[], char* env[]) +{ +#if defined(__GLIBC__) + return ::execvpe(filename, arg_list, env); +#else + //use my own implementation + std::string fn = filename; + if ((fn.find('/') == std::string::npos) && ::access(fn.c_str(), X_OK)) + { + auto e = ::environ; + while ((*e != nullptr) && !boost::starts_with(*e, "PATH=")) + e++; + + if (e != nullptr) + { + std::vector<std::string> path; + boost::split(path, *e, boost::is_any_of(":")); + + for (const std::string & pp : path) + { + auto p = pp + "/" + filename; + if (!::access(p.c_str(), X_OK)) + { + fn = p; + break; + } + } + } + } + return ::execve(fn.c_str(), arg_list, env); +#endif +} + +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 &ec, const char* msg, 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_) + { + 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::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(); + + 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)); + if (cmd_style) + ::boost::process::detail::posix::execvpe(exe, cmd_line, env); + else + ::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_) +{ + int p[2]; + if (::pipe(p) == -1) + { + set_error(::boost::process::detail::get_last_error(), "pipe(2) failed"); + return child(); + } + if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1) + { + set_error(::boost::process::detail::get_last_error(), "fcntl(2) failed"); + 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(); + } + + 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[1]; + ::close(p[0]); + + boost::fusion::for_each(seq, call_on_exec_setup(*this)); + if (cmd_style) + ::boost::process::detail::posix::execvpe(exe, cmd_line, env); + else + ::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(p[1]); + + _exit(EXIT_FAILURE); + return child(); + } + + child c(child_handle(pid), exit_status); + + + + ::close(p[1]); + _read_error(p[0]); + ::close(p[0]); + + 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; +} + +#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(); + + 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)); + + if (cmd_style) + ::boost::process::detail::posix::execvpe(exe, cmd_line, env); + else + ::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 diff --git a/boost/process/detail/posix/fd.hpp b/boost/process/detail/posix/fd.hpp new file mode 100644 index 0000000000..51790c3237 --- /dev/null +++ b/boost/process/detail/posix/fd.hpp @@ -0,0 +1,92 @@ +// 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> + +namespace boost { namespace process { namespace detail { namespace posix { + + +struct close_fd_ : handler_base_ext +{ + 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"); + } + +private: + int fd_; +}; + +template <class Range> +struct close_fds_ : handler_base_ext +{ +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; + } + } + +private: + Range fds_; +}; + + + +template <class FileDescriptor> +struct bind_fd_ : handler_base_ext +{ +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"); + } + +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 diff --git a/boost/process/detail/posix/file_descriptor.hpp b/boost/process/detail/posix/file_descriptor.hpp new file mode 100644 index 0000000000..72552444b0 --- /dev/null +++ b/boost/process/detail/posix/file_descriptor.hpp @@ -0,0 +1,76 @@ +// 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_ */
diff --git a/boost/process/detail/posix/file_in.hpp b/boost/process/detail/posix/file_in.hpp new file mode 100644 index 0000000000..c3ceeeead2 --- /dev/null +++ b/boost/process/detail/posix/file_in.hpp @@ -0,0 +1,40 @@ +// 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 <cstdio>
+#include <unistd.h>
+ +namespace boost { namespace process { namespace detail { namespace posix {
+ +struct file_in : handler_base_ext
+{
+ file_descriptor file;
+ int handle = file.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
diff --git a/boost/process/detail/posix/file_out.hpp b/boost/process/detail/posix/file_out.hpp new file mode 100644 index 0000000000..6fef732598 --- /dev/null +++ b/boost/process/detail/posix/file_out.hpp @@ -0,0 +1,65 @@ +// 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 <unistd.h>
+namespace boost { namespace process { namespace detail { namespace posix {
+ +template<int p1, int p2>
+struct file_out : handler_base_ext
+{
+ 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)) {}
+ + + 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
diff --git a/boost/process/detail/posix/group_handle.hpp b/boost/process/detail/posix/group_handle.hpp new file mode 100644 index 0000000000..856b36a6b0 --- /dev/null +++ b/boost/process/detail/posix/group_handle.hpp @@ -0,0 +1,103 @@ +// 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/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 & ec) noexcept + { + return ::getpgid(proc) == grp; + + } + + bool valid() const + { + return grp != -1; + } + +}; + +inline void terminate(group_handle &p) +{ + if (::killpg(p.grp, SIGKILL) == -1) + boost::process::detail::throw_last_error("killpg(2) failed"); + p.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 bool in_group() +{ + return true; +} + + + +}}}} + + +#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ diff --git a/boost/process/detail/posix/group_ref.hpp b/boost/process/detail/posix/group_ref.hpp new file mode 100644 index 0000000000..d46e631fe7 --- /dev/null +++ b/boost/process/detail/posix/group_ref.hpp @@ -0,0 +1,52 @@ +// 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& exec) 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_ */ diff --git a/boost/process/detail/posix/handler.hpp b/boost/process/detail/posix/handler.hpp new file mode 100644 index 0000000000..506db4e649 --- /dev/null +++ b/boost/process/detail/posix/handler.hpp @@ -0,0 +1,74 @@ +// 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_ */
diff --git a/boost/process/detail/posix/io_service_ref.hpp b/boost/process/detail/posix/io_service_ref.hpp new file mode 100644 index 0000000000..ced1d51033 --- /dev/null +++ b/boost/process/detail/posix/io_service_ref.hpp @@ -0,0 +1,155 @@ +// 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_SERVICE_REF_HPP_
+#define BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
+ +#include <boost/process/detail/posix/handler.hpp>
+#include <boost/process/detail/posix/async_handler.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/signal_set.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 <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_service_ref : handler_base_ext
+{
+ io_service_ref(boost::asio::io_service & ios) : ios(ios)
+ {
+ + }
+ boost::asio::io_service &get() {return ios;};
+ + boost::asio::signal_set *signal_p = nullptr;
+ + template <class Executor>
+ void on_setup(Executor& exec)
+ {
+ //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));
+ + wait_handler wh(std::move(funcs), ios, exec.exit_status);
+ + signal_p = wh.signal_.get();
+ signal_p->async_wait(std::move(wh));
+ + }
+ + template <class Executor>
+ void on_error(Executor & exec, const std::error_code & ec) const
+ {
+ if (signal_p != nullptr)
+ {
+ boost::system::error_code ec;
+ signal_p->cancel(ec);
+ }
+ }
+ + struct wait_handler
+ {
+ std::shared_ptr<boost::asio::signal_set> signal_;
+ std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
+ std::shared_ptr<std::atomic<int>> exit_status;
+ + wait_handler(const wait_handler & ) = default;
+ wait_handler(wait_handler && ) = default;
+ wait_handler(
+ std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
+ boost::asio::io_service & ios,
+ const std::shared_ptr<std::atomic<int>> &exit_status)
+ : signal_(new boost::asio::signal_set(ios, SIGCHLD)),
+ funcs(std::move(funcs)),
+ exit_status(exit_status)
+ {
+ + }
+ void operator()(const boost::system::error_code & ec_in, int /*signal*/)
+ {
+ if (ec_in.value() == boost::asio::error::operation_aborted)
+ return;
+ + + int status;
+ ::wait(&status);
+ + std::error_code ec(ec_in.value(), std::system_category());
+ int val = WEXITSTATUS(status);
+ exit_status->store(status);
+ + for (auto & func : funcs)
+ func(val, ec);
+ }
+ + };
+private:
+ boost::asio::io_service &ios;
+};
+ +}}}}
+ +#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
diff --git a/boost/process/detail/posix/is_running.hpp b/boost/process/detail/posix/is_running.hpp new file mode 100644 index 0000000000..e8a009dd22 --- /dev/null +++ b/boost/process/detail/posix/is_running.hpp @@ -0,0 +1,78 @@ +// 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 { + + +constexpr int still_active = 0x7F; +static_assert(!WIFEXITED(still_active), "Internal Error"); + +inline bool is_running(const child_handle &p, int & exit_code) +{ + int status; + auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED); + + if (ret == -1) + { + if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously. + ::boost::process::detail::throw_last_error("is_running error"); + + return false; + } + else if (ret == 0) + return true; + else //exited + { + if (WIFEXITED(status)) + exit_code = status; + return false; + } +} + +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|WUNTRACED); + + 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 (WIFEXITED(status)) + exit_code = status; + + return false; + } +} + +inline bool is_running(int code) +{ + return !WIFEXITED(code); +} + +inline int eval_exit_status(int code) +{ + return WEXITSTATUS(code); +} + +}}}} + +#endif diff --git a/boost/process/detail/posix/null_in.hpp b/boost/process/detail/posix/null_in.hpp new file mode 100644 index 0000000000..9f082054c6 --- /dev/null +++ b/boost/process/detail/posix/null_in.hpp @@ -0,0 +1,35 @@ +// 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>
+ +namespace boost { namespace process { namespace detail { namespace posix {
+ +struct null_in : handler_base_ext
+{
+ file_descriptor source{"/dev/null", file_descriptor::read};
+ +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
diff --git a/boost/process/detail/posix/null_out.hpp b/boost/process/detail/posix/null_out.hpp new file mode 100644 index 0000000000..ed4f915f35 --- /dev/null +++ b/boost/process/detail/posix/null_out.hpp @@ -0,0 +1,58 @@ +// 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 <unistd.h>
+namespace boost { namespace process { namespace detail { namespace posix {
+ +template<int p1, int p2>
+struct null_out : handler_base_ext
+{
+ file_descriptor sink{"/dev/null", file_descriptor::write};
+
+ template <typename Executor>
+ void on_exec_setup(Executor &e) const;
+};
+ +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
diff --git a/boost/process/detail/posix/on_exit.hpp b/boost/process/detail/posix/on_exit.hpp new file mode 100644 index 0000000000..d3160aff32 --- /dev/null +++ b/boost/process/detail/posix/on_exit.hpp @@ -0,0 +1,35 @@ +// 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 & exec)
+ {
+ return handler;
+ + };
+};
+ + +}}}}
+#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
diff --git a/boost/process/detail/posix/pipe_in.hpp b/boost/process/detail/posix/pipe_in.hpp new file mode 100644 index 0000000000..fa294cf310 --- /dev/null +++ b/boost/process/detail/posix/pipe_in.hpp @@ -0,0 +1,90 @@ +// 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>
+ + +namespace boost { namespace process { namespace detail { namespace posix {
+ +struct pipe_in : handler_base_ext
+{
+ int source;
+ int sink; //opposite end
+ + pipe_in(int sink, int source) : source(source), sink(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");
+ ::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
diff --git a/boost/process/detail/posix/pipe_out.hpp b/boost/process/detail/posix/pipe_out.hpp new file mode 100644 index 0000000000..0148c19d26 --- /dev/null +++ b/boost/process/detail/posix/pipe_out.hpp @@ -0,0 +1,116 @@ +// 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(), "dup3() failed");
+ ::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");
+ ::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");
+ ::close(sink);
+ ::close(source);
+}
+ +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
diff --git a/boost/process/detail/posix/search_path.hpp b/boost/process/detail/posix/search_path.hpp new file mode 100644 index 0000000000..1ce5c65575 --- /dev/null +++ b/boost/process/detail/posix/search_path.hpp @@ -0,0 +1,39 @@ +// 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) +{ + std::string result; + for (const boost::filesystem::path & pp : path) + { + auto p = pp / filename; + if (!::access(p.c_str(), X_OK)) + return p; + } + return ""; +} + +}}}} + +#endif diff --git a/boost/process/detail/posix/shell_path.hpp b/boost/process/detail/posix/shell_path.hpp new file mode 100644 index 0000000000..870cab6b90 --- /dev/null +++ b/boost/process/detail/posix/shell_path.hpp @@ -0,0 +1,32 @@ +// 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 diff --git a/boost/process/detail/posix/signal.hpp b/boost/process/detail/posix/signal.hpp new file mode 100644 index 0000000000..f9ef32d05d --- /dev/null +++ b/boost/process/detail/posix/signal.hpp @@ -0,0 +1,79 @@ +// 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 diff --git a/boost/process/detail/posix/start_dir.hpp b/boost/process/detail/posix/start_dir.hpp new file mode 100644 index 0000000000..1b73172c8b --- /dev/null +++ b/boost/process/detail/posix/start_dir.hpp @@ -0,0 +1,38 @@ +// 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(const string_type &s) : s_(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 diff --git a/boost/process/detail/posix/terminate.hpp b/boost/process/detail/posix/terminate.hpp new file mode 100644 index 0000000000..d8048362b0 --- /dev/null +++ b/boost/process/detail/posix/terminate.hpp @@ -0,0 +1,44 @@ +// 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) +{ + if (::kill(p.pid, SIGKILL) == -1) + boost::process::detail::throw_last_error("kill(2) failed"); + int status; + ::waitpid(p.pid, &status, 0); //just to clean it up +} + +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, 0); //just to clean it up +} + +}}}} + +#endif diff --git a/boost/process/detail/posix/use_vfork.hpp b/boost/process/detail/posix/use_vfork.hpp new file mode 100644 index 0000000000..98f74b24ff --- /dev/null +++ b/boost/process/detail/posix/use_vfork.hpp @@ -0,0 +1,33 @@ +/* + * 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_ */ diff --git a/boost/process/detail/posix/wait_for_exit.hpp b/boost/process/detail/posix/wait_for_exit.hpp new file mode 100644 index 0000000000..bf25e2a3d8 --- /dev/null +++ b/boost/process/detail/posix/wait_for_exit.hpp @@ -0,0 +1,205 @@ +// 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> + + +namespace boost { namespace process { namespace detail { namespace posix { + +inline void wait(const child_handle &p, int & exit_code) +{ + pid_t ret; + int status; + do + { + ret = ::waitpid(p.pid, &status, 0); + } while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status))); + if (ret == -1) + boost::process::detail::throw_last_error("waitpid(2) failed"); + exit_code = status; +} + +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))); + + if (ret == -1) + ec = boost::process::detail::get_last_error(); + else + { + ec.clear(); + exit_code = status; + } + + +} + +template< class Rep, class Period > +inline bool wait_for( + const child_handle &p, + int & exit_code, + const std::chrono::duration<Rep, Period>& rel_time) +{ + + pid_t ret; + int status; + + auto start = std::chrono::system_clock::now(); + auto time_out = start + rel_time; + + bool time_out_occured = false; + do + { + ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + boost::process::detail::throw_last_error("waitpid(2) failed"); + + exit_code = status; + + return !time_out_occured; +} + + +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 +{ + + pid_t ret; + int status; + + auto start = std::chrono::system_clock::now(); + auto time_out = start + rel_time; + + bool time_out_occured = false; + do + { + ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + ec = boost::process::detail::get_last_error(); + else + { + ec.clear(); + exit_code = status; + } + + return !time_out_occured; +} + + + +template< class Rep, class Period > +inline bool wait_until( + const child_handle &p, + int & exit_code, + const std::chrono::duration<Rep, Period>& time_out) +{ + + pid_t ret; + int status; + + bool time_out_occured = false; + do + { + ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + boost::process::detail::throw_last_error("waitpid(2) failed"); + + exit_code = status; + + return !time_out_occured; +} + + +template< class Rep, class Period > +inline bool wait_until( + const child_handle &p, + int & exit_code, + const std::chrono::duration<Rep, Period>& time_out, + std::error_code & ec) noexcept +{ + + pid_t ret; + int status; + + bool time_out_occured = false; + do + { + ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + ec = boost::process::detail::get_last_error(); + else + { + ec.clear(); + exit_code = status; + } + + return !time_out_occured; +} + +}}}} + +#endif diff --git a/boost/process/detail/posix/wait_group.hpp b/boost/process/detail/posix/wait_group.hpp new file mode 100644 index 0000000000..8b768ffc14 --- /dev/null +++ b/boost/process/detail/posix/wait_group.hpp @@ -0,0 +1,191 @@ +// 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 <system_error> +#include <sys/types.h> +#include <sys/wait.h> + +namespace boost { namespace process { namespace detail { namespace posix { + +inline void wait(const group_handle &p) +{ + pid_t ret; + int status; + do + { + ret = ::waitpid(-p.grp, &status, 0); + } while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status))); + if (ret == -1) + boost::process::detail::throw_last_error("waitpid(2) failed"); +} + +inline void wait(const group_handle &p, std::error_code &ec) noexcept +{ + pid_t ret; + int status; + + do + { + ret = ::waitpid(-p.grp, &status, 0); + } + while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status))); + + if (ret == -1) + ec = boost::process::detail::get_last_error(); + else + ec.clear(); + +} + +template< class Rep, class Period > +inline bool wait_for( + const group_handle &p, + const std::chrono::duration<Rep, Period>& rel_time) +{ + + pid_t ret; + int status; + + auto start = std::chrono::system_clock::now(); + auto time_out = start + rel_time; + + bool time_out_occured = false; + do + { + ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + boost::process::detail::throw_last_error("waitpid(2) failed"); + + + return !time_out_occured; +} + + +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 +{ + + pid_t ret; + int status; + + auto start = std::chrono::system_clock::now(); + auto time_out = start + rel_time; + + bool time_out_occured = false; + do + { + ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + ec = boost::process::detail::get_last_error(); + else + ec.clear(); + + return !time_out_occured; +} + + + +template< class Rep, class Period > +inline bool wait_until( + const group_handle &p, + const std::chrono::duration<Rep, Period>& time_out) +{ + + pid_t ret; + int status; + + auto start = std::chrono::system_clock::now(); + + bool time_out_occured = false; + do + { + ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + boost::process::detail::throw_last_error("waitpid(2) failed"); + + + return !time_out_occured; +} + + +template< class Rep, class Period > +inline bool wait_until( + const group_handle &p, + const std::chrono::duration<Rep, Period>& time_out, + std::error_code & ec) noexcept +{ + + pid_t ret; + int status; + + auto start = std::chrono::system_clock::now(); + + bool time_out_occured = false; + do + { + ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG); + if (std::chrono::system_clock::now() >= time_out) + { + time_out_occured = true; + break; + } + } + while (((ret == -1) && errno == EINTR) || + ((ret != -1) && !WIFEXITED(status))); + + + if (ret == -1) + ec = boost::process::detail::get_last_error(); + else + ec.clear(); + + return !time_out_occured; +} + +}}}} + +#endif |