FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
ns_subprocess::Subprocess Class Reference

Public Member Functions

template<ns_concept::StringRepresentable T>
 Subprocess (T &&t)
 Construct a new Subprocess object with a program path.
 
 ~Subprocess ()
 Destroy the Subprocess object.
 
 Subprocess (Subprocess const &)=delete
 
Subprocessoperator= (Subprocess const &)=delete
 
 Subprocess (Subprocess &&)=delete
 
Subprocessoperator= (Subprocess &&)=delete
 
Subprocessenv_clear ()
 Clears all environment variables before starting the process.
 
template<ns_concept::StringRepresentable K, ns_concept::StringRepresentable V>
Subprocesswith_var (K &&k, V &&v)
 Adds or replaces a single environment variable.
 
template<ns_concept::StringRepresentable K>
Subprocessrm_var (K &&k)
 Removes an environment variable from the process environment.
 
template<typename... Args>
Subprocesswith_args (Args &&... args)
 Arguments forwarded as the process' arguments.
 
template<typename... Args>
Subprocesswith_env (Args &&... args)
 Includes environment variables with the format 'NAME=VALUE' in the environment.
 
Subprocesswith_die_on_pid (pid_t pid)
 Configures the child process to die when the specified PID dies.
 
Subprocesswith_stdio (Stream mode)
 Sets the stdio redirection mode for the child process.
 
Subprocesswith_log_file (std::filesystem::path const &path)
 Configures logging output for child process stdout/stderr.
 
Subprocesswith_log_level (ns_log::Level const &level)
 Sets the logging level for the pipe reader processes.
 
Subprocesswith_streams (std::istream &stdin_stream, std::ostream &stdout_stream, std::ostream &stderr_stream)
 Configures stream handlers for stdin, stdout, and stderr of the child process.
 
template<typename F>
Subprocesswith_callback_child (F &&f)
 Sets a callback to run in the child process after fork() but before execve()
 
template<typename F>
Subprocesswith_callback_parent (F &&f)
 Sets a callback to run in the parent process after fork()
 
Subprocesswith_daemon ()
 Enable daemon mode using double fork pattern.
 
std::unique_ptr< Childspawn ()
 Spawns (forks) the child process and begins execution.
 

Detailed Description

Definition at line 108 of file subprocess.hpp.

Constructor & Destructor Documentation

◆ Subprocess()

ns_subprocess::Subprocess::Subprocess ( T && t)
nodiscard

Construct a new Subprocess object with a program path.

Creates a subprocess object configured to run the specified program. The environment is inherited from the parent process by default.

Template Parameters
TType that is string representable
Parameters
tThe program path or name to execute
// Using string literal
Subprocess proc1("/bin/ls");
// Using std::string
std::string program = "/usr/bin/gcc";
Subprocess proc2(program);
// Using filesystem::path
std::filesystem::path exe = "/usr/bin/python3";
Subprocess proc3(exe);
Subprocess(T &&t)
Construct a new Subprocess object with a program path.

Definition at line 204 of file subprocess.hpp.

Here is the caller graph for this function:

◆ ~Subprocess()

ns_subprocess::Subprocess::~Subprocess ( )
inline

Destroy the Subprocess object.

Note: After spawn() is called, the Child handle takes ownership of the child process. The Subprocess destructor does not wait for the child since that responsibility has been transferred to Child.

{
Subprocess proc("/bin/sleep");
auto spawned = proc.with_args("5").spawn();
// Child destructor will wait
} // spawned's destructor waits here, not proc's

Definition at line 243 of file subprocess.hpp.

Member Function Documentation

◆ env_clear()

Subprocess & ns_subprocess::Subprocess::env_clear ( )
inlinenodiscard

Clears all environment variables before starting the process.

Removes all inherited environment variables, creating a clean slate. Useful for when you need precise control over the environment.

Returns
Subprocess& A reference to *this for method chaining
// Start process with only specific environment variables
Subprocess proc("/usr/bin/env");
proc.env_clear() // Remove all inherited vars
.with_env("PATH=/usr/bin") // Add only what we need
.with_env("HOME=/tmp")
.spawn();
// Secure execution with minimal environment
Subprocess secure("/bin/untrusted_app");
secure.env_clear()
.with_env("SAFE_VAR=value")
.spawn();

Definition at line 270 of file subprocess.hpp.

Here is the call graph for this function:

◆ rm_var()

Subprocess & ns_subprocess::Subprocess::rm_var ( K && k)
nodiscard

Removes an environment variable from the process environment.

Deletes the specified environment variable if it exists. If the variable doesn't exist, this is a no-op (safe to call multiple times).

Template Parameters
KType that is string representable
Parameters
kThe name of the variable to remove
Returns
Subprocess& A reference to *this for method chaining
// Remove potentially dangerous environment variables
Subprocess proc("/bin/app");
proc.rm_var("LD_PRELOAD")
.rm_var("LD_LIBRARY_PATH")
.rm_var("DYLD_INSERT_LIBRARIES")
.spawn();
// Remove inherited variable before setting custom value
proc.rm_var("PATH")
.with_var("PATH", "/usr/local/bin:/usr/bin");
// Safe to remove non-existent variables
proc.rm_var("DOES_NOT_EXIST"); // No error

Definition at line 342 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ spawn()

std::unique_ptr< Child > ns_subprocess::Subprocess::spawn ( )
inlinenodiscard

Spawns (forks) the child process and begins execution.

Creates a child process via fork() and executes the configured program. When daemon mode is enabled via with_daemon(), performs a double fork pattern to fully detach the process from the terminal and parent.

The parent process returns a Child handle immediately while the child runs asynchronously. Call wait() on the returned handle to synchronize and retrieve the exit code.

Use with_log_file() before spawn() to capture child's stdout/stderr to log files.

Returns
std::unique_ptr<Child> Unique pointer to the spawned process with wait() methods
// Basic spawn and wait
auto result = Subprocess("/bin/ls")
.with_args("-la")
.spawn()
->wait();
// Spawn with stdout/stderr capture to files
auto proc = Subprocess("/bin/app")
.with_log_file("/tmp/child.log")
.spawn();
// Background process (destructor waits automatically)
{
auto daemon = Subprocess("/usr/bin/daemon")
.with_stdio(Stream::Null)
.spawn();
// daemon runs, destructor waits when going out of scope
}
// Multiple subprocesses in parallel
auto worker1 = Subprocess("/bin/worker").with_args("task1").spawn();
auto worker2 = Subprocess("/bin/worker").with_args("task2").spawn();
// Both run in parallel
worker1->wait();
worker2->wait();
// Spawn with output capture
std::ostringstream output;
auto result = Subprocess("/bin/ps")
.with_stdio(Stream::Pipe)
.with_streams(std::cin, output, std::cerr)
.with_args("aux")
.spawn()
->wait();

Definition at line 948 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_args()

template<typename... Args>
Subprocess & ns_subprocess::Subprocess::with_args ( Args &&... args)
nodiscard

Arguments forwarded as the process' arguments.

Accepts any number of arguments (including zero). Each argument can be:

  • A single string/string-like value (added as one argument)
  • An iterable container (each element added as separate argument)
Template Parameters
ArgsTypes of arguments (variadic, can be string, iterable, or string representable)
Parameters
argsArguments to forward to the process
Returns
Subprocess& A reference to *this
// Single argument
.with_args("--verbose")
// Multiple arguments
.with_args("--input", "file.txt", "--output", "out.txt")
// Container of arguments
std::vector<std::string> opts = {"--flag1", "--flag2"};
.with_args(opts)
// Mixed
.with_args("gcc", opts, "-o", "output")

Definition at line 389 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_callback_child()

template<typename F>
Subprocess & ns_subprocess::Subprocess::with_callback_child ( F && f)
nodiscard

Sets a callback to run in the child process after fork() but before execve()

The callback runs in the child process context, allowing you to for example:

  • Manipulate file descriptors beyond stdin/stdout/stderr
  • Change working directory

IMPORTANT: The callback runs AFTER stdio redirection and die_on_pid setup, but BEFORE execve(). Any errors should use _exit() not exit() to avoid flushing parent's buffers.

Template Parameters
FFunction type compatible with std::function<void(ArgsCallbackChild)>
Parameters
fCallback function that receives ArgsCallbackChild
Returns
Subprocess& A reference to *this for method chaining
// Close extra file descriptors
Subprocess proc("/usr/bin/app");
proc.with_callback_child([](ArgsCallbackChild args) {
// Close all FDs except 0, 1, 2
for (int fd = 3; fd < 1024; fd++) {
close(fd);
}
}).spawn();
// Change working directory
proc.with_callback_child([](ArgsCallbackChild args) {
if (chdir("/tmp") < 0) {
_exit(1); // Use _exit, not exit
}
}).spawn();
// Duplicate FD for inheritance
int special_fd = open("/path/to/file", O_RDONLY);
proc.with_callback_child([special_fd](ArgsCallbackChild args) {
dup2(special_fd, 10); // Child will have file at FD 10
close(special_fd);
// Can also access args.parent_pid, args.stdin_fd, etc.
}).spawn();
std::unique_ptr< Child > spawn()
Spawns (forks) the child process and begins execution.
Arguments passed to child callback.

Definition at line 812 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_callback_parent()

template<typename F>
Subprocess & ns_subprocess::Subprocess::with_callback_parent ( F && f)
inlinenodiscard

Sets a callback to run in the parent process after fork()

The callback runs in the parent process context after the child has been forked, allowing you to:

  • Record the child PID for monitoring
  • Close file descriptors that only the child needs
  • Set up additional IPC mechanisms
  • Perform cleanup or wait operations in the parent

The callback receives ArgsCallbackParent containing the child's PID.

IMPORTANT: The callback runs AFTER the child has been forked and BEFORE the Child handle is returned. Any exceptions or errors will prevent the Child handle from being created.

Template Parameters
FFunction type compatible with std::function<void(ArgsCallbackParent)>
Parameters
fCallback function that receives ArgsCallbackParent
Returns
Subprocess& A reference to *this for method chaining
// Record child PID
pid_t child_pid;
Subprocess proc("/usr/bin/app");
proc.with_callback_parent([&child_pid](ArgsCallbackParent args) {
child_pid = args.child_pid;
std::cout << "Spawned child: " << args.child_pid << "\n";
}).spawn();
// Close inherited FD in parent (child keeps it)
int shared_fd = open("/path/to/file", O_RDONLY);
proc.with_callback_parent([shared_fd](ArgsCallbackParent args) {
close(shared_fd); // Parent doesn't need it anymore
}).spawn();
// Set up process monitoring
proc.with_callback_parent([](ArgsCallbackParent args) {
register_process_monitor(args.child_pid);
}).spawn();
Arguments passed to parent callback.

Definition at line 860 of file subprocess.hpp.

Here is the call graph for this function:

◆ with_daemon()

Subprocess & ns_subprocess::Subprocess::with_daemon ( )
inlinenodiscard

Enable daemon mode using double fork pattern.

When enabled, the spawn() method will perform a double fork:

  1. First fork creates intermediate child
  2. Intermediate child forks to create grandchild (daemon)
  3. Intermediate child exits immediately
  4. Parent waits for intermediate child
  5. Grandchild becomes orphaned, adopted by init
  6. Grandchild calls setsid() to become session leader
  7. Grandchild continues with execve

This detaches the process from the terminal and parent process.

Returns
Reference to this Subprocess for method chaining
Subprocess proc("/usr/bin/my-daemon");
auto child = proc.with_args("--config", "/etc/config")
.with_daemon()
.spawn();
// Process is now daemonized and detached

Definition at line 890 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_die_on_pid()

Subprocess & ns_subprocess::Subprocess::with_die_on_pid ( pid_t pid)
inlinenodiscard

Configures the child process to die when the specified PID dies.

Uses prctl(PR_SET_PDEATHSIG) to ensure the child process receives SIGKILL when the parent process with the given PID terminates. This prevents orphaned processes and ensures cleanup even if the parent crashes.

Parameters
pidThe PID that the child should monitor (typically parent's PID)
Returns
Subprocess& A reference to *this for method chaining
// Child dies when current process dies
pid_t my_pid = getpid();
Subprocess daemon("/usr/bin/daemon");
daemon.with_die_on_pid(my_pid)
.spawn();
// If this process exits/crashes, daemon is automatically killed

Definition at line 512 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_env()

template<typename... Args>
Subprocess & ns_subprocess::Subprocess::with_env ( Args &&... args)
nodiscard

Includes environment variables with the format 'NAME=VALUE' in the environment.

Accepts any number of environment variable entries (including zero). Each entry can be:

  • A single "KEY=VALUE" string (replaces existing KEY if present)
  • An iterable container of "KEY=VALUE" strings (each element processed)

Automatically removes duplicate keys - if the same KEY appears multiple times, only the last value is kept.

Template Parameters
ArgsTypes of arguments (variadic, can be string, iterable, or string representable)
Parameters
argsEnvironment variables to include (format: "KEY=VALUE")
Returns
Subprocess& A reference to *this
// Single variable
.with_env("PATH=/usr/bin")
// Multiple variables
.with_env("HOME=/home/user", "LANG=en_US.UTF-8", "EDITOR=vim")
// Container of variables
std::vector<std::string> env_vars = {"VAR1=value1", "VAR2=value2"};
.with_env(env_vars)
// Mixed
.with_env("PATH=/usr/bin", env_vars, "DEBUG=1")

Definition at line 448 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_log_file()

Subprocess & ns_subprocess::Subprocess::with_log_file ( std::filesystem::path const & path)
inlinenodiscard

Configures logging output for child process stdout/stderr.

Automatically sets up pipe redirection (Stream::Pipe mode) and configures the log sink for the pipe reader threads. All child process output (stdout and stderr) is captured and logged to the specified file.

The child's stdout/stderr are redirected to pipes, and those pipes are read by detached threads that write directly to log files. This works even if the child process calls execve(), as the pipe readers remain in the parent.

The log file path is used directly by ns_log::set_sink_file() in the pipe reader threads.

If stdout/stderr stream handlers are registered via with_streams(), they will receive the child's output in addition to the log file.

Parameters
pathPath for log file (e.g., "/tmp/app.log")
Returns
Subprocess& A reference to *this for method chaining
// Capture child's stdout/stderr to log file
Subprocess("/usr/bin/app")
.with_log_file("/tmp/app.log")
.spawn();

Definition at line 584 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_log_level()

Subprocess & ns_subprocess::Subprocess::with_log_level ( ns_log::Level const & level)
inlinenodiscard

Sets the logging level for the pipe reader processes.

Configures the verbosity level for the pipe reader processes that capture the child's stdout/stderr. The log level determines which messages are written to the log files:

  • Level::CRITICAL: Only critical messages (always shown)
  • Level::ERROR: Critical and error messages
  • Level::WARN: Critical, error, and warning messages
  • Level::INFO: Critical, error, warning, and info messages
  • Level::DEBUG: All messages including debug (most verbose)

This is applied in the forked pipe reader processes (not the main child process), so it affects logging from the subprocess library's pipe handling mechanism.

Parameters
levelThe logging level to set (ns_log::Level enum)
Returns
Subprocess& A reference to *this for method chaining
// Enable debug logging for pipe readers
Subprocess proc("/usr/bin/app");
proc.with_log_level(ns_log::Level::DEBUG)
.with_log_file("/tmp/app.log")
.spawn();
// Minimal logging (only critical messages)
Subprocess quiet("/usr/bin/background_task");
quiet.with_log_level(ns_log::Level::CRITICAL)
.with_stdio(Stream::Null)
.spawn();
// Standard info level logging
Subprocess normal("/usr/bin/service");
normal.with_log_level(ns_log::Level::INFO)
.spawn();

Definition at line 628 of file subprocess.hpp.

Here is the call graph for this function:

◆ with_stdio()

Subprocess & ns_subprocess::Subprocess::with_stdio ( Stream mode)
inlinenodiscard

Sets the stdio redirection mode for the child process.

Controls how the child's stdin, stdout, and stderr are handled:

  • Stream::Inherit: Child inherits parent's stdio (default)
  • Stream::Pipe: Redirect to pipes with stream handlers (use with_streams())
  • Stream::Null: Redirect to /dev/null (silent execution)
Parameters
modeStream redirection mode
Returns
Subprocess& A reference to *this for method chaining
// Silent execution (no output)
Subprocess quiet("/usr/bin/noisy_app");
quiet.with_stdio(Stream::Null)
.spawn();
// Capture output with pipes
std::ostringstream output;
Subprocess capture("/bin/ls");
capture.with_stdio(Stream::Pipe)
.with_streams(std::cin, output, std::cerr)
.with_args("-la")
.spawn()
.wait();
// Inherit (show on parent's terminal)
Subprocess interactive("/usr/bin/vim");
interactive.with_stdio(Stream::Inherit)
.spawn();

Definition at line 550 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ with_streams()

Subprocess & ns_subprocess::Subprocess::with_streams ( std::istream & stdin_stream,
std::ostream & stdout_stream,
std::ostream & stderr_stream )
inlinenodiscard

Configures stream handlers for stdin, stdout, and stderr of the child process.

Sets up the stream redirection for all three standard I/O streams at once. The streams are used when Stream::Pipe mode is active via with_stdio(Stream::Pipe).

  • stdin_stream: Input stream to read from and write to child's stdin
  • stdout_stream: Output stream to write child's stdout to
  • stderr_stream: Output stream to write child's stderr to
Parameters
stdin_streamInput stream for the child process's stdin
stdout_streamOutput stream for the child process's stdout
stderr_streamOutput stream for the child process's stderr
Returns
Subprocess& A reference to *this for method chaining
// Redirect all streams to custom handlers
std::istringstream input("echo hello");
std::ostringstream output;
std::ostringstream errors;
Subprocess proc("/bin/bash");
proc.with_stdio(Stream::Pipe)
.with_streams(input, output, errors)
.spawn()
.wait();
// Use with std::cout and std::cerr
Subprocess build("/usr/bin/make");
build.with_stdio(Stream::Pipe)
.with_streams(std::cin, std::cout, std::cerr)
.spawn();
// Capture output to files via fstream
std::ifstream stdin_file("/dev/null");
std::ofstream stdout_file("/tmp/output.log");
std::ofstream stderr_file("/tmp/errors.log");
Subprocess cmd("/bin/app");
cmd.with_stdio(Stream::Pipe)
.with_streams(stdin_file, stdout_file, stderr_file)
.spawn();

Definition at line 762 of file subprocess.hpp.

Here is the call graph for this function:

◆ with_var()

Subprocess & ns_subprocess::Subprocess::with_var ( K && k,
V && v )
nodiscard

Adds or replaces a single environment variable.

Sets an environment variable by key-value pair. If the key already exists, it is replaced with the new value. More convenient than with_env() when you have separate key and value.

Template Parameters
KType that is string representable for the key
VType that is string representable for the value
Parameters
kThe name of the environment variable
vThe value of the environment variable
Returns
Subprocess& A reference to *this for method chaining
// Add environment variables by key-value pairs
Subprocess proc("/usr/bin/python3");
proc.with_var("PYTHONPATH", "/usr/lib/python")
.with_var("DEBUG", "1")
.with_var("HOME", "/home/user")
.spawn();
// Replace existing variable
proc.with_var("PATH", "/usr/bin"); // First value
proc.with_var("PATH", "/usr/local/bin"); // Replaces previous
// Using different types
std::string key = "PORT";
int value = 8080;
proc.with_var(key, value); // PORT=8080

Definition at line 308 of file subprocess.hpp.

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following file: