diff options
| author | Lexi Winter <lexi@le-fay.org> | 2025-07-01 17:07:04 +0100 |
|---|---|---|
| committer | Lexi Winter <lexi@le-fay.org> | 2025-07-01 17:07:04 +0100 |
| commit | 2e2d1bd3b6c7776b77c33b94f30ead89367a71e6 (patch) | |
| tree | 54d37ffadf8e677938d9b7a28e4e9b71be1e75c1 /nihil.posix/spawn.ccm | |
| parent | 36427c0966faa7aecd586b397ed9b845f18172f5 (diff) | |
| download | nihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.gz nihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.bz2 | |
add nihil.std
Diffstat (limited to 'nihil.posix/spawn.ccm')
| -rw-r--r-- | nihil.posix/spawn.ccm | 128 |
1 files changed, 46 insertions, 82 deletions
diff --git a/nihil.posix/spawn.ccm b/nihil.posix/spawn.ccm index a185bb3..1e4102a 100644 --- a/nihil.posix/spawn.ccm +++ b/nihil.posix/spawn.ccm @@ -1,52 +1,27 @@ // This source code is released into the public domain. -module; - -/* - * spawn(): fork and execute a child process. - */ - -#include <algorithm> -#include <cerrno> -#include <coroutine> -#include <expected> -#include <filesystem> -#include <format> -#include <iterator> -#include <print> -#include <string> -#include <utility> - -#include <sys/types.h> -#include <sys/wait.h> - -#include <fcntl.h> -#include <unistd.h> - export module nihil.posix:spawn; +// spawn(): fork and execute a child process. + import nihil.monad; import :argv; import :executor; +import :fd; import :open; import :process; +import :unistd; namespace nihil { -// Useful constants -export inline int constexpr stdin_fileno = STDIN_FILENO; -export inline int constexpr stdout_fileno = STDOUT_FILENO; -export inline int constexpr stderr_fileno = STDERR_FILENO; - -/* - * fd_{read,write}_pipe: create a pipe with one end in the child and the other in the parent. - * The child's side will be dup2()'d to the provided fd number. - * The parent side fd can be retrieved via parent_fd(). - * - * fd_read_pipe() puts the reading side in the child, while fd_write_pipe() puts the writing - * side in the child. - */ +// fd_{read,write}_pipe: create a pipe with one end in the child and the other in the parent. +// The child's side will be dup2()'d to the provided fd number. +// The parent side fd can be retrieved via parent_fd(). +// +// fd_read_pipe() puts the reading side in the child, while fd_write_pipe() puts the writing +// side in the child. -struct fd_pipe_base { +struct fd_pipe_base +{ fd_pipe_base(int fdno, fd &&child_fd, fd &&parent_fd) : m_fdno(fdno) , m_child_fd(std::move(child_fd)) @@ -58,8 +33,8 @@ struct fd_pipe_base { { auto err = raw_dup(self.m_child_fd, self.m_fdno); if (!err) { - std::print("dup: {}\n", err.error()); - _exit(1); + std::println("dup: {}", err.error()); + std::quick_exit(1); } /* @@ -81,35 +56,34 @@ struct fd_pipe_base { } private: - int m_fdno; - fd m_child_fd; - fd m_parent_fd; - + int m_fdno; + fd m_child_fd; + fd m_parent_fd; }; -export struct fd_read_pipe final : fd_pipe_base { +export struct fd_read_pipe final : fd_pipe_base +{ fd_read_pipe(int fdno, fd &&read_fd, fd &&write_fd) : fd_pipe_base(fdno, std::move(read_fd), std::move(write_fd)) { } }; -export struct fd_write_pipe final : fd_pipe_base { +export struct fd_write_pipe final : fd_pipe_base +{ fd_write_pipe(int fdno, fd &&read_fd, fd &&write_fd) : fd_pipe_base(fdno, std::move(write_fd), std::move(read_fd)) { } }; -export [[nodiscard]] auto -make_fd_read_pipe(int fdno) -> std::expected<fd_read_pipe, error> +export [[nodiscard]] auto make_fd_read_pipe(int fdno) -> std::expected<fd_read_pipe, error> { auto fds = co_await pipe(); co_return fd_read_pipe(fdno, std::move(fds.first), std::move(fds.second)); } -export [[nodiscard]] auto -make_fd_write_pipe(int fdno) -> std::expected<fd_write_pipe, error> +export [[nodiscard]] auto make_fd_write_pipe(int fdno) -> std::expected<fd_write_pipe, error> { auto fds = co_await pipe(); co_return fd_write_pipe(fdno, std::move(fds.first), std::move(fds.second)); @@ -119,7 +93,8 @@ make_fd_write_pipe(int fdno) -> std::expected<fd_write_pipe, error> * fd_file: open a file and provide it to the child as a file descriptor. * open_flags and open_mode are as for ::open(). */ -export struct fd_file final { +export struct fd_file final +{ fd_file(int fdno, fd &&file_fd) : m_fdno(fdno) , m_file_fd(std::move(file_fd)) @@ -136,20 +111,19 @@ export struct fd_file final { auto err = raw_dup(self.m_file_fd, self.m_fdno); if (!err) { std::print("dup: {}\n", err.error()); - _exit(1); + std::quick_exit(1); } std::ignore = self.m_file_fd.close(); } private: - int m_fdno; - fd m_file_fd; + int m_fdno; + fd m_file_fd; }; export [[nodiscard]] auto -make_fd_file(int fdno, std::filesystem::path const &file, - open_flags flags, int mode = 0777) +make_fd_file(int fdno, std::filesystem::path const &file, open_flags flags, int mode = 0777) -> std::expected<fd_file, error> { auto fd = co_await open(file, flags, mode); @@ -160,20 +134,17 @@ make_fd_file(int fdno, std::filesystem::path const &file, * Shorthand for fd_file with /dev/null as the file. */ -export [[nodiscard]] inline auto -stdin_devnull() -> std::expected<fd_file, error> +export [[nodiscard]] inline auto stdin_devnull() -> std::expected<fd_file, error> { return make_fd_file(stdin_fileno, "/dev/null", open_read); } -export [[nodiscard]] inline auto -stdout_devnull() -> std::expected<fd_file, error> +export [[nodiscard]] inline auto stdout_devnull() -> std::expected<fd_file, error> { return make_fd_file(stdout_fileno, "/dev/null", open_write); } -export [[nodiscard]] inline auto -stderr_devnull() -> std::expected<fd_file, error> +export [[nodiscard]] inline auto stderr_devnull() -> std::expected<fd_file, error> { return make_fd_file(stderr_fileno, "/dev/null", open_write); } @@ -182,8 +153,9 @@ stderr_devnull() -> std::expected<fd_file, error> * Capture the output of a pipe in the parent and read it into an * output iterator. */ -export template<std::output_iterator<char> Iterator> -struct fd_capture final { +export template <std::output_iterator<char> Iterator> +struct fd_capture final +{ fd_capture(fd_write_pipe &&pipe, Iterator it) : m_pipe(std::move(pipe)) , m_iterator(std::move(it)) @@ -204,7 +176,7 @@ struct fd_capture final { auto &fd = self.m_pipe.parent_fd(); for (;;) { auto ret = read(fd, buffer); - if (!ret || ret->size() == 0) + if (!ret || ret->empty()) break; std::ranges::copy(*ret, self.m_iterator); @@ -215,21 +187,18 @@ struct fd_capture final { } private: - fd_write_pipe m_pipe; - Iterator m_iterator; + fd_write_pipe m_pipe; + Iterator m_iterator; }; -export [[nodiscard]] auto -make_capture(int fdno, std::output_iterator<char> auto &&it) +export [[nodiscard]] auto make_capture(int fdno, std::output_iterator<char> auto &&it) -> std::expected<fd_capture<decltype(it)>, error> { auto pipe = co_await make_fd_write_pipe(fdno); - co_return fd_capture(std::move(pipe), - std::forward<decltype(it)>(it)); + co_return fd_capture(std::move(pipe), std::forward<decltype(it)>(it)); } -export [[nodiscard]] auto -make_capture(int fdno, std::string &str) +export [[nodiscard]] auto make_capture(int fdno, std::string &str) -> std::expected<fd_capture<decltype(std::back_inserter(str))>, error> { auto pipe = co_await make_fd_write_pipe(fdno); @@ -241,14 +210,9 @@ make_capture(int fdno, std::string &str) * Throws exec_error() on failure. */ export [[nodiscard]] auto -spawn(executor auto &&executor, auto &&...actions) - -> std::expected<process, error> +spawn(executor auto &&executor, auto &&...actions) -> std::expected<process, error> { - auto const pid = ::fork(); - if (pid == -1) - return std::unexpected(error("fork failed", - error(std::errc(errno)))); - + auto const pid = co_await fork(); auto proc = process(pid); if (pid == 0) { @@ -257,13 +221,13 @@ spawn(executor auto &&executor, auto &&...actions) std::ignore = std::move(proc).release(); auto err = executor.exec(); - std::print("{}\n", err.error()); - _exit(1); + std::println("{}", err.error()); + std::quick_exit(1); } (actions.run_in_parent(proc), ...); - return proc; + co_return proc; } } // namespace nihil |
