File indexing completed on 2025-01-18 09:50:11
0001
0002
0003
0004
0005 #ifndef BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP
0006 #define BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP
0007
0008 #include <boost/process/v2/posix/default_launcher.hpp>
0009
0010 #include <unistd.h>
0011 #include <sys/procdesc.h>
0012
0013 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0014
0015 namespace posix
0016 {
0017
0018
0019 struct pdfork_launcher : default_launcher
0020 {
0021
0022 int fd;
0023 pdfork_launcher() = default;
0024
0025 template<typename ExecutionContext, typename Args, typename ... Inits>
0026 auto operator()(ExecutionContext & context,
0027 const typename std::enable_if<is_convertible<
0028 ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
0029 filesystem::path >::type & executable,
0030 Args && args,
0031 Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
0032 {
0033 error_code ec;
0034 auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0035
0036 if (ec)
0037 v2::detail::throw_error(ec, "pdfork_launcher");
0038
0039 return proc;
0040 }
0041
0042
0043 template<typename ExecutionContext, typename Args, typename ... Inits>
0044 auto operator()(ExecutionContext & context,
0045 error_code & ec,
0046 const typename std::enable_if<is_convertible<
0047 ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
0048 filesystem::path >::type & executable,
0049 Args && args,
0050 Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
0051 {
0052 return (*this)(context.get_executor(), executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0053 }
0054
0055 template<typename Executor, typename Args, typename ... Inits>
0056 auto operator()(Executor exec,
0057 const typename std::enable_if<
0058 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
0059 BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
0060 filesystem::path >::type & executable,
0061 Args && args,
0062 Inits && ... inits ) -> basic_process<Executor>
0063 {
0064 error_code ec;
0065 auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
0066
0067 if (ec)
0068 v2::detail::throw_error(ec, "pdfork_launcher");
0069
0070 return proc;
0071 }
0072
0073 template<typename Executor, typename Args, typename ... Inits>
0074 auto operator()(Executor exec,
0075 error_code & ec,
0076 const typename std::enable_if<
0077 BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
0078 BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
0079 filesystem::path >::type & executable,
0080 Args && args,
0081 Inits && ... inits ) -> basic_process<Executor>
0082 {
0083 auto argv = this->build_argv_(executable, std::forward<Args>(args));
0084 {
0085 pipe_guard pg;
0086 if (::pipe(pg.p))
0087 {
0088 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
0089 return basic_process<Executor>{exec};
0090 }
0091 if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
0092 {
0093 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
0094 return basic_process<Executor>{exec};
0095 }
0096 ec = detail::on_setup(*this, executable, argv, inits ...);
0097 if (ec)
0098 {
0099 detail::on_error(*this, executable, argv, ec, inits...);
0100 return basic_process<Executor>(exec);
0101 }
0102 fd_whitelist.push_back(pg.p[1]);
0103
0104 auto & ctx = BOOST_PROCESS_V2_ASIO_NAMESPACE::query(
0105 exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context);
0106 ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_prepare);
0107 pid = ::pdfork(&fd, PD_DAEMON | PD_CLOEXEC);
0108 if (pid == -1)
0109 {
0110 ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);
0111 detail::on_fork_error(*this, executable, argv, ec, inits...);
0112 detail::on_error(*this, executable, argv, ec, inits...);
0113
0114 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
0115 return basic_process<Executor>{exec};
0116 }
0117 else if (pid == 0)
0118 {
0119 ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_child);
0120 ::close(pg.p[0]);
0121
0122 ec = detail::on_exec_setup(*this, executable, argv, inits...);
0123 if (!ec)
0124 {
0125 close_all_fds(ec);
0126 }
0127 if (!ec)
0128 ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
0129
0130 default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
0131 BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
0132 detail::on_exec_error(*this, executable, argv, ec, inits...);
0133 ::exit(EXIT_FAILURE);
0134 return basic_process<Executor>{exec};
0135 }
0136 ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);
0137 ::close(pg.p[1]);
0138 pg.p[1] = -1;
0139 int child_error{0};
0140 int count = -1;
0141 while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1)
0142 {
0143 int err = errno;
0144 if ((err != EAGAIN) && (err != EINTR))
0145 {
0146 BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
0147 break;
0148 }
0149 }
0150 if (count != 0)
0151 BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
0152
0153 if (ec)
0154 {
0155 detail::on_error(*this, executable, argv, ec, inits...);
0156 return basic_process<Executor>{exec};
0157 }
0158 }
0159 basic_process<Executor> proc(exec, pid, fd);
0160 detail::on_success(*this, executable, argv, ec, inits...);
0161 return proc;
0162 }
0163 };
0164
0165
0166 }
0167
0168 BOOST_PROCESS_V2_END_NAMESPACE
0169
0170
0171 #endif