Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:02:56

0001 // Copyright (c) 2022 Klemens D. Morgenstern
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 #ifndef BOOST_PROCESS_V2_POSIX_DEFAULT_LAUNCHER
0006 #define BOOST_PROCESS_V2_POSIX_DEFAULT_LAUNCHER
0007 
0008 #include <boost/process/v2/detail/config.hpp>
0009 #include <boost/process/v2/cstring_ref.hpp>
0010 #include <boost/process/v2/posix/detail/close_handles.hpp>
0011 #include <boost/process/v2/detail/throw_error.hpp>
0012 #include <boost/process/v2/detail/utf8.hpp>
0013 
0014 #if defined(BOOST_PROCESS_V2_STANDALONE)
0015 #include <asio/execution/executor.hpp>
0016 #include <asio/is_executor.hpp>
0017 #include <asio/execution_context.hpp>
0018 #include <asio/execution/context.hpp>
0019 #include <asio/query.hpp>
0020 #else
0021 #include <boost/asio/execution/executor.hpp>
0022 #include <boost/asio/is_executor.hpp>
0023 #include <boost/asio/execution_context.hpp>
0024 #include <boost/asio/execution/context.hpp>
0025 #include <boost/asio/query.hpp>
0026 #endif
0027 
0028 #include <fcntl.h>
0029 #include <sys/types.h>
0030 #include <sys/wait.h>
0031 #include <unistd.h>
0032 
0033 #if defined(__APPLE__)
0034 # include <crt_externs.h>
0035 # if !defined(environ)
0036 #  define environ (*_NSGetEnviron())
0037 # endif
0038 #elif defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
0039  extern "C" { extern char **environ; }
0040 #endif
0041 
0042 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0043 
0044 template<typename Executor>
0045 struct basic_process;
0046 
0047 namespace posix
0048 {
0049 
0050 
0051 namespace detail
0052 {
0053 
0054 struct base {};
0055 struct derived : base {};
0056 
0057 template<typename Launcher, typename Init>
0058 inline error_code invoke_on_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0059                                   const char * const * (&/*cmd_line*/),
0060                                   Init && /*init*/, base && )
0061 {
0062     return error_code{};
0063 }
0064 
0065 template<typename Launcher, typename Init>
0066 inline auto invoke_on_setup(Launcher & launcher, const filesystem::path &executable,
0067                             const char * const * (&cmd_line),
0068                             Init && init, derived && )
0069     -> decltype(init.on_setup(launcher, executable, cmd_line))
0070 {
0071     return init.on_setup(launcher, executable, cmd_line);
0072 }
0073 
0074 template<typename Launcher>
0075 inline error_code on_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0076                            const char * const * (&/*cmd_line*/))
0077 {
0078     return error_code{};
0079 }
0080 
0081 template<typename Launcher, typename Init1, typename ... Inits>
0082 inline error_code on_setup(Launcher & launcher, const filesystem::path &executable,
0083                            const char * const * (&cmd_line),
0084                            Init1 && init1, Inits && ... inits)
0085 {
0086     auto ec = invoke_on_setup(launcher, executable, cmd_line, init1, derived{});
0087     if (ec)
0088         return ec;
0089     else
0090         return on_setup(launcher, executable, cmd_line, inits...);
0091 }
0092 
0093 
0094 template<typename Launcher, typename Init>
0095 inline void invoke_on_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0096                             const char * const * (&/*cmd_line*/),
0097                             const error_code & /*ec*/, Init && /*init*/, base && )
0098 {
0099 }
0100 
0101 template<typename Launcher, typename Init>
0102 inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable,
0103                             const char * const * (&cmd_line),
0104                             const error_code & ec, Init && init, derived && )
0105 -> decltype(init.on_error(launcher, executable, cmd_line, ec))
0106 {
0107     init.on_error(launcher, executable, cmd_line, ec);
0108 }
0109 
0110 template<typename Launcher>
0111 inline void on_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0112                      const char * const * (&/*cmd_line*/),
0113                      const error_code & /*ec*/)
0114 {
0115 }
0116 
0117 template<typename Launcher, typename Init1, typename ... Inits>
0118 inline void on_error(Launcher & launcher, const filesystem::path &executable,
0119                      const char * const * (&cmd_line),
0120                      const error_code & ec,
0121                      Init1 && init1, Inits && ... inits)
0122 {
0123     invoke_on_error(launcher, executable, cmd_line, ec, init1, derived{});
0124     on_error(launcher, executable, cmd_line, ec, inits...);
0125 }
0126 
0127 template<typename Launcher, typename Init>
0128 inline void invoke_on_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0129                               const char * const * (&/*cmd_line*/),
0130                               Init && /*init*/, base && )
0131 {
0132 }
0133 
0134 template<typename Launcher, typename Init>
0135 inline auto invoke_on_success(Launcher & launcher, const filesystem::path &executable,
0136                               const char * const * (&cmd_line),
0137                               Init && init, derived && )
0138 -> decltype(init.on_success(launcher, executable, cmd_line))
0139 {
0140     init.on_success(launcher, executable, cmd_line);
0141 }
0142 
0143 template<typename Launcher>
0144 inline void on_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0145                        const char * const * (&/*cmd_line*/))
0146 {
0147 }
0148 
0149 template<typename Launcher, typename Init1, typename ... Inits>
0150 inline void on_success(Launcher & launcher, const filesystem::path &executable,
0151                        const char * const * (&cmd_line),
0152                        Init1 && init1, Inits && ... inits)
0153 {
0154     invoke_on_success(launcher, executable, cmd_line, init1, derived{});
0155     on_success(launcher, executable, cmd_line, inits...);
0156 }
0157 
0158 template<typename Launcher, typename Init>
0159 inline void invoke_on_fork_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0160                                  const char * const * (&/*cmd_line*/),
0161                                  const error_code & /*ec*/, Init && /*init*/, base && )
0162 {
0163 }
0164 
0165 template<typename Launcher, typename Init>
0166 inline auto invoke_on_fork_error(Launcher & launcher, const filesystem::path &executable,
0167                                  const char * const * (&cmd_line),
0168                                  const error_code & ec, Init && init, derived && )
0169 -> decltype(init.on_fork_error(launcher, executable, cmd_line, ec))
0170 {
0171     init.on_fork_error(launcher, executable, cmd_line, ec);
0172 }
0173 
0174 template<typename Launcher>
0175 inline void on_fork_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0176                           const char * const * (&/*cmd_line*/),
0177                           const error_code & /*ec*/)
0178 {
0179 }
0180 
0181 template<typename Launcher, typename Init1, typename ... Inits>
0182 inline void on_fork_error(Launcher & launcher, const filesystem::path &executable,
0183                           const char * const * (&cmd_line),
0184                           const error_code & ec,
0185                           Init1 && init1, Inits && ... inits)
0186 {
0187     invoke_on_fork_error(launcher, executable, cmd_line, ec, init1, derived{});
0188     on_fork_error(launcher, executable, cmd_line, ec, inits...);
0189 }
0190 
0191 template<typename Launcher, typename Init>
0192 inline error_code invoke_on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0193                                        const char * const * (&/*cmd_line*/),
0194                                        Init && /*init*/, base && )
0195 {
0196     return error_code{};
0197 }
0198 
0199 template<typename Launcher, typename Init>
0200 inline auto invoke_on_exec_setup(Launcher & launcher, const filesystem::path &executable,
0201                                  const char * const * (&cmd_line),
0202                                  Init && init, derived && )
0203 -> decltype(init.on_exec_setup(launcher, executable, cmd_line))
0204 {
0205     return init.on_exec_setup(launcher, executable, cmd_line);
0206 }
0207 
0208 template<typename Launcher>
0209 inline error_code on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0210                                 const char * const * (&/*cmd_line*/))
0211 {
0212     return error_code{};
0213 }
0214 
0215 template<typename Launcher, typename Init1, typename ... Inits>
0216 inline error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable,
0217                                 const char * const * (&cmd_line),
0218                                 Init1 && init1, Inits && ... inits)
0219 {
0220     auto ec = invoke_on_exec_setup(launcher, executable, cmd_line, init1, derived{});
0221     if (ec)
0222         return ec;
0223     else
0224         return on_exec_setup(launcher, executable, cmd_line, inits...);
0225 }
0226 
0227 
0228 
0229 template<typename Launcher, typename Init>
0230 inline void invoke_on_exec_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0231                                  const char * const * (&/*cmd_line*/),
0232                                  const error_code & /*ec*/, Init && /*init*/, base && )
0233 {
0234 }
0235 
0236 template<typename Launcher, typename Init>
0237 inline auto invoke_on_exec_error(Launcher & launcher, const filesystem::path &executable,
0238                                  const char * const * (&cmd_line),
0239                                  const error_code & ec, Init && init, derived && )
0240 -> decltype(init.on_exec_error(launcher, executable, cmd_line, ec))
0241 {
0242     init.on_exec_error(launcher, executable, cmd_line, ec);
0243 }
0244 
0245 template<typename Launcher>
0246 inline void on_exec_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/,
0247                           const char * const * (&/*cmd_line*/),
0248                           const error_code & /*ec*/)
0249 {
0250 }
0251 
0252 template<typename Launcher, typename Init1, typename ... Inits>
0253 inline void on_exec_error(Launcher & launcher, const filesystem::path &executable,
0254                           const char * const * (&cmd_line),
0255                           const error_code & ec,
0256                           Init1 && init1, Inits && ... inits)
0257 {
0258     invoke_on_exec_error(launcher, executable, cmd_line, ec, init1, derived{});
0259     on_exec_error(launcher, executable, cmd_line, ec, inits...);
0260 }
0261 }
0262 
0263 /// The default launcher for processes on windows.
0264 struct default_launcher
0265 {
0266     /// The pointer to the environment forwarded to the subprocess.
0267     const char * const * env = environ;
0268     /// The pid of the subprocess - will be assigned after fork.
0269     int pid = -1;
0270 
0271     /// The whitelist for file descriptors.
0272     std::vector<int> fd_whitelist = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
0273 
0274     default_launcher() = default;
0275 
0276     template<typename ExecutionContext, typename Args, typename ... Inits>
0277     auto operator()(ExecutionContext & context,
0278                     const typename std::enable_if<std::is_convertible<
0279                             ExecutionContext&, net::execution_context&>::value,
0280                             filesystem::path >::type & executable,
0281                     Args && args,
0282                     Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
0283     {
0284         error_code ec;
0285         auto proc =  (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0286 
0287         if (ec)
0288             v2::detail::throw_error(ec, "default_launcher");
0289 
0290         return proc;
0291     }
0292 
0293 
0294     template<typename ExecutionContext, typename Args, typename ... Inits>
0295     auto operator()(ExecutionContext & context,
0296                     error_code & ec,
0297                     const typename std::enable_if<std::is_convertible<
0298                             ExecutionContext&, net::execution_context&>::value,
0299                             filesystem::path >::type & executable,
0300                     Args && args,
0301                     Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
0302     {
0303         return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0304     }
0305 
0306     template<typename Executor, typename Args, typename ... Inits>
0307     auto operator()(Executor exec,
0308                     const typename std::enable_if<
0309                             net::execution::is_executor<Executor>::value ||
0310                             net::is_executor<Executor>::value,
0311                             filesystem::path >::type & executable,
0312                     Args && args,
0313                     Inits && ... inits ) -> basic_process<Executor>
0314     {
0315         error_code ec;
0316         auto proc =  (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0317 
0318         if (ec)
0319             v2::detail::throw_error(ec, "default_launcher");
0320 
0321         return proc;
0322     }
0323 
0324     template<typename Executor, typename Args, typename ... Inits>
0325     auto operator()(Executor exec,
0326                     error_code & ec,
0327                     const typename std::enable_if<
0328                             net::execution::is_executor<Executor>::value ||
0329                             net::is_executor<Executor>::value,
0330                             filesystem::path >::type & executable,
0331                     Args && args,
0332                     Inits && ... inits ) -> basic_process<Executor>
0333     {
0334         auto argv = this->build_argv_(executable, std::forward<Args>(args));
0335         {
0336             pipe_guard pg;
0337             if (::pipe(pg.p))
0338             {
0339                 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0340                 return basic_process<Executor>{exec};
0341             }
0342             if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
0343             {
0344                 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0345                 return basic_process<Executor>{exec};
0346             }
0347             ec = detail::on_setup(*this, executable, argv, inits ...);
0348             if (ec)
0349             {
0350                 detail::on_error(*this, executable, argv, ec, inits...);
0351                 return basic_process<Executor>(exec);
0352             }
0353             fd_whitelist.push_back(pg.p[1]);
0354 
0355             auto & ctx = net::query(
0356                     exec, net::execution::context);
0357 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0358             ctx.notify_fork(net::execution_context::fork_prepare);
0359 #endif
0360             pid = ::fork();
0361             if (pid == -1)
0362             {
0363 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0364                 ctx.notify_fork(net::execution_context::fork_parent);
0365 #endif
0366                 detail::on_fork_error(*this, executable, argv, ec, inits...);
0367                 detail::on_error(*this, executable, argv, ec, inits...);
0368 
0369                 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0370                 return basic_process<Executor>{exec};
0371             }
0372             else if (pid == 0)
0373             {
0374                 ::close(pg.p[0]);
0375 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0376                 ctx.notify_fork(net::execution_context::fork_child);
0377 #endif
0378                 ec = detail::on_exec_setup(*this, executable, argv, inits...);
0379                 if (!ec)
0380                 {
0381                     close_all_fds(ec);
0382                 }                
0383                 if (!ec)
0384                     ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
0385 
0386                 ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
0387                 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
0388                 detail::on_exec_error(*this, executable, argv, ec, inits...);
0389                 ::exit(EXIT_FAILURE);
0390                 return basic_process<Executor>{exec};
0391             }
0392 #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
0393             ctx.notify_fork(net::execution_context::fork_parent);
0394 #endif
0395             ::close(pg.p[1]);
0396             pg.p[1] = -1;
0397             int child_error{0};
0398             int count = -1;
0399             while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1)
0400             {
0401                 int err = errno;
0402                 if ((err != EAGAIN) && (err != EINTR))
0403                 {
0404                     BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category());
0405                     break;
0406                 }
0407             }
0408             if (count != 0)
0409                 BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category());
0410 
0411             if (ec)
0412             {
0413                 detail::on_error(*this, executable, argv, ec, inits...);
0414                 do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR);
0415                 return basic_process<Executor>{exec};
0416             }
0417         }
0418         basic_process<Executor> proc(exec, pid);
0419         detail::on_success(*this, executable, argv, ec, inits...);
0420         return proc;
0421 
0422     }
0423   protected:
0424 
0425     void ignore_unused(std::size_t ) {}
0426     void close_all_fds(error_code & ec)
0427     {
0428         std::sort(fd_whitelist.begin(), fd_whitelist.end());
0429         detail::close_all(fd_whitelist, ec);
0430         fd_whitelist = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
0431     }
0432 
0433     struct pipe_guard
0434     {
0435         int p[2];
0436         pipe_guard() : p{-1,-1} {}
0437 
0438         ~pipe_guard()
0439         {
0440             if (p[0] != -1)
0441                 ::close(p[0]);
0442             if (p[1] != -1)
0443                 ::close(p[1]);
0444         }
0445     };
0446 
0447     //if we need to allocate something
0448     std::vector<std::string> argv_buffer_;
0449     std::vector<const char *> argv_;
0450 
0451     template<typename Args>
0452     const char * const * build_argv_(const filesystem::path & pt, const Args & args,
0453                                      typename std::enable_if<
0454                                              std::is_convertible<
0455                                                      decltype(*std::begin(std::declval<Args>())),
0456                                                      cstring_ref>::value>::type * = nullptr)
0457     {
0458         const auto arg_cnt = std::distance(std::begin(args), std::end(args));
0459         argv_.reserve(arg_cnt + 2);
0460         argv_.push_back(pt.native().data());
0461         for (auto && arg : args)
0462             argv_.push_back(arg.c_str());
0463 
0464         argv_.push_back(nullptr);
0465         return argv_.data();
0466     }
0467 
0468     const char * const * build_argv_(const filesystem::path &, const char ** argv)
0469     {
0470         return argv;
0471     }
0472 
0473     template<typename Args>
0474     const char * const *  build_argv_(const filesystem::path & pt, const Args & args,
0475                                       typename std::enable_if<
0476                                               !std::is_convertible<
0477                                                       decltype(*std::begin(std::declval<Args>())),
0478                                                       cstring_ref>::value>::type * = nullptr)
0479     {
0480         const auto arg_cnt = std::distance(std::begin(args), std::end(args));
0481         argv_.reserve(arg_cnt + 2);
0482         argv_buffer_.reserve(arg_cnt);
0483         argv_.push_back(pt.native().data());
0484 
0485         using char_type = typename decay<decltype((*std::begin(std::declval<Args>()))[0])>::type;
0486 
0487         for (basic_string_view<char_type>  arg : args)
0488             argv_buffer_.push_back(v2::detail::conv_string<char>(arg.data(), arg.size()));
0489 
0490         for (auto && arg : argv_buffer_)
0491             argv_.push_back(arg.c_str());
0492 
0493         argv_.push_back(nullptr);
0494         return argv_.data();
0495     }
0496 };
0497 
0498 
0499 }
0500 
0501 BOOST_PROCESS_V2_END_NAMESPACE
0502 
0503 #endif //BOOST_PROCESS_V2_POSIX_DEFAULT_LAUNCHER