Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:06

0001 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
0002 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
0003 // Copyright (c) 2009 Boris Schaeling
0004 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
0005 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
0011 #define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
0012 
0013 #include <boost/process/detail/child_decl.hpp>
0014 #include <boost/process/error.hpp>
0015 #include <boost/process/pipe.hpp>
0016 #include <boost/process/detail/posix/basic_pipe.hpp>
0017 #include <boost/process/detail/posix/use_vfork.hpp>
0018 #include <boost/fusion/algorithm/iteration/for_each.hpp>
0019 #include <cstdlib>
0020 #include <sys/types.h>
0021 #include <fcntl.h>
0022 #include <errno.h>
0023 #include <unistd.h>
0024 
0025 #include <boost/algorithm/string/predicate.hpp>
0026 #include <boost/algorithm/string/split.hpp>
0027 #include <boost/algorithm/string/classification.hpp>
0028 
0029 #include <boost/core/ignore_unused.hpp>
0030 
0031 namespace boost { namespace process { namespace detail { namespace posix {
0032 
0033 template<typename Executor>
0034 struct on_setup_t
0035 {
0036     Executor & exec;
0037     on_setup_t(Executor & exec) : exec(exec) {};
0038     template<typename T>
0039     void operator()(T & t) const
0040     {
0041         if (!exec.error())
0042             t.on_setup(exec);
0043     }
0044 };
0045 
0046 template<typename Executor>
0047 struct on_error_t
0048 {
0049     Executor & exec;
0050     const std::error_code & error;
0051     on_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
0052     template<typename T>
0053     void operator()(T & t) const
0054     {
0055         t.on_error(exec, error);
0056     }
0057 };
0058 
0059 template<typename Executor>
0060 struct on_success_t
0061 {
0062     Executor & exec;
0063     on_success_t(Executor & exec) : exec(exec) {};
0064     template<typename T>
0065     void operator()(T & t) const {t.on_success(exec);}
0066 };
0067 
0068 
0069 
0070 template<typename Executor>
0071 struct on_fork_error_t
0072 {
0073     Executor & exec;
0074     const std::error_code & error;
0075     on_fork_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
0076 
0077     template<typename T>
0078     void operator()(T & t) const
0079     {
0080         t.on_fork_error(exec, error);
0081     }
0082 };
0083 
0084 
0085 template<typename Executor>
0086 struct on_exec_setup_t
0087 {
0088     Executor & exec;
0089     on_exec_setup_t(Executor & exec) : exec(exec) {};
0090 
0091     template<typename T>
0092     void operator()(T & t) const
0093     {
0094         t.on_exec_setup(exec);
0095     }
0096 };
0097 
0098 
0099 template<typename Executor>
0100 struct on_exec_error_t
0101 {
0102     Executor & exec;
0103     const std::error_code &ec;
0104     on_exec_error_t(Executor & exec, const std::error_code & error) : exec(exec), ec(error) {};
0105 
0106     template<typename T>
0107     void operator()(T & t) const
0108     {
0109         t.on_exec_error(exec, ec);
0110     }
0111 };
0112 
0113 template<typename Executor>
0114 struct on_fork_success_t
0115 {
0116     Executor & exec;
0117     on_fork_success_t(Executor & exec) : exec(exec) {};
0118 
0119     template<typename T>
0120     void operator()(T & t) const
0121     {
0122         t.on_fork_success(exec);
0123     }
0124 };
0125 
0126 template<typename Executor> on_setup_t  <Executor> call_on_setup  (Executor & exec) {return exec;}
0127 template<typename Executor> on_error_t  <Executor> call_on_error  (Executor & exec, const std::error_code & ec)
0128 {
0129     return on_error_t<Executor> (exec, ec);
0130 }
0131 template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
0132 
0133 template<typename Executor> on_fork_error_t  <Executor> call_on_fork_error  (Executor & exec, const std::error_code & ec)
0134 {
0135     return on_fork_error_t<Executor> (exec, ec);
0136 }
0137 
0138 
0139 template<typename Executor> on_exec_setup_t  <Executor> call_on_exec_setup  (Executor & exec) {return exec;}
0140 template<typename Executor> on_exec_error_t  <Executor> call_on_exec_error  (Executor & exec, const std::error_code & ec)
0141 {
0142     return on_exec_error_t<Executor> (exec, ec);
0143 }
0144 
0145 
0146 template<typename Sequence>
0147 class executor
0148 {
0149     template<typename HasHandler, typename UseVFork>
0150     void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {}
0151 
0152     int _pipe_sink = -1;
0153 
0154 
0155     void write_error(const std::error_code & ec, const char * msg)
0156     {
0157         //I am the child
0158         const auto len = static_cast<int>(std::strlen(msg));
0159         int data[2] = {ec.value(), len + 1};
0160 
0161         boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
0162         boost::ignore_unused(::write(_pipe_sink, msg, len));
0163     }
0164 
0165     void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
0166     {
0167         if (this->pid == 0) //on the fork.
0168             write_error(ec, msg);
0169         else
0170         {
0171             this->_ec  = ec;
0172             this->_msg = msg;
0173         }
0174     }
0175     void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::false_)
0176     {
0177         if (this->pid == 0)
0178             write_error(ec, msg);
0179         else
0180             throw process_error(ec, msg);
0181     }
0182 
0183 
0184     void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::true_)
0185     {
0186         this->_ec  = ec;
0187         this->_msg = msg;
0188     }
0189     void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::true_)
0190     {
0191         if (this->pid == 0)
0192         {
0193             this->_ec  = ec;
0194             this->_msg = msg;
0195         }
0196         else
0197             throw process_error(ec, msg);
0198     }
0199 
0200     void check_error(boost::mpl::true_) {};
0201     void check_error(boost::mpl::false_)
0202     {
0203         if (_ec)
0204             throw process_error(_ec, _msg);
0205     }
0206 
0207     typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
0208     typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
0209     typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
0210 
0211     inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
0212     inline child invoke(boost::mpl::false_, boost::mpl::true_ );
0213     inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
0214     inline child invoke(boost::mpl::false_, boost::mpl::false_ );
0215     void _write_error(int sink)
0216     {
0217         int data[2] = {_ec.value(),static_cast<int>(_msg.size())};
0218         while (::write(sink, &data[0], sizeof(int) *2) == -1)
0219         {
0220             auto err = errno;
0221 
0222             if (err == EBADF)
0223                 return;
0224             else if ((err != EINTR) && (err != EAGAIN))
0225                 break;
0226         }
0227         while (::write(sink, &_msg.front(), _msg.size()) == -1)
0228         {
0229             auto err = errno;
0230 
0231             if (err == EBADF)
0232                 return;
0233             else if ((err != EINTR) && (err != EAGAIN))
0234                 break;
0235         }
0236     }
0237 
0238     void _read_error(int source)
0239     {
0240         int data[2];
0241 
0242         _ec.clear();
0243         int count = 0;
0244         while ((count = ::read(source, &data[0], sizeof(int) *2 ) ) == -1)
0245         {
0246             //actually, this should block until it's read.
0247             auto err = errno;
0248             if ((err != EAGAIN ) && (err != EINTR))
0249                 set_error(std::error_code(err, std::system_category()), "Error read pipe");
0250         }
0251         if (count == 0)
0252             return  ;
0253 
0254         std::error_code ec(data[0], std::system_category());
0255         std::string msg(data[1], ' ');
0256 
0257         while (::read(source, &msg.front(), msg.size() ) == -1)
0258         {
0259             //actually, this should block until it's read.
0260             auto err = errno;
0261             if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
0262                 return;
0263                 //EAGAIN not yet forked, EINTR interrupted, i.e. try again
0264             else if ((err != EAGAIN ) && (err != EINTR))
0265                 set_error(std::error_code(err, std::system_category()), "Error read pipe");
0266         }
0267         set_error(ec, std::move(msg));
0268     }
0269 
0270     std::string prepare_cmd_style_fn; //buffer
0271 
0272     inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations.
0273     {
0274         //use my own implementation
0275         prepare_cmd_style_fn = exe;
0276         if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
0277         {
0278             const auto * e = ::environ;
0279             while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
0280                 e++;
0281 
0282             if ((e != nullptr) && (*e != nullptr))
0283             {
0284                 std::vector<std::string> path;
0285                 //the beginning of the string contains "PATH="
0286                 boost::split(path, (*e) + 5, boost::is_any_of(":"));
0287 
0288                 for (const std::string & pp : path)
0289                 {
0290                     auto p = pp + "/" + exe;
0291                     if (!::access(p.c_str(), X_OK))
0292                     {
0293                         prepare_cmd_style_fn = p;
0294                         break;
0295                     }
0296                 }
0297             }
0298         }
0299         exe = prepare_cmd_style_fn.c_str();
0300     }
0301 
0302     std::error_code _ec;
0303     std::string _msg;
0304 public:
0305     executor(Sequence & seq) : seq(seq)
0306     {
0307     }
0308 
0309     child operator()()
0310     {
0311         return invoke(has_ignore_error(), shall_use_vfork());
0312     }
0313 
0314 
0315     Sequence & seq;
0316     const char * exe      = nullptr;
0317     char *const* cmd_line = nullptr;
0318     bool cmd_style = false;
0319     char **env      = ::environ;
0320     pid_t pid = -1;
0321     std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
0322 
0323     const std::error_code & error() const {return _ec;}
0324 
0325     void set_error(const std::error_code &ec, const char* msg)
0326     {
0327         internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
0328     }
0329     void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
0330 
0331     std::vector<int> get_used_handles() const 
0332     {
0333         if (_pipe_sink == -1)
0334             return {};
0335         else
0336             return {_pipe_sink};
0337     };
0338 };
0339 
0340 template<typename Sequence>
0341 child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore errors
0342 {
0343     boost::fusion::for_each(seq, call_on_setup(*this));
0344     if (_ec)
0345         return child();
0346     if (cmd_style)
0347         prepare_cmd_style();
0348 
0349     this->pid = ::fork();
0350     if (pid == -1)
0351     {
0352         auto ec = boost::process::detail::get_last_error();
0353         boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
0354         return child();
0355     }
0356     else if (pid == 0)
0357     {
0358         boost::fusion::for_each(seq, call_on_exec_setup(*this));
0359         ::execve(exe, cmd_line, env);
0360         auto ec = boost::process::detail::get_last_error();
0361         boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
0362         _exit(EXIT_FAILURE);
0363     }
0364 
0365     child c(child_handle(pid), exit_status);
0366 
0367     boost::fusion::for_each(seq, call_on_success(*this));
0368 
0369     return c;
0370 }
0371 
0372 template<typename Sequence>
0373 child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
0374 {
0375     {
0376         struct pipe_guard
0377         {
0378             int p[2];
0379             pipe_guard() : p{-1,-1} {}
0380 
0381             ~pipe_guard()
0382             {
0383                 if (p[0] != -1)
0384                     ::close(p[0]);
0385                 if (p[1] != -1)
0386                     ::close(p[1]);
0387             }
0388         } p{};
0389 
0390         if (::pipe(p.p) == -1)
0391         {
0392             set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
0393             return child();
0394         }
0395         if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
0396         {
0397             auto err = ::boost::process::detail::get_last_error();
0398             set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
0399             return child();
0400         }
0401         _ec.clear();
0402         boost::fusion::for_each(seq, call_on_setup(*this));
0403 
0404         if (_ec)
0405         {
0406             boost::fusion::for_each(seq, call_on_error(*this, _ec));
0407             return child();
0408         }
0409 
0410         if (cmd_style)
0411             prepare_cmd_style();
0412 
0413         this->pid = ::fork();
0414         if (pid == -1)
0415         {
0416             _ec = boost::process::detail::get_last_error();
0417             _msg = "fork() failed";
0418             boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
0419             boost::fusion::for_each(seq, call_on_error(*this, _ec));
0420             return child();
0421         }
0422         else if (pid == 0)
0423         {
0424             _pipe_sink = p.p[1];
0425             ::close(p.p[0]);
0426 
0427             boost::fusion::for_each(seq, call_on_exec_setup(*this));
0428             ::execve(exe, cmd_line, env);
0429             _ec = boost::process::detail::get_last_error();
0430             _msg = "execve failed";
0431             boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
0432 
0433             _write_error(_pipe_sink);
0434             ::close(p.p[1]);
0435 
0436             _exit(EXIT_FAILURE);
0437             return child();
0438         }
0439 
0440         ::close(p.p[1]);
0441         p.p[1] = -1;
0442         _read_error(p.p[0]);
0443 
0444     }
0445     if (_ec)
0446     {
0447         //if an error occurred we need to reap the child process
0448         ::waitpid(this->pid, nullptr, WNOHANG);
0449         boost::fusion::for_each(seq, call_on_error(*this, _ec));
0450         return child();
0451     }
0452 
0453     child c(child_handle(pid), exit_status);
0454 
0455     boost::fusion::for_each(seq, call_on_success(*this));
0456 
0457     if (_ec)
0458     {
0459         boost::fusion::for_each(seq, call_on_error(*this, _ec));
0460         return child();
0461     }
0462 
0463     return c;
0464 }
0465 
0466 #if BOOST_POSIX_HAS_VFORK
0467 
0468 
0469 template<typename Sequence>
0470 child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore errors
0471 {
0472     boost::fusion::for_each(seq, call_on_setup(*this));
0473     if (_ec)
0474         return child();
0475     this->pid = ::vfork();
0476     if (pid == -1)
0477     {
0478         auto ec = boost::process::detail::get_last_error();
0479         boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
0480         return child();
0481     }
0482     else if (pid == 0)
0483     {
0484         boost::fusion::for_each(seq, call_on_exec_setup(*this));
0485         ::execve(exe, cmd_line, env);
0486         auto ec = boost::process::detail::get_last_error();
0487         boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
0488         _exit(EXIT_FAILURE);
0489     }
0490     child c(child_handle(pid), exit_status);
0491 
0492     boost::fusion::for_each(seq, call_on_success(*this));
0493 
0494     return c;
0495 }
0496 
0497 template<typename Sequence>
0498 child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
0499 {
0500     boost::fusion::for_each(seq, call_on_setup(*this));
0501 
0502     if (_ec)
0503     {
0504         boost::fusion::for_each(seq, call_on_error(*this, _ec));
0505         return child();
0506     }
0507     _ec.clear();
0508     if (cmd_style)
0509         this->prepare_cmd_style();
0510 
0511     this->pid = ::vfork();
0512     if (pid == -1)
0513     {
0514         _ec = boost::process::detail::get_last_error();
0515         _msg = "fork() failed";
0516         boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
0517         boost::fusion::for_each(seq, call_on_error(*this, _ec));
0518 
0519         return child();
0520     }
0521     else if (pid == 0)
0522     {
0523         boost::fusion::for_each(seq, call_on_exec_setup(*this));
0524 
0525         ::execve(exe, cmd_line, env);
0526 
0527         _ec = boost::process::detail::get_last_error();
0528         _msg = "execve failed";
0529         boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
0530 
0531         _exit(EXIT_FAILURE);
0532         return child();
0533     }
0534     child c(child_handle(pid), exit_status);
0535 
0536     check_error(has_error_handler());
0537 
0538 
0539 
0540     if (_ec)
0541     {
0542         ::waitpid(this->pid, nullptr, WNOHANG);
0543         boost::fusion::for_each(seq, call_on_error(*this, _ec));
0544         return child();
0545     }
0546     else
0547         boost::fusion::for_each(seq, call_on_success(*this));
0548 
0549     if (_ec)
0550     {
0551         boost::fusion::for_each(seq, call_on_error(*this, _ec));
0552         return child();
0553     }
0554 
0555     return c;
0556 }
0557 
0558 #endif
0559 
0560 template<typename Char, typename Tup>
0561 inline executor<Tup> make_executor(Tup & tup)
0562 {
0563     return executor<Tup>(tup);
0564 }
0565 
0566 }}}}
0567 
0568 #endif