Module

std::process

Process

Safe, owned process helpers on supported POSIX hosts.

Overview

The Process namespace exposes startup argument access, process identifiers, host shell execution, and an owned Command builder for child processes. Argument helpers copy host argv data into owned String values so callers do not depend on raw C pointers.

The compiler-generated C main wrapper bootstraps runtime access to argc and argv. Runtime C does not own command-builder state; Process::Command stores owned Ignis data and drives POSIX fork, execvp, pipe, dup2, waitpid, and related calls through std::libc.

  C entrypoint
  ┌──────────────────────────────────────────────────────────────┐
  │ int main(int argc, char** argv)                              │
  └───────────────────────┬──────────────────────────────────────┘
                          │ stores argc/argv in runtime slots
                          ▼
  __process_rt
  ┌──────────────────────────────────────────────────────────────┐
  │ ignis_process_arg_count() -> argc                            │
  │ ignis_process_arg_at(i) -> argv[i] or null                   │
  └───────────────────────┬──────────────────────────────────────┘
                          │ copied into owned String values
                          ▼
  Process::args() -> Vector<String>

APIs

API Description
Process::args Owned startup arguments, including argv[0]
Process::argCount Raw startup argument count
Process::id Current process identifier
Process::parentId Parent process identifier
Process::system Execute a command through the host shell
Process::Command Owned child-process builder backed by POSIX APIs
Process::command Convenience constructor for Command
Process::ExitStatus Normalized wait-status view
Process::Output Captured stdout/stderr and status

Raw Status Values

Process::system returns the raw integer status produced by the host C library. This value is not normalized to an exit code; POSIX hosts encode signal and exit information in the wait status. Callers that need portable exit-code handling should prefer Process::Command::run or Process::Command::output, which return Process::ExitStatus.

Shell and Security Notes

Process::system delegates to the host shell. Shell expansion, quoting, environment inheritance, current working directory, and PATH lookup all follow host behavior. Do not pass untrusted text into system without explicit validation or quoting for the target shell.

Process::Command bypasses the shell unless the selected program is itself a shell. Arguments are passed as distinct argv entries to execvp.

Platform Notes

These APIs are currently enabled on Linux and macOS. system returns the raw host status and inherits the shell’s quoting and security behavior.

Example

import Process from "std::process";
import String from "std::string";
import Vector from "std::vector";

function main(): i32 {
  let args: Vector<String> = Process::args();
  return args.length() > 0 ? 0 : 1;
}

Command Example

import Path from "std::path";
import Process from "std::process";
import String from "std::string";
import Vector from "std::vector";

function main(): i32 {
  let mut command: Process::Command = Process::command("/bin/sh");
  command.arg("-c");
  command.arg("printf '%s' \"$IGNIS_EXAMPLE\"");
  command.env("IGNIS_EXAMPLE", "ok");
  command.cwd(&Path::PathBuf::create("/tmp"));

  match (command.output()) {
    Result::OK(output) -> {
      let status: Process::ExitStatus = output.status();
      let stdout: String = output.stdout();

      if status.success && stdout.equalsStr("ok") {
        return 0;
      }

      return status.code;
    },
    Result::ERROR(_) -> return 1,
  };
}
namespace __process_rt

Functions

function ignis_process_arg_at(index: i32): *mut u8

Returns a borrowed argv[index] pointer captured by the runtime.

function ignis_process_arg_count(): i32

Returns the argc value captured by the generated runtime entrypoint.

namespace Process

Process inspection and command execution helpers.

This namespace wraps runtime-provided startup arguments and selected POSIX process calls. Argument APIs return owned strings detached from the raw C argv storage captured when the generated program starts.

Records

record Command

Owned child-process builder implemented in Ignis std.

The builder keeps owned program, argument, environment, and cwd state in nongeneric storage so the std module can drive POSIX fork/execvp directly through std::libc without relying on dedicated runtime helpers.

Example

import Path from "std::path";
import Process from "std::process";
import String from "std::string";
import Vector from "std::vector";

let mut extra: Vector<String> = Vector::new<String>();
extra.push(String::create("-c"));
extra.push(String::create("printf done"));

let mut command: Process::Command = Process::Command::new("/bin/sh");
command.args(extra);
command.env("IGNIS_CHILD", "1");
command.cwd(&Path::PathBuf::create("/tmp"));

match (command.run()) {
  Result::OK(status) -> {
    let ok: boolean = status.success;
  },
  Result::ERROR(_) -> {},
};
Members
program: String

Program path or command name used for execvp.

args(&mut self, values: Vector<String>): void

Appends multiple arguments in order.

Each vector element is appended as one argv entry, preserving order.

argsLength: u64

Number of initialized entries in args.

argsCapacity: u64

Allocated capacity of args.

envKeys: *mut String

Owned child-only environment keys.

envValues: *mut String

Owned child-only environment values.

envLength: u64

Number of initialized key/value pairs in envKeys and envValues.

envCapacity: u64

Allocated capacity of envKeys and envValues.

cwd(&mut self, path: &PathBuf): void

Sets the child working directory without mutating the parent process.

The directory change runs after fork and before execvp, so it applies only to the child process.

hasCwd: boolean

True when cwd should be applied in the child after fork.

static new(program: str): Command

Creates a new child-process command builder.

program is copied into owned storage and is also inserted as argv[0].

arg(&mut self, value: str): void

Appends one argument to the child command line.

Arguments are not parsed by a shell. Each call appends one exact argv entry for the eventual execvp call.

args(&mut self, values: Vector<String>): void

Appends multiple arguments in order.

Each vector element is appended as one argv entry, preserving order.

buildArgv(&self): *mut str

Builds the null-terminated borrowed argv array required by execvp.

The returned array owns only the pointer vector, not the pointed-to string bytes. The parent frees the vector after fork; the child only uses it until execvp succeeds or processCommandChildFail exits.

cwd(&mut self, path: &PathBuf): void

Sets the child working directory without mutating the parent process.

The directory change runs after fork and before execvp, so it applies only to the child process.

drop(&mut self): void

Releases the owned builder storage.

dropArgsStorage(&mut self): void

Drops all initialized argv strings and frees argv storage.

dropEnvStorage(&mut self): void

Drops all initialized environment strings and frees environment storage.

env(&mut self, key: str, value: str): void

Adds or replaces one environment variable for the child only.

The parent process environment is not changed. Reusing the same key updates the child override instead of adding a duplicate entry.

growArgs(&mut self, minCapacity: u64): void

Ensures argv storage can hold at least minCapacity initialized entries.

growEnv(&mut self, minCapacity: u64): void

Ensures environment key/value storage can hold minCapacity entries.

output(&self): Result<Output, IoError>

Runs the child process and captures stdout/stderr into owned Strings.

Captured output is stored in temporary files created with mkstemp and unlinked before the child runs, avoiding visible leftover paths when the process completes normally.

Example

import Process from "std::process";
import String from "std::string";

let mut command: Process::Command = Process::Command::new("/bin/sh");
command.arg("-c");
command.arg("printf stdout; printf stderr 1>&2");

match (command.output()) {
  Result::OK(output) -> {
    let status: Process::ExitStatus = output.status();
    let stdout: String = output.stdout();
    let stderr: String = output.stderr();
  },
  Result::ERROR(_) -> {},
};
prepareChild(&self, errorFd: i32): void

Applies child-only cwd and environment state after fork.

This function must run in the child. On failure it reports errno through errorFd and exits, because returning into shared parent control flow after partial child setup would be unsafe.

pushArgValue(&mut self, value: str): void

Copies value into owned argv storage.

run(&self): Result<ExitStatus, IoError>

Runs the child process without capturing stdout or stderr.

Example

import Process from "std::process";

let mut command: Process::Command = Process::command("/bin/sh");
command.arg("-c");
command.arg("exit 7");

match (command.run()) {
  Result::OK(status) -> {
    let code: i32 = status.code;
    let ok: boolean = status.success;
  },
  Result::ERROR(_) -> {},
};
setEnvValue(&mut self, key: str, value: str): void

Adds or replaces one child environment override in owned storage.

spawn(&self, stdoutFd: i32, stderrFd: i32, rawStatusOut: &mut i32): i32

Forks, optionally redirects output fds, execs the program, and waits.

Returns 0 on successful spawn/wait and writes the raw wait status to rawStatusOut. A nonzero return value is a raw errno suitable for Io::IoError::fromErrno.

record ExitStatus

Normalized child-process status derived from a POSIX wait status.

raw preserves the host wait status. code contains a shell-like exit code: regular exits use the child exit code and signal exits use 128 + signal. success is true only when the child exited with code 0.

Members
raw: i32

Raw host wait status returned by the runtime.

code: i32

Normalized exit-code-like value.

success: boolean

True when the command exited successfully.

record Output

Captured child-process output plus exit status.

Example

import Process from "std::process";
import String from "std::string";

let command: Process::Command = Process::Command::new("/bin/echo");
match (command.output()) {
  Result::OK(output) -> {
    let status: Process::ExitStatus = output.status();
    let stdout: String = output.stdout();
  },
  Result::ERROR(_) -> {},
};
Members
status(&self): ExitStatus

Returns the child exit status.

stdout(&self): String

Returns a cloned copy of captured stdout.

stderr(&self): String

Returns a cloned copy of captured stderr.

status(&self): ExitStatus

Returns the child exit status.

stderr(&self): String

Returns a cloned copy of captured stderr.

stdout(&self): String

Returns a cloned copy of captured stdout.

Functions

function argCount(): i32

Returns the host startup argument count, including argv[0].

The count comes from the runtime bootstrap created by the compiler’s C main wrapper. It is the same count used by Process::args.

Returns

Number of startup arguments captured by the runtime, including argv[0].

Invariants

argCount() should match Process::args().length() as long as runtime initialization happened before the call and the runtime bridge remains unchanged.

Example

import Process from "std::process";

let count: i32 = Process::argCount();
let hasProgramName: boolean = count > 0;
function args(): Vector<String>

Returns owned copies of the startup arguments, including argv[0].

The returned vector owns every string. Mutating or storing the returned values is safe because they no longer borrow from the runtime argv array.

Ordering

The result preserves host argv order exactly:

  args()[0] -> argv[0]  // program/test binary path
  args()[1] -> argv[1]
  args()[2] -> argv[2]

The std test runner invokes individual tests through its own harness, so argv[0] is the generated std test binary in that context.

Returns

A vector with Process::argCount() entries. The first entry is the program path or command name as supplied by the host process launcher.

Example

import Process from "std::process";

let args = Process::args();
let hasUserArg: boolean = args.length() > 1;
function command(program: str): Command

Convenience helper mirroring common builder-style construction.

Example

import Process from "std::process";

let mut command: Process::Command = Process::command("/bin/echo");
command.arg("hello");
function id(): i32

Returns the current process identifier.

This is the host PID returned by getpid(2) on POSIX platforms. The value is useful for diagnostics, logs, temporary file names, and process-aware integration tests.

Returns

Positive host process identifier for the currently running test or program.

Notes

PIDs are host resources. They are not deterministic between runs and should only be used for diagnostics, uniqueness, or sanity checks.

Example

import Process from "std::process";

let pid: i32 = Process::id();
let valid: boolean = pid > 0;
function parentId(): i32

Returns the parent process identifier.

This is the host parent PID returned by getppid(2). Parent process IDs can change if the original parent exits and the process is reparented by the operating system.

Returns

Host process identifier for the current process parent.

Notes

POSIX can reparent processes when the original parent exits. Do not use this value as a stable identity across long-running programs.

Example

import Process from "std::process";

let parent: i32 = Process::parentId();
let hasParent: boolean = parent > 0;
function system(command: str): i32

Executes command through the host shell and returns the raw host status.

The command is passed to the platform C library system(3). The shell is responsible for parsing, expansion, redirection, PATH lookup, and process creation. The returned value is the raw host status, not a normalized exit code.

Security

Avoid building command from untrusted input. Shell metacharacters can change the executed program or add additional commands.

Arguments

  • command: shell command text passed directly to system(3).

Returns

Raw host status returned by the C library. On POSIX this is a wait status, not just the child exit code.

Status Encoding

A command that exits with code 1 may return an encoded value such as 256, depending on the platform. Prefer Process::Command::run when you need the normalized Process::ExitStatus view.

Example

import Process from "std::process";

let status: i32 = Process::system("true");
let succeededExactly: boolean = status == 0;

Functions

function processCommandChildFail(errorFd: i32, rawErrno: i32): void

Reports child setup or exec failure to the parent, then exits the child.

This helper must only run after fork in the child process. It writes a raw errno value to the close-on-exec error pipe so the parent can distinguish successful execvp from setup failures before returning an IoError.

function processCommandReadAll(fd: i32): Result<String, IoError>

Reads a seekable temporary output file into an owned String.

The caller retains ownership of fd and must close it after this helper returns. The temporary file has already been unlinked by Command::output, so reading consumes only the anonymous open descriptor.

function processCommandSetCloseOnExec(fd: i32): i32

Marks fd close-on-exec so parent-only descriptors do not leak into children.

function processCommandWaitForExec(pid: i32, errorReadFd: i32, rawStatusOut: &mut i32): i32

Waits for child startup completion and then reaps the child process.

The error pipe is close-on-exec. EOF therefore means execvp succeeded, while bytes on the pipe contain the child setup/exec errno. This function owns and closes errorReadFd before returning.

function processExitStatusFromRaw(rawStatus: i32): ExitStatus

Converts a raw host wait status into the public ExitStatus record.

function processOwnedArgAt(index: i32): String

Copies one runtime argument into an owned String.

A null runtime pointer is treated as an empty string to keep Process::args total over the range 0..Process::argCount().

Runtime Contract

The generated C wrapper must call ignis_runtime_init(argc, argv) before any user or test code calls this helper. Without runtime initialization, argument count and pointer reads fall back to whatever the runtime bridge reports.

Arguments

  • index: zero-based runtime argument index.

Returns

An owned String copy of argv[index], or an empty String if the runtime reports a null pointer. Callers normally use Process::args instead of this helper.

function processWaitStatusCode(rawStatus: i32): i32

Converts a POSIX wait status into a shell-like status code.

function processWaitStatusExited(rawStatus: i32): boolean

Returns true when a POSIX wait status represents normal child exit.

function processWaitStatusStopped(rawStatus: i32): boolean

Returns true when a POSIX wait status represents a stopped child.

function processWaitStatusSuccess(rawStatus: i32): boolean

Returns true only for normal exit with status code 0.

Constants

const PROCESS_EXEC_FAILURE_EXIT: i32
const PROCESS_SIGNAL_MASK: i32
const PROCESS_STOPPED_MASK: i32
const PROCESS_STOPPED_VALUE: i32