FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
pipe.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include <cstring>
12#include <istream>
13#include <thread>
14#include <functional>
15#include <optional>
16#include <vector>
17#include <sys/wait.h>
18#include <sys/prctl.h>
19#include <csignal>
20#include <string>
21#include <unistd.h>
22#include <sys/types.h>
23#include <filesystem>
24
25#include "../../macro.hpp"
26#include "../../lib/log.hpp"
28
29namespace ns_subprocess
30{
31
40namespace ns_pipe
41{
42
53inline void write_pipe(pid_t child_pid, int pipe_fd, std::istream& stream)
54{
55 ns_linux::ns_fd::redirect_stream_to_fd(child_pid, stream, pipe_fd).discard();
56 close(pipe_fd);
57}
58
72inline void read_pipe(pid_t child_pid, int pipe_fd, std::ostream& stream, std::filesystem::path const& path_file_log)
73{
74 ns_log::set_sink_file(path_file_log);
75
77 , pipe_fd
78 , stream
79 , [](std::string const& s) { logger("D::STD(OUT|ERR)::{}", s); return s; }
80 ).discard();
81 close(pipe_fd);
82}
83
91template<typename Stream>
93{
94 if constexpr (std::is_same_v<Stream, std::istream>)
95 {
96 return (&stream == &std::cin);
97 }
98 else if constexpr (std::is_same_v<Stream, std::ostream>)
99 {
100 return (&stream == &std::cout) or (&stream == &std::cerr);
101 }
102 return false;
103}
104
114template<typename Stream>
115void pipes_child(bool is_istream, int pipe[2], Stream& stream, int fileno)
116{
117 // For input streams (stdin): child uses read end [0], parent uses write end [1]
118 // For output streams (stdout/stderr): child uses write end [1], parent uses read end [0]
119 int idx_child = is_istream ? 0 : 1;
120 int idx_parent = is_istream ? 1 : 0;
121
122 // Close the parent's end
123 return_if(close(pipe[idx_parent]) == -1,, "E::pipe[{}]: {}}", idx_parent, strerror(errno));
124
125 // If using standard stream, don't redirect (allow terminal access)
127 {
128 close(pipe[idx_child]);
129 return;
130 }
131
132 // Redirect to the specified file descriptor
133 return_if(dup2(pipe[idx_child], fileno) == -1,, "E::dup2(pipe[{}], {}): {}", idx_child, fileno, strerror(errno));
134 return_if(close(pipe[idx_child]) == -1,, "E::pipe[{}]: {}", idx_child, strerror(errno));
135}
136
148template<typename Stream>
149std::optional<std::jthread> pipes_parent(
150 pid_t child_pid,
151 bool is_istream,
152 int pipe[2],
153 Stream& stream,
154 std::filesystem::path const& path_file_log)
155{
156 // For input streams (stdin): parent uses write end [1], child uses read end [0]
157 // For output streams (stdout/stderr): parent uses read end [0], child uses write end [1]
158 int idx_parent = is_istream ? 1 : 0;
159 int idx_child = is_istream ? 0 : 1;
160
161 // Close the child's end
162 return_if(close(pipe[idx_child]) == -1, std::nullopt,"E::pipe[{}]: {}", idx_child, strerror(errno));
163
164 // If using standard stream, close parent end and return (no thread needed)
166 {
167 close(pipe[idx_parent]);
168 return std::nullopt;
169 }
170
171 // Create appropriate thread (use if constexpr to avoid compiling invalid branch)
172 if constexpr (std::is_same_v<Stream, std::istream>)
173 {
174 // Input stream: read from Stream and write to child's stdin pipe
175 return std::jthread(write_pipe, child_pid, pipe[idx_parent], std::ref(stream));
176 }
177 else // std::ostream
178 {
179 // Output stream: read from child's stdout/stderr pipe and write to Stream
180 return std::jthread(read_pipe, child_pid, pipe[idx_parent], std::ref(stream), path_file_log);
181 }
182}
183
204inline std::vector<std::jthread> setup(
205 pid_t pid,
206 int pipestdin[2],
207 int pipestdout[2],
208 int pipestderr[2],
209 std::istream& stdin,
210 std::ostream& stdout,
211 std::ostream& stderr,
212 std::filesystem::path const& path_file_log)
213{
214 std::vector<std::jthread> threads;
215
216 // Parent: setup writer/reader threads (or skip if std::cin/cout/cerr)
217 if (pid > 0)
218 {
219 if (auto t = pipes_parent(pid, true, pipestdin, stdin, path_file_log))
220 {
221 threads.push_back(std::move(*t));
222 }
223 if (auto t = pipes_parent(pid, false, pipestdout, stdout, path_file_log))
224 {
225 threads.push_back(std::move(*t));
226 }
227 if (auto t = pipes_parent(pid, false, pipestderr, stderr, path_file_log))
228 {
229 threads.push_back(std::move(*t));
230 }
231 }
232 // Child: redirect stdin/stdout/stderr (or skip if std::cin/cout/cerr)
233 else if (pid == 0)
234 {
235 pipes_child(true, pipestdin, stdin, STDIN_FILENO);
236 pipes_child(false, pipestdout, stdout, STDOUT_FILENO);
237 pipes_child(false, pipestderr, stderr, STDERR_FILENO);
238 }
239 else
240 {
241 logger("E::Invalid negative pid for pipe setup");
242 }
243
244 return threads;
245}
246
247} // namespace ns_pipe
248
249} // namespace ns_subprocess
250
251/* vim: set expandtab fdm=marker ts=2 sw=2 tw=100 et :*/
File descriptor redirection helpers.
Value< void > redirect_fd_to_stream(pid_t ppid, int fd_src, std::ostream &stream_dst, std::function< std::string(std::string const &)> transform=[](std::string e) -> std::string { return e;})
Redirects the output of a file descriptor to a stream.
Definition fd.hpp:151
Value< void > redirect_stream_to_fd(pid_t ppid, std::istream &stream_src, int fd_dst)
Redirects the output of a stream to a file descriptor.
Definition fd.hpp:205
A library for file logging.
#define logger(fmt,...)
Compile-time log level dispatch macro with automatic location capture.
Definition log.hpp:682
Simplified macros for common control flow patterns with optional logging.
void set_sink_file(fs::path const &path_file_sink)
Sets the sink file of the logger.
Definition log.hpp:359
Inter-process pipe management.
void read_pipe(pid_t child_pid, int pipe_fd, std::ostream &stream, std::filesystem::path const &path_file_log)
Read from a pipe file descriptor and write to an output stream.
Definition pipe.hpp:72
void pipes_child(bool is_istream, int pipe[2], Stream &stream, int fileno)
Setup pipe for child process (unified for stdin/stdout/stderr)
Definition pipe.hpp:115
void write_pipe(pid_t child_pid, int pipe_fd, std::istream &stream)
Write from an input stream to a pipe file descriptor.
Definition pipe.hpp:53
std::optional< std::jthread > pipes_parent(pid_t child_pid, bool is_istream, int pipe[2], Stream &stream, std::filesystem::path const &path_file_log)
Setup pipe for parent process (unified for stdin/stdout/stderr)
Definition pipe.hpp:149
std::vector< std::jthread > setup(pid_t pid, int pipestdin[2], int pipestdout[2], int pipestderr[2], std::istream &stdin, std::ostream &stdout, std::ostream &stderr, std::filesystem::path const &path_file_log)
Handle pipe setup for both parent and child processes.
Definition pipe.hpp:204
bool is_standard_stream(Stream &stream)
Check if a stream is a standard stream (std::cin, std::cout, or std::cerr)
Definition pipe.hpp:92
Custom stream redirection for child process stdio.
Child process management and execution.
Stream
Stream redirection modes for child process stdio.