aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.posix/spawn.ccm
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.posix/spawn.ccm')
-rw-r--r--nihil.posix/spawn.ccm128
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