// Copyright (c) 2022 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_V2_POSIX_PDFORK_LAUNCHER_HPP #define BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP #include #include #include BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace posix { /// A launcher using `pdfork`. Default on FreeBSD struct pdfork_launcher : default_launcher { /// The file descriptor of the subprocess. Set after fork. int fd; pdfork_launcher() = default; template auto operator()(ExecutionContext & context, const typename std::enable_if::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { error_code ec; auto proc = (*this)(context, ec, executable, std::forward(args), std::forward(inits)...); if (ec) asio::detail::throw_error(ec, "pdfork_launcher"); return proc; } template auto operator()(ExecutionContext & context, error_code & ec, const typename std::enable_if::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { return (*this)(context.get_executor(), executable, std::forward(args), std::forward(inits)...); } template auto operator()(Executor exec, const typename std::enable_if< BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor::value || BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { error_code ec; auto proc = (*this)(std::move(exec), ec, executable, std::forward(args), std::forward(inits)...); if (ec) asio::detail::throw_error(ec, "pdfork_launcher"); return proc; } template auto operator()(Executor exec, error_code & ec, const typename std::enable_if< BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor::value || BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor::value, filesystem::path >::type & executable, Args && args, Inits && ... inits ) -> basic_process { auto argv = this->build_argv_(executable, std::forward(args)); { pipe_guard pg; if (::pipe(pg.p)) { ec.assign(errno, system_category()); return basic_process{exec}; } if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC)) { ec.assign(errno, system_category()); return basic_process{exec}; } ec = detail::on_setup(*this, executable, argv, inits ...); if (ec) { detail::on_error(*this, executable, argv, ec, inits...); return basic_process(exec); } auto & ctx = BOOST_PROCESS_V2_ASIO_NAMESPACE::query( exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context); ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_prepare); pid = ::pdfork(&fd, PD_DAEMON | PD_CLOEXEC); if (pid == -1) { ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent); detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_error(*this, executable, argv, ec, inits...); ec.assign(errno, system_category()); return basic_process{exec}; } else if (pid == 0) { ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_child); ::close(pg.p[0]); ec = detail::on_exec_setup(*this, executable, argv, inits...); if (!ec) { fd_whitelist.push_back(pg.p[1]); close_all_fds(ec); } if (!ec) ::execve(executable.c_str(), const_cast(argv), const_cast(env)); default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int))); ec.assign(errno, system_category()); detail::on_exec_error(*this, executable, argv, ec, inits...); ::exit(EXIT_FAILURE); return basic_process{exec}; } ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent); ::close(pg.p[1]); pg.p[1] = -1; int child_error{0}; int count = -1; while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1) { int err = errno; if ((err != EAGAIN) && (err != EINTR)) { ec.assign(err, system_category()); break; } } if (count != 0) ec.assign(child_error, system_category()); if (ec) { detail::on_error(*this, executable, argv, ec, inits...); return basic_process{exec}; } } basic_process proc(exec, pid, fd); detail::on_success(*this, executable, argv, ec, inits...); return proc; } }; } BOOST_PROCESS_V2_END_NAMESPACE #endif //BOOST_PROCESS_V2_POSIX_PDFORK_LAUNCHER_HPP