// This source code is released into the public domain. module; #include // execv() #include "nihil.hh" extern char **environ; // NOLINT export module nihil.posix:execv; import nihil.std; import nihil.util; import :argv; import :executor; import :fd; namespace nihil { // execv: use a filename and an argument vector to call ::execv(). export struct execv final { using tag = exec_tag; // Construct an execv from a filename. execv(std::filesystem::path path, argv &&args) noexcept : m_executable(std::move(path)) , m_args(std::move(args)) { } // Construct an execv from a file descriptor execv(fd &&executable, argv &&argv) noexcept : m_executable(std::move(executable)) , m_args(std::move(argv)) { } ~execv() = default; // Movable execv(execv &&) noexcept = default; auto operator=(execv &&) noexcept -> execv & = default; // Not copyable (because m_args isn't copyable). execv(execv const &) = delete; auto operator=(this execv &, execv const &) -> execv & = delete; // Perform the execv(). This only returns on failure. [[nodiscard]] auto exec(this execv &self) -> std::expected { auto guard = save_errno(); // clang-format off return self.m_executable | match { [&](std::filesystem::path const &path) { ::execv(path.string().c_str(), self.m_args.data()); return std::unexpected(error("execve failed", error(sys_error()))); }, [&](fd const &file) { #if NIHIL_HAVE_FEXECVE == 1 ::fexecve(file.get(), self.m_args.data(), environ); return std::unexpected(error("execve failed", error(sys_error()))); #else std::ignore = file; return std::unexpected(error(std::errc::function_not_supported)); #endif } }; // clang-format on } private: // The thing we will execute. std::variant m_executable; // Arguments to pass to the thing. argv m_args; }; } // namespace nihil