1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
3 // Copyright (c) 2009 Boris Schaeling
4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 #ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
11 #define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
13 #include <boost/process/detail/child_decl.hpp>
14 #include <boost/process/error.hpp>
15 #include <boost/process/pipe.hpp>
16 #include <boost/process/detail/posix/basic_pipe.hpp>
17 #include <boost/process/detail/posix/use_vfork.hpp>
18 #include <boost/fusion/algorithm/iteration/for_each.hpp>
20 #include <sys/types.h>
25 #include <boost/algorithm/string/predicate.hpp>
26 #include <boost/algorithm/string/split.hpp>
27 #include <boost/algorithm/string/classification.hpp>
29 namespace boost { namespace process { namespace detail { namespace posix {
31 template<typename Executor>
35 on_setup_t(Executor & exec) : exec(exec) {};
37 void operator()(T & t) const
44 template<typename Executor>
48 const std::error_code & error;
49 on_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
51 void operator()(T & t) const
53 t.on_error(exec, error);
57 template<typename Executor>
61 on_success_t(Executor & exec) : exec(exec) {};
63 void operator()(T & t) const {t.on_success(exec);}
68 template<typename Executor>
69 struct on_fork_error_t
72 const std::error_code & error;
73 on_fork_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
76 void operator()(T & t) const
78 t.on_fork_error(exec, error);
83 template<typename Executor>
84 struct on_exec_setup_t
87 on_exec_setup_t(Executor & exec) : exec(exec) {};
90 void operator()(T & t) const
92 t.on_exec_setup(exec);
97 template<typename Executor>
98 struct on_exec_error_t
101 const std::error_code &ec;
102 on_exec_error_t(Executor & exec, const std::error_code & error) : exec(exec), ec(error) {};
105 void operator()(T & t) const
107 t.on_exec_error(exec, ec);
111 template<typename Executor>
112 struct on_fork_success_t
115 on_fork_success_t(Executor & exec) : exec(exec) {};
118 void operator()(T & t) const
120 t.on_fork_success(exec);
124 template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
125 template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
127 return on_error_t<Executor> (exec, ec);
129 template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
131 template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
133 return on_fork_error_t<Executor> (exec, ec);
137 template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;}
138 template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
140 return on_exec_error_t<Executor> (exec, ec);
144 template<typename Sequence>
147 template<typename HasHandler, typename UseVFork>
148 void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {}
152 void write_error(const std::error_code & ec, const char * msg)
155 const auto len = std::strlen(msg);
156 int data[2] = {ec.value(), len + 1};
158 ::write(_pipe_sink, &data[0], sizeof(int) * 2);
159 ::write(_pipe_sink, msg, len);
162 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
164 if (this->pid == 0) //on the fork.
165 write_error(ec, msg);
172 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::false_)
175 write_error(ec, msg);
177 throw process_error(ec, msg);
181 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::true_)
186 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::true_)
194 throw process_error(ec, msg);
197 void check_error(boost::mpl::true_) {};
198 void check_error(boost::mpl::false_)
201 throw process_error(_ec, _msg);
204 typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
205 typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
206 typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
208 inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
209 inline child invoke(boost::mpl::false_, boost::mpl::true_ );
210 inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
211 inline child invoke(boost::mpl::false_, boost::mpl::false_ );
212 void _write_error(int sink)
214 int data[2] = {_ec.value(),static_cast<int>(_msg.size())};
215 while (::write(sink, &data[0], sizeof(int) *2) == -1)
221 else if ((err != EINTR) && (err != EAGAIN))
224 while (::write(sink, &_msg.front(), _msg.size()) == -1)
230 else if ((err != EINTR) && (err != EAGAIN))
235 void _read_error(int source)
241 while ((count = ::read(source, &data[0], sizeof(int) *2 ) ) == -1)
243 //actually, this should block until it's read.
245 if ((err != EAGAIN ) && (err != EINTR))
246 set_error(std::error_code(err, std::system_category()), "Error read pipe");
251 std::error_code ec(data[0], std::system_category());
252 std::string msg(data[1], ' ');
254 while (::read(source, &msg.front(), msg.size() ) == -1)
256 //actually, this should block until it's read.
258 if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
260 //EAGAIN not yet forked, EINTR interrupted, i.e. try again
261 else if ((err != EAGAIN ) && (err != EINTR))
262 set_error(std::error_code(err, std::system_category()), "Error read pipe");
264 set_error(ec, std::move(msg));
267 std::string prepare_cmd_style_fn; //buffer
269 inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations.
271 //use my own implementation
272 prepare_cmd_style_fn = exe;
273 if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
275 const auto * e = ::environ;
276 while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
279 if ((e != nullptr) && (*e != nullptr))
281 std::vector<std::string> path;
282 //the beginning of the string contains "PATH="
283 boost::split(path, (*e) + 5, boost::is_any_of(":"));
285 for (const std::string & pp : path)
287 auto p = pp + "/" + exe;
288 if (!::access(p.c_str(), X_OK))
290 prepare_cmd_style_fn = p;
296 exe = prepare_cmd_style_fn.c_str();
302 executor(Sequence & seq) : seq(seq)
308 return invoke(has_ignore_error(), shall_use_vfork());
313 const char * exe = nullptr;
314 char *const* cmd_line = nullptr;
315 bool cmd_style = false;
316 char **env = ::environ;
318 std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
320 const std::error_code & error() const {return _ec;}
322 void set_error(const std::error_code &ec, const char* msg)
324 internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
326 void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
330 template<typename Sequence>
331 child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore errors
333 boost::fusion::for_each(seq, call_on_setup(*this));
339 this->pid = ::fork();
342 auto ec = boost::process::detail::get_last_error();
343 boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
348 boost::fusion::for_each(seq, call_on_exec_setup(*this));
349 ::execve(exe, cmd_line, env);
350 auto ec = boost::process::detail::get_last_error();
351 boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
355 child c(child_handle(pid), exit_status);
357 boost::fusion::for_each(seq, call_on_success(*this));
362 template<typename Sequence>
363 child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
369 pipe_guard() : p{-1,-1} {}
380 if (::pipe(p.p) == -1)
382 set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
385 if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
387 auto err = ::boost::process::detail::get_last_error();
388 set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
392 boost::fusion::for_each(seq, call_on_setup(*this));
396 boost::fusion::for_each(seq, call_on_error(*this, _ec));
403 this->pid = ::fork();
406 _ec = boost::process::detail::get_last_error();
407 _msg = "fork() failed";
408 boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
409 boost::fusion::for_each(seq, call_on_error(*this, _ec));
417 boost::fusion::for_each(seq, call_on_exec_setup(*this));
418 ::execve(exe, cmd_line, env);
419 _ec = boost::process::detail::get_last_error();
420 _msg = "execve failed";
421 boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
423 _write_error(_pipe_sink);
437 boost::fusion::for_each(seq, call_on_error(*this, _ec));
441 child c(child_handle(pid), exit_status);
443 boost::fusion::for_each(seq, call_on_success(*this));
447 boost::fusion::for_each(seq, call_on_error(*this, _ec));
454 #if BOOST_POSIX_HAS_VFORK
457 template<typename Sequence>
458 child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore errors
460 boost::fusion::for_each(seq, call_on_setup(*this));
463 this->pid = ::vfork();
466 auto ec = boost::process::detail::get_last_error();
467 boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
472 boost::fusion::for_each(seq, call_on_exec_setup(*this));
473 ::execve(exe, cmd_line, env);
474 auto ec = boost::process::detail::get_last_error();
475 boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
478 child c(child_handle(pid), exit_status);
480 boost::fusion::for_each(seq, call_on_success(*this));
485 template<typename Sequence>
486 child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
488 boost::fusion::for_each(seq, call_on_setup(*this));
492 boost::fusion::for_each(seq, call_on_error(*this, _ec));
497 this->prepare_cmd_style();
499 this->pid = ::vfork();
502 _ec = boost::process::detail::get_last_error();
503 _msg = "fork() failed";
504 boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
505 boost::fusion::for_each(seq, call_on_error(*this, _ec));
511 boost::fusion::for_each(seq, call_on_exec_setup(*this));
513 ::execve(exe, cmd_line, env);
515 _ec = boost::process::detail::get_last_error();
516 _msg = "execve failed";
517 boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
522 child c(child_handle(pid), exit_status);
524 check_error(has_error_handler());
530 boost::fusion::for_each(seq, call_on_error(*this, _ec));
534 boost::fusion::for_each(seq, call_on_success(*this));
538 boost::fusion::for_each(seq, call_on_error(*this, _ec));
547 template<typename Char, typename Tup>
548 inline executor<Tup> make_executor(Tup & tup)
550 return executor<Tup>(tup);