System Services
System Information
Introduction
The free functions in erbsland::system::info provide small machine-wide queries without exposing native types.
With the default flattened namespace, the same functions are available through erbsland::sys_info and
el::sys_info.
This deliberate alias avoids the ambiguous erbsland::info name.
operatingSystem() classifies the current host operating-system family, and cpuArchitecture() reports the native
host architecture rather than an emulated executable ABI such as Rosetta or WOW.
logicalCpuCount() is an affinity-aware thread-count hint where the platform supports that query.
It falls back through the platform’s active-CPU count and the standard-library hardware concurrency value and always
returns at least one.
The count is not a promise of dedicated cores or a representation of a container CPU quota.
OperatingSystem and CpuArchitecture are comparable smart-enum values with stable lowercase toString()
representations.
Unsupported values use Unknown.
Process Information
Introduction
ProcessId is an opaque, platform-independent identifier created by system APIs.
Its default value is invalid, and validity only means that the value can represent a native process identifier; it does
not prove that a process currently exists.
Valid identifiers format as decimal text, while an invalid identifier formats as an empty string.
ProcessInfo eagerly loads one independently owned snapshot for the current process or a supplied ProcessId.
Every accessor reads that snapshot without another platform query, and ordinary copies keep independent snapshot data.
Call reload() or reloadOrThrow() to replace all cached fields together.
Process Lifetime and Identifier Reuse
A process can exit while information is collected.
When the backend can prove that the process vanished, the result is a normal absent snapshot with exists() false.
The non-throwing reload also converts unexpected lookup failures into an absent snapshot, while reloadOrThrow()
reports those failures as PlatformError after replacing the previous snapshot.
Reload follows the numeric identifier.
An operating system can reuse that identifier for a new process, so code that needs continuity must retain the old valid
startTime() and compare it with the reloaded valid value.
auto info = erbsland::system::ProcessInfo{process.processId()};
const auto originalStart = info.startTime();
info.reload();
const bool sameProcess = info.exists() && originalStart.isValid() &&
info.startTime().isValid() && info.startTime() == originalStart;
Partial Access
An existing process can expose only part of its information because of platform permissions or native limitations.
The non-throwing accessors return the normal invalid sentinel for an unavailable field: an empty Path, invalid
ProcessId or Timestamp, or empty UserId.
Each throwing accessor reports the native diagnostic cached when the snapshot was loaded; it does not perform a second
lookup.
The first version intentionally excludes command lines, working directories, environment data, per-process CPU architecture, and mutable resource-usage metrics.
Environment Variables
Introduction
EnvironmentVariables provides portable access to the environment of the current process.
Each instance uses the native backend for the current operating system by default.
A custom backend can be supplied for isolated tests or specialized hosts.
Environment entries are process-wide. Changes are visible to subsequent native lookups and to child processes that inherit the environment. Names retain the native platform’s case-sensitivity rules.
Reading Variables
Use get(name) when absence must be distinguished from an empty stored value.
It returns std::nullopt for a missing variable or a failed lookup.
The two-argument overload returns its explicit fallback in these cases.
getOrThrow(name) returns an empty string for a stored empty value, throws NotFoundError for an absent variable,
and preserves native lookup failures as PlatformError.
Writing and Removing Variables
set() and remove() report failure through their boolean result.
Their OrThrow variants preserve platform failure details in PlatformError.
Removal is idempotent, so removing a variable that is already absent succeeds.
Setting an empty value stores an empty value; it does not remove the entry.
Names must not be empty or contain an equals sign or embedded null byte.
Values must not contain embedded null bytes.
The throwing variable methods report these portable syntax errors as ParseError.
Reading and Editing PATH
paths() returns an el::PathList of valid, lexically normalized entries in search order.
Reading never changes the environment.
Duplicate paths and malformed entries are skipped.
The non-throwing form returns an empty list when PATH is missing or lookup fails; pathsOrThrow() preserves lookup
errors.
prependPath(path) moves a path to the front, while appendPath(path) adds it only if absent.
insertPath(index, path) accepts an ItemIndex in the deduplicated list, including its end.
The index refers to the list before removing an existing equivalent entry; moving an earlier entry adjusts the index.
removePath(path) removes equivalent entries and removePathsIn(base) also removes descendants.
Every edit drops malformed entries and deduplicates the list, retaining the original spelling of other valid entries.
The boolean forms report failure; the OrThrow forms distinguish invalid arguments (ParameterFailure), backend
decoding errors (ParseError), and native failures (PlatformError).
A failed read does not cause an edit to replace PATH with a fallback value.
auto environment = el::EnvironmentVariables{};
const auto directories = environment.pathsOrThrow();
environment.prependPathOrThrow(el::Path::userHomeDirectory() / "tools/bin"_el);
environment.removePathsInOrThrow(el::Path::userHomeDirectory() / "obsolete-sdk"_el);
Both environment APIs share separator, lexical comparison, deduplication, and malformed-entry rules described below.
These are process-wide read/modify/write operations.
Coordinate concurrent environment changes in application code; the methods do not provide an atomic edit across
independent environment writers.
An absent PATH remains absent after removals.
As with EnvironmentChanges, removing all entries from an existing PATH stores an empty value, which represents the
current directory on subsequent reads.
Executable Candidates
executableCandidates(name) returns possible executable paths without accessing the filesystem.
A filename is combined with each valid PATH entry, in order; an absolute native path produces one candidate.
Relative paths containing directory components are rejected.
The non-throwing form returns an empty list on failure; executableCandidatesOrThrow() reports invalid input and
lookup failures.
On Windows, names without a suffix gain .exe; an explicit suffix is retained.
This API supports native process launching, so it does not consult shell aliases, PATHEXT, or implicit application
search directories.
Check each candidate’s existence, file type, and executable permissions before selecting it.
Use Path::toNativeString() when passing path-valued arguments to a subprocess.
Environment Changes
EnvironmentChanges is a copyable description of changes to an unspecified base environment.
Default construction inherits every base variable unchanged.
setInherit(EnvironmentInherit::None) starts with no inherited entries; All selects all entries.
setInherit(StringList) replaces inheritance with a named selection, ignoring missing names.
An empty selection inherits nothing.
setVariable(name, value) assigns after inheritance, and removeVariable(name) or its list overload removes
variables.
The latest action for each name wins under native name-comparison rules.
clearVariableChange(name) cancels either action and restores inheritance behavior for that name.
clearVariableChanges() preserves inheritance and PATH rules.
Explicit names and values must be valid UTF-8 with the same syntax constraints as subprocess environment entries;
invalid arguments immediately throw ParameterFailure.
Empty values remain distinct from absent variables.
apply(base) returns a new StringMap<String> without modifying the supplied map or accessing the process
environment.
SubprocessOptions::environmentChanges() provides mutable and const access to the descriptor, and
setEnvironmentChanges(changes) replaces it.
Subprocess preparation copies the descriptor; regular and detached launches read the parent environment when the child
is started.
Portable PATH Edits
PATH processing follows inheritance and variable assignments/removals.
removePath(path) removes every equivalent entry, while removePathsIn(base) removes the base itself and its
descendants using complete path components.
Comparison normalizes separators and dot components without accessing the filesystem, following symlinks, or making
relative paths absolute.
Windows names and paths compare case-insensitively; POSIX comparisons are case-sensitive.
After filtering, prependPath(path) and appendPath(path) insert explicit additions.
Repeated prepends put the most recent addition first; appends retain call order.
An addition can restore a filtered path.
Finally, deduplication retains the first lexically equivalent entry and its original spelling.
Malformed inherited PATH entries are discarded when PATH edits run.
Unchanged environment values retain their original encoding.
The separator is ; on Windows and : on POSIX.
Explicit path arguments must be valid and contain neither a null character nor the native PATH separator.
On Windows, paired outer quotes are accepted when reading entries, and %NAME% placeholders resolve once against the
environment being read or edited, using case-insensitive variable lookup.
For deferred changes, this is the resulting environment after inheritance and variable actions.
Unresolved or malformed placeholders, recursive expansions, embedded quotes, separator-containing expansions,
drive-relative paths such as C:tools, and invalid native encoding are skipped.
Valid original quotes and placeholders are retained when writing other entries back.
Explicit Windows Path arguments must not contain quote or percent characters, which would introduce ambiguous PATH
syntax.
PATH processing runs only when a prepend, append, or removal rule is configured.
Default inheritance and raw PATH assignments preserve the original value exactly.
Empty PATH entries represent the current directory and are deduplicated with equivalent . entries.
Removing every entry leaves an existing PATH present with an empty value.
An absent PATH stays absent unless additions create it; removeVariable("PATH") can remove it completely, while PATH
additions can recreate it.
clearPathChanges() preserves inheritance and variable actions.
User Lookup
Introduction
The system namespace provides application-shared services that expose small, portable wrappers around native
operating-system facilities.
Native failures use immutable PlatformErrorContext values.
The internal platform backends capture native details immediately and expose a portable PlatformErrorCategory for
domain diagnostics and actionable help.
PlatformError is the concrete exception used when the native failure itself is the reported error.
UserLookup resolves owner and group identifiers into display names and resolves names back to platform identifiers.
It caches successful lookups and is available through
Application::userLookup() for code that needs a shared service
instance.
Subprocesses
Creation and Ownership
Subprocess::create(executable, arguments, options) prepares a shared SubprocessPtr without launching a child.
Install optional handlers, then call start() once.
Executables and arguments are passed directly without shell interpretation or PATH lookup.
Plain procedural use requires no event loop.
Releasing the last process owner requests termination, waits briefly, then forcefully terminates and reaps a running
child.
Event callbacks should use weak pointers or non-owning captures to avoid retaining their source indefinitely.
DetachedSubprocess::start(...) launches independently and returns a shared DetachedSubprocessPtr exposing only
processId().
It has no events, capture, wait or termination API.
Dropping this handle does not stop the child; an independent waiter prevents POSIX zombies.
Capture options are rejected for detached children.
SubprocessOptions controls working directory, environment inheritance and changes, standard input inheritance,
output handling, capture limits and maximum output block size.
Its EnvironmentChanges descriptor selects inherited variables and applies variable and PATH changes at launch.
Waiting and Termination
wait() returns native completion without running callbacks.
The timed overload returns no status when its non-negative deadline expires.
isRunning(), processId(), and exitStatus() provide synchronized snapshots; the identifier remains valid
after exit.
Native launch, read and wait failures remain available through procedural exceptions.
Procedural waits and event observation can be mixed without consuming each other’s completion state.
On POSIX, terminate() sends SIGTERM and kill() sends SIGKILL.
Windows uses forced native termination for both operations.
A process can be started only once, including after a failed launch.
Optional Owner-Loop Events
Prefer creating event-driven processes through the loop’s system frontend:
auto process = events->get<el::System>().createSubprocess(executable, arguments, options);
process->events().onExit([](el::ExitCode code) -> void {
// Inspect an ordinary zero or nonzero exit.
}).onFinal([]() -> void {
// The workflow has ended.
});
process->start();
The frontend is obtained as a reference from Events::get<System>().
Creation through it and handler editing must occur on its owner loop.
For manually created processes, the first events() call binds the current loop, or throws LogicFailure if the
thread has no active loop.
Binding cannot later change; past lifecycle events are not replayed.
The source owns one stable SubprocessEventEditor with the usual source() and target() accessors.
onStarted() reports successful native launch.
onStandardOutput() and onStandardError() deliver String blocks with the initial UTF-8 BOM removed unless
removal was disabled in the launch options.
Pending output is delivered before one terminal outcome: onExit(ExitCode) for an ordinary exit, including nonzero
codes, or onError(const PlatformErrorContext &) for launch, read, wait or crash failures.
onFinal() follows either outcome, including when launch failed.
Fatal launch exceptions, including allocation and thread-creation failures, propagate unchanged from start() after
cleanup.
They do not emit onError() or onFinal().
POSIX signal termination is abnormal; Windows exit statuses with the high bit set are treated as exception-style
outcomes.
Windows exposes an exit code rather than definitive proof that the child crashed.
All callbacks execute on the owner loop and callback exceptions follow that loop’s configured error policy. Blocking waits neither pump the loop nor wait for callback delivery. Releasing the source suppresses callbacks that have not begun dispatching.
Standard Streams and Buffering
Stdout and stderr independently use inheritance, discard or bounded capture. Merged stderr follows the stdout destination and does not invoke the stderr handler. Standard input is inherited or connected to an immediately closed null stream.
For a Capture stream without an output handler, Core retains a prefix up to captureLimit() and drains excess bytes.
Setting its handler switches subsequent bytes to event delivery and disables further capture for that stream.
Clearing the handler discards queued event bytes and resumes capture, preserving earlier captured bytes.
Replacing a handler affects pending delivery.
By default, Core removes one initial UTF-8 BOM from each captured stream before retaining or delivering output.
Set SubprocessOptions::setRemoveOutputBom(false) to preserve it when reading byte-exact machine output;
removesOutputBom() reports the selected policy.
The signature may span native pipe reads and does not count toward the capture limit or pending-byte budget.
Merged stdout and stderr form one stream, so only its initial signature is removed.
Changing output handlers does not restart BOM handling.
maximumOutputChunkSize() bounds a callback’s byte count, defaults to 4096 and must be finite, representable and at
least 256. Valid UTF-8 code points are not split between callbacks.
All remaining bytes, including malformed bytes and later U+FEFF sequences, are preserved without decoding or
replacement; an unfinished trailing sequence or incomplete initial BOM is emitted unchanged at EOF.
Blocks are not line-oriented and may contain invalid UTF-8 or null bytes.
Each event-driven stream uses captureLimit() as its own pending-byte budget.
When the loop cannot keep up, new excess bytes are silently discarded while native pipes continue draining.
The stream’s truncation flag is set and onOutputTruncated() runs once per process if registered.
Overflow is not an operational error.
Subsequent output can be accepted after the buffer drains.
One coalesced dispatch per process bounds queued delivery work.
Environment-variable throwing operations report invalid names or values as ParseError and absent variables as
NotFoundError.
Native operation failures remain PlatformError.
Interface
-
class CpuArchitecture
A supported native CPU architecture.
Public Types
-
class DetachedSubprocess
Launch-only child handle; destruction does not stop the child.
Public Functions
Public Static Functions
-
static auto start(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {}) -> DetachedSubprocessPtr
Launch a child independently; an internal waiter prevents POSIX zombies.
- Parameters:
executable – Direct executable path.
arguments – Arguments following argv[0].
options – Environment and stream settings; capture is prohibited.
- Throws:
PlatformError – If native launch fails.
- Returns:
A shared launch identifier, without process control.
-
static auto start(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {}) -> DetachedSubprocessPtr
-
using erbsland::system::DetachedSubprocessPtr = std::shared_ptr<DetachedSubprocess>
Shared access to a detached child identifier.
-
class EnvironmentChanges
Describes inheritance, variable changes, and portable PATH edits without reading the environment.
See: System Services
Public Functions
-
bool isUnchangedInheritance() const noexcept
Test whether application inherits every variable without changing anything.
-
EnvironmentChanges &setInherit(EnvironmentInherit inherit)
Replace the inheritance selection with all or no base variables.
-
EnvironmentChanges &setInherit(text::StringList names)
Inherit only the named base variables; missing variables are ignored.
- Parameters:
names – The replacement selection; an empty list inherits nothing.
-
EnvironmentChanges &setVariable(const text::String &name, text::String value)
Assign a variable after inheritance, replacing any pending assignment or removal.
- Parameters:
name – A non-empty valid UTF-8 name without ‘=’ or null characters.
value – A valid UTF-8 value without null characters; may be empty.
-
EnvironmentChanges &removeVariable(const text::String &name)
Remove a variable after inheritance, replacing any pending assignment.
- Parameters:
name – The variable name.
-
EnvironmentChanges &removeVariable(const text::StringList &names)
Remove the named variables after inheritance.
- Parameters:
names – The variable names.
-
EnvironmentChanges &clearVariableChange(const text::String &name)
Cancel a variable’s pending assignment or removal, restoring inheritance behavior.
- Parameters:
name – The variable name.
-
EnvironmentChanges &clearVariableChanges() noexcept
Clear variable actions while preserving inheritance and PATH rules.
-
EnvironmentChanges &prependPath(path::Path path)
Insert a path at the front, ahead of earlier prepends.
- Parameters:
path – A valid path without the native PATH separator or null characters.
-
EnvironmentChanges &appendPath(path::Path path)
Insert a path at the back, after earlier appends.
- Parameters:
path – A valid path without the native PATH separator or null characters.
-
EnvironmentChanges &removePath(path::Path path)
Remove every lexically equivalent path before inserting additions.
- Parameters:
path – The path to remove.
-
EnvironmentChanges &removePathsIn(path::Path base)
Remove a base directory and its descendants before inserting additions.
- Parameters:
base – The base directory; matching is lexical and component-based.
-
EnvironmentChanges &clearPathChanges() noexcept
Clear PATH rules while preserving inheritance and variable actions.
-
text::StringMap<text::String> apply(const text::StringMap<text::String> &base) const
Return a new environment by applying this descriptor to a supplied base.
- Parameters:
base – The source environment; this method never reads or changes the process environment.
- Returns:
The resulting environment using the current platform’s name and PATH rules.
-
bool isUnchangedInheritance() const noexcept
-
enum class erbsland::system::EnvironmentInherit : uint8_t
Select the base environment inherited before applying changes.
Values:
-
enumerator None
Start with no inherited variables.
-
enumerator All
Inherit every variable from the base environment.
-
enumerator None
-
class EnvironmentVariables
Provides portable access to process environment variables.
See: System Services
Public Functions
-
EnvironmentVariables()
Create an instance using the backend for the current platform.
-
explicit EnvironmentVariables(impl::EnvironmentVariableBackendPtr backend)
Create an instance using a custom backend.
- Parameters:
backend – The custom backend, which must not be null.
-
std::optional<text::String> get(const text::String &name) const noexcept
Read an environment variable without throwing.
- Parameters:
name – The variable name.
- Returns:
The variable value, or
std::nulloptif it does not exist or the lookup fails.
-
text::String get(const text::String &name, text::String defaultValue) const noexcept
Read an environment variable without throwing, using a fallback value.
- Parameters:
name – The variable name.
defaultValue – The value returned if the variable does not exist or the lookup fails.
- Returns:
The variable value or the supplied fallback.
-
text::String getOrThrow(const text::String &name) const
Read an environment variable.
- Parameters:
name – The variable name. Must not be empty or contain
=or a null byte.- Throws:
PlatformError – If the native lookup fails.
err::ParseError – If the name or value contains invalid environment-variable syntax.
err::NotFoundError – If the variable is absent.
- Returns:
The variable value, including an empty value if one is stored.
-
bool set(const text::String &name, const text::String &value) noexcept
Set an environment variable without throwing.
- Parameters:
name – The variable name.
value – The new variable value.
- Returns:
trueon success, otherwisefalse.
-
void setOrThrow(const text::String &name, const text::String &value)
Set an environment variable.
- Parameters:
name – The variable name. Must not be empty or contain
=or a null byte.value – The new variable value. Must not contain a null byte.
- Throws:
PlatformError – If the native operation fails.
err::ParseError – If the name or value contains invalid environment-variable syntax.
-
bool remove(const text::String &name) noexcept
Remove an environment variable without throwing.
Removing a variable that does not exist succeeds.
- Parameters:
name – The variable name.
- Returns:
trueon success, otherwisefalse.
-
void removeOrThrow(const text::String &name)
Remove an environment variable.
Removing a variable that does not exist succeeds.
- Parameters:
name – The variable name. Must not be empty or contain
=or a null byte.- Throws:
PlatformError – If the native operation fails.
err::ParseError – If the name or value contains invalid environment-variable syntax.
-
path::PathList paths() const noexcept
Read valid, deduplicated PATH entries in search order without throwing.
- Returns:
Normalized paths, or an empty list if PATH is absent or inaccessible.
-
path::PathList pathsOrThrow() const
Read valid, deduplicated PATH entries in search order.
- Throws:
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode the environment value.
- Returns:
Normalized paths; absent PATH produces an empty list.
-
path::PathList executableCandidates(const text::String &name) const noexcept
Get native executable candidates without checking the filesystem or throwing.
- Parameters:
name – A filename or absolute native path; Windows adds .exe when no suffix is present.
- Returns:
Candidates in search order, or an empty list on failure.
-
path::PathList executableCandidatesOrThrow(const text::String &name) const
Get native executable candidates without checking the filesystem.
- Parameters:
name – A filename or absolute native path; Windows adds .exe when no suffix is present.
- Throws:
err::ParameterFailure – If the executable name is invalid.
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode an environment value.
- Returns:
PATH candidates, or a single explicitly supplied absolute path.
-
bool prependPath(const path::Path &path) noexcept
Move a path to the front of PATH without throwing.
- Parameters:
path – The path to prepend.
- Returns:
Whether the change succeeded.
-
void prependPathOrThrow(const path::Path &path)
Move a path to the front of PATH.
- Parameters:
path – The path to prepend.
- Throws:
err::ParameterFailure – If a supplied path or index is invalid.
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode an environment value.
-
bool appendPath(const path::Path &path) noexcept
Append a path unless it is already present in PATH without throwing.
- Parameters:
path – The path to append.
- Returns:
Whether the change succeeded.
-
void appendPathOrThrow(const path::Path &path)
Append a path unless it is already present in PATH.
- Parameters:
path – The path to append.
- Throws:
err::ParameterFailure – If a supplied path or index is invalid.
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode an environment value.
-
bool insertPath(unit::ItemIndex index, const path::Path &path) noexcept
Insert a path at an index, removing an equivalent entry first without throwing.
- Parameters:
index – Position in the deduplicated list before removal; the end is allowed.
path – The path to insert.
- Returns:
Whether the change succeeded.
-
void insertPathOrThrow(unit::ItemIndex index, const path::Path &path)
Insert a path at an index, removing an equivalent entry first.
- Parameters:
index – Position in the deduplicated list before removal; the end is allowed.
path – The path to insert.
- Throws:
err::ParameterFailure – If a supplied path or index is invalid.
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode an environment value.
-
bool removePath(const path::Path &path) noexcept
Remove lexically equivalent paths from PATH without throwing.
- Parameters:
path – The path to remove.
- Returns:
Whether the change succeeded.
-
void removePathOrThrow(const path::Path &path)
Remove lexically equivalent paths from PATH.
- Parameters:
path – The path to remove.
- Throws:
err::ParameterFailure – If a supplied path or index is invalid.
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode an environment value.
-
bool removePathsIn(const path::Path &base) noexcept
Remove a directory and its descendants from PATH without throwing.
- Parameters:
base – The directory to remove.
- Returns:
Whether the change succeeded.
-
void removePathsInOrThrow(const path::Path &base)
Remove a directory and its descendants from PATH.
- Parameters:
base – The directory to remove.
- Throws:
err::ParameterFailure – If a supplied path or index is invalid.
PlatformError – If environment access fails.
err::ParseError – If a backend cannot decode an environment value.
-
EnvironmentVariables()
-
class FileIdentity
An opaque identity for one filesystem object.
Public Functions
-
FileIdentity() = default
Create an invalid file identity.
-
inline constexpr bool isValid() const noexcept
Test if this identity represents a filesystem object.
Public Static Functions
-
static inline constexpr auto fromNativeValues(const uint64_t first, const uint64_t second) noexcept -> FileIdentity
Create a valid identity from two platform-specific values.
The values remain opaque and are meaningful only for equality comparison.
- Parameters:
first – The first native identity component.
second – The second native identity component.
- Returns:
A valid identity containing both native components.
-
FileIdentity() = default
-
class GroupId
A platform group identifier.
POSIX stores the numeric GID as text, Windows stores the SID string.
Public Functions
-
GroupId() = default
Create an empty group identifier.
-
inline explicit GroupId(const text::String &value)
Create a group identifier from its platform representation.
-
inline bool isEmpty() const noexcept
Test if this identifier is empty.
-
inline std::size_t hash() const noexcept
Get a stable hash for this identifier.
-
GroupId() = default
-
class GroupName
A platform group name with an optional domain.
Public Functions
-
GroupName() = default
Create an empty group name.
-
inline GroupName(const text::String &name, const text::String &domain)
Create a group name with an optional domain.
-
inline bool isEmpty() const noexcept
Test if this group name is empty.
-
std::size_t hash() const noexcept
Get a stable hash for this name.
-
GroupName() = default
-
class OperatingSystem
A supported operating-system family.
Public Types
-
class PlatformError : public erbsland::err::RuntimeError
A native platform error with immutable diagnostic context.
Public Functions
-
explicit PlatformError(text::String reason, PlatformErrorContextConstPtr context = {}, std::exception_ptr cause = {}) noexcept
Create a native platform error.
- Parameters:
reason – A developer-authored description of the failed operation.
context – The captured native diagnostic context.
cause – An optional independent cause.
-
virtual err::DiagnosticConstPtr diagnostic() const override
Convert the error with all its details into a structured diagnostic.
-
inline const PlatformErrorContextConstPtr &context() const noexcept
Get the captured native diagnostic context.
-
explicit PlatformError(text::String reason, PlatformErrorContextConstPtr context = {}, std::exception_ptr cause = {}) noexcept
-
class PlatformErrorCategory
A platform-neutral category for a native operating-system error.
Public Types
-
enum Value
Portable native failure categories.
Values:
-
enumerator Unknown
-
enumerator NotFound
-
enumerator PermissionDenied
-
enumerator AlreadyExists
-
enumerator InvalidPath
-
enumerator NotDirectory
-
enumerator IsDirectory
-
enumerator NameTooLong
-
enumerator SymbolicLinkLoop
-
enumerator ReadOnlyFileSystem
-
enumerator StorageFull
-
enumerator QuotaExceeded
-
enumerator CrossDevice
-
enumerator ResourceBusy
-
enumerator TooManyOpenFiles
-
enumerator FileTooLarge
-
enumerator Unsupported
-
enumerator Unknown
-
enum Value
-
class PlatformErrorContext
Immutable diagnostic details captured from a native operating-system error.
Subclassed by erbsland::network::impl::HostResolverErrorContext, erbsland::system::impl::PosixErrorContext, erbsland::system::impl::SubprocessErrorContext, erbsland::system::impl::WindowsErrorContext
Public Functions
-
virtual PlatformErrorCategory category() const noexcept = 0
Get the platform-neutral error category.
-
virtual text::String toString() const noexcept = 0
Get the native error message or a compact code representation.
-
virtual text::TextDocument toTextDocument() const = 0
Convert the native details into a field-only diagnostic document.
-
virtual PlatformErrorCategory category() const noexcept = 0
-
class ProcessId
A platform-independent process identifier.
A valid identifier can be compared and passed to process APIs, but does not guarantee that a process currently exists for it. Only system APIs create valid identifiers.
See: System Services
Public Functions
-
constexpr ProcessId() noexcept = default
Create an invalid process identifier.
-
inline constexpr bool isValid() const noexcept
Test if this process identifier can represent a native process.
-
text::String toString() const
Convert the identifier to decimal text, or return empty text for an invalid identifier.
-
inline std::size_t toHash() const noexcept
Get a stable hash for this identifier.
-
constexpr ProcessId() noexcept = default
-
class ProcessInfo
A cached snapshot of portable information about one process identifier.
Construction eagerly loads all attributes. The snapshot remains unchanged until
reload()is called. Reloading follows the numeric identifier, so comparestartTime()values when process-identifier reuse matters.See: System Services
Public Functions
-
ProcessInfo() noexcept
Create and load process information for the current process.
-
explicit ProcessInfo(ProcessId processId) noexcept
Create and load process information for the given identifier.
An invalid or currently unused identifier produces a non-existing snapshot.
- Parameters:
processId – The process identifier to inspect.
-
inline ProcessId processId() const noexcept
Get the process identifier represented by this snapshot.
-
inline bool exists() const noexcept
Test if the platform reported a process for this identifier when the snapshot was loaded.
-
inline const path::Path &executablePath() const noexcept
Get the absolute executable image path, or an empty path when unavailable.
-
path::Path executablePathOrThrow() const
Get the absolute executable image path.
- Throws:
PlatformError – If the path was unavailable in this snapshot.
-
inline ProcessId parentProcessId() const noexcept
Get the parent process identifier, or an invalid identifier when unavailable.
-
ProcessId parentProcessIdOrThrow() const
Get the parent process identifier.
- Throws:
PlatformError – If the identifier was unavailable in this snapshot.
-
inline time::Timestamp startTime() const noexcept
Get the UTC process start time, or an invalid date/time when unavailable.
-
time::Timestamp startTimeOrThrow() const
Get the UTC process start time.
- Throws:
PlatformError – If the start time was unavailable in this snapshot.
-
inline UserId ownerId() const noexcept
Get the process owner identifier, or an empty identifier when unavailable.
-
UserId ownerIdOrThrow() const
Get the process owner identifier.
- Throws:
PlatformError – If the owner was unavailable in this snapshot.
-
void reload() noexcept
Replace this snapshot with newly loaded information without throwing.
-
void reloadOrThrow()
Replace this snapshot with newly loaded information.
An unused identifier is a normal non-existing result.
- Throws:
PlatformError – If the platform cannot determine the process snapshot.
-
ProcessInfo() noexcept
-
class Subprocess : public erbsland::event::EventSource
Shared owner of one directly launched child with optional owner-loop events.
Releasing the last owner terminates and reaps a running child. Event handlers must not strongly capture their source.
See: System Services
Public Functions
-
void start()
Launch this prepared child once.
- Throws:
PlatformError – If native launch fails; event users also receive onError then onFinal.
-
ProcessId processId() const noexcept
Get the native identifier, invalid before launch and retained after exit.
-
bool isRunning()
Test whether the launched child is still running.
-
std::optional<SubprocessExitStatus> exitStatus() const
Get a synchronized exit-status snapshot.
-
SubprocessExitStatus wait()
Wait for workflow completion without pumping or waiting for event delivery.
- Throws:
PlatformError – If a native launch, read, or wait operation failed.
LogicFailure – If start() has not been called.
- Returns:
The native exit status.
-
std::optional<SubprocessExitStatus> wait(time::TimeDelta timeout)
Wait until completion or a non-negative timeout.
- Parameters:
timeout – Non-negative duration to wait for native exit and output drainage. Zero polls the synchronized workflow once. Expiry does not terminate the child or discard output. This wait neither pumps the owner loop nor waits for callback delivery.
- Throws:
PlatformError – If a native operation failed.
LogicFailure – If start() has not been called.
ParameterFailure – If timeout is negative.
- Returns:
Exit status, or no value on timeout.
-
void terminate()
Request native termination.
- Throws:
PlatformError – If termination fails.
-
void kill()
Force native termination.
- Throws:
PlatformError – If termination fails.
-
text::String standardOutput() const
Get the retained stdout prefix; event-routed bytes are not retained.
One initial UTF-8 BOM is removed before capture unless disabled in SubprocessOptions.
-
text::String standardError() const
Get the retained stderr prefix, empty when stderr is merged.
One initial UTF-8 BOM is removed before capture unless disabled in SubprocessOptions.
-
bool wasStandardOutputTruncated() const noexcept
Test whether stdout capture or event output overflowed.
-
bool wasStandardErrorTruncated() const noexcept
Test whether stderr capture or event output overflowed.
-
virtual SubprocessEventEditor &events() override
Access the stable editor, lazily binding the current loop on first use.
Must run on the owner loop. Past events are not replayed.
- Returns:
The source-owned editor.
Public Static Functions
-
static auto create(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {}) -> SubprocessPtr
Prepare a one-shot child without launching it or requiring an event loop.
- Parameters:
executable – Direct executable path; no shell interpretation or PATH lookup.
arguments – Arguments following argv[0], valid UTF-8 without null bytes.
options – Validated environment, capture, and output settings.
- Returns:
The inactive shared owner.
-
void start()
-
using erbsland::system::SubprocessPtr = std::shared_ptr<Subprocess>
Shared ownership of an owned subprocess.
-
class SubprocessEventEditor : public erbsland::event::impl::CommonEventEditor
Editor for owner-loop subprocess handlers; empty callbacks clear handlers.
Subclassed by erbsland::system::impl::SubprocessEventEditor
Public Types
-
using EventFn = std::function<void()>
A lifecycle notification.
-
using OutputFn = std::function<void(const text::String&)>
Stdout or stderr bytes, aligned at valid UTF-8 boundaries; BOM removal follows SubprocessOptions.
-
using ExitFn = std::function<void(unit::ExitCode)>
An ordinary process exit, including nonzero exit codes.
-
using ErrorFn = std::function<void(const PlatformErrorContext&)>
An abnormal workflow outcome with native diagnostic details.
Public Functions
-
virtual SubprocessEventEditor &onStarted(EventFn callback) = 0
Set the successful launch handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
virtual SubprocessEventEditor &onStandardOutput(OutputFn callback) = 0
Set the standard output handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
virtual SubprocessEventEditor &onStandardError(OutputFn callback) = 0
Set the standard error output handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
virtual SubprocessEventEditor &onOutputTruncated(EventFn callback) = 0
Set the once-only event-buffer overflow handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
virtual SubprocessEventEditor &onExit(ExitFn callback) = 0
Set the ordinary exit handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
virtual SubprocessEventEditor &onError(ErrorFn callback) = 0
Set the abnormal outcome handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
virtual SubprocessEventEditor &onFinal(EventFn callback) = 0
Set the final completion handler.
- Parameters:
callback – The replacement handler, or empty to clear it.
- Returns:
This editor.
-
using EventFn = std::function<void()>
-
class SubprocessExitStatus
Describes how an owned subprocess exited.
POSIX signal termination has no direct Windows equivalent. On Windows, native termination is represented by the process exit code and
terminationSignal()remains empty.See: System Services
Public Functions
-
inline constexpr bool hasExited() const noexcept
Test if the process returned an exit code.
-
inline constexpr bool wasSignaled() const noexcept
Test if the process was terminated by a POSIX signal.
-
inline constexpr bool isSuccess() const noexcept
Test if the process returned exit code zero.
-
inline constexpr const std::optional<std::int32_t> &exitCode() const noexcept
Get the process exit code, if the platform reported one.
-
inline constexpr const std::optional<std::int32_t> &terminationSignal() const noexcept
Get the POSIX termination signal, if the platform reported one.
Public Static Functions
-
static inline constexpr SubprocessExitStatus exited(const std::int32_t exitCode) noexcept
Create a status for a process that returned an exit code.
- Parameters:
exitCode – The process exit code.
-
static inline constexpr SubprocessExitStatus signaled(const std::int32_t signal) noexcept
Create a status for a process terminated by a POSIX signal.
- Parameters:
signal – The positive native signal number.
-
inline constexpr bool hasExited() const noexcept
-
class SubprocessOptions
Configures the launch environment and standard streams of a subprocess.
See: System Services
Public Functions
-
unit::ByteCount maximumOutputChunkSize() const noexcept
Get the maximum bytes in one output callback.
-
SubprocessOptions &setMaximumOutputChunkSize(unit::ByteCount value) noexcept
Set the maximum output block size (finite, at least 256 bytes).
-
const std::optional<path::Path> &workingDirectory() const noexcept
Get the optional child working directory.
-
SubprocessOptions &setWorkingDirectory(path::Path value) noexcept
Set the child working directory.
-
SubprocessOptions &clearWorkingDirectory() noexcept
Clear the configured child working directory.
-
const EnvironmentChanges &environmentChanges() const noexcept
Get the declarative environment changes applied when the child starts.
-
EnvironmentChanges &environmentChanges() noexcept
Edit the declarative environment changes applied when the child starts.
-
SubprocessOptions &setEnvironmentChanges(EnvironmentChanges value) noexcept
Replace the child environment configuration.
-
bool inheritsStandardInput() const noexcept
Test if the child inherits the parent’s standard input stream.
-
SubprocessOptions &setInheritStandardInput(const bool value) noexcept
Select whether the child inherits standard input or receives an immediately closed stream.
-
SubprocessOutputMode standardOutputMode() const noexcept
Get the standard output handling mode.
-
SubprocessOptions &setStandardOutputMode(const SubprocessOutputMode value) noexcept
Set the standard output handling mode.
-
SubprocessOutputMode standardErrorMode() const noexcept
Get the standard error handling mode.
-
SubprocessOptions &setStandardErrorMode(const SubprocessOutputMode value) noexcept
Set the standard error handling mode.
-
bool mergesStandardError() const noexcept
Test if standard error is redirected into standard output.
-
SubprocessOptions &setMergeStandardError(const bool value) noexcept
Select whether standard error is redirected into standard output.
-
inline bool removesOutputBom() const noexcept
Test whether one initial UTF-8 BOM is removed from each output stream.
-
SubprocessOptions &setRemoveOutputBom(bool value) noexcept
Select BOM removal; disable it when consuming byte-exact machine output.
-
unit::ByteCount captureLimit() const noexcept
Get the per-stream capture-prefix limit, or pending-byte budget when an output handler is set.
-
SubprocessOptions &setCaptureLimit(const unit::ByteCount value) noexcept
Set the number of bytes retained for each captured output stream.
-
unit::ByteCount maximumOutputChunkSize() const noexcept
-
enum class erbsland::system::SubprocessOutputMode : std::uint8_t
Selects how a subprocess output stream is handled.
Values:
-
enumerator Inherit
Inherit the matching stream from the parent process.
-
enumerator Discard
Discard all bytes written to the stream.
-
enumerator Capture
Capture a bounded prefix and continue draining excess bytes.
-
enumerator Inherit
-
class System
Event-loop frontend for system event sources.
Subclassed by erbsland::system::impl::SystemBackend
Public Functions
-
virtual auto createSubprocess(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {}) -> SubprocessPtr = 0
Prepare an owned child bound to this loop; call on its owner loop.
- Parameters:
executable – Direct executable path.
arguments – Child arguments.
options – Launch and output configuration.
- Returns:
A prepared event source; start it after configuring handlers.
Public Static Functions
-
static inline constexpr event::EventBackendId backendId() noexcept
Get the system backend identifier.
- Returns:
The built-in system backend identifier.
-
virtual auto createSubprocess(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {}) -> SubprocessPtr = 0
-
OperatingSystem erbsland::system::info::operatingSystem() noexcept
Get the current operating-system family.
-
CpuArchitecture erbsland::system::info::cpuArchitecture() noexcept
Get the native host CPU architecture.
This is the host architecture, not the current executable’s emulated architecture.
-
std::uint32_t erbsland::system::info::logicalCpuCount() noexcept
Get the usable logical CPU count as a thread-count hint.
The returned count is always at least one.
-
class UserId
A platform user identifier.
POSIX stores the numeric UID as text, Windows stores the SID string.
Public Functions
-
UserId() = default
Create an empty user identifier.
-
inline explicit UserId(const text::String &value)
Create a user identifier from its platform representation.
-
inline bool isEmpty() const noexcept
Test if this identifier is empty.
-
inline std::size_t hash() const noexcept
Get a stable hash for this identifier.
-
UserId() = default
-
class UserLookup
Cached lookup service for platform user and group identities.
Public Functions
-
UserLookup()
Create a lookup service with the default platform backend.
-
explicit UserLookup(impl::UserLookupBackendPtr backend)
Create a lookup service with a custom backend.
-
UserName userNameForId(const UserId &id)
Resolve an owner name from a platform owner identifier.
- Throws:
path::PathError – If the identifier cannot be resolved.
-
GroupName groupNameForId(const GroupId &id)
Resolve a group name from a platform group identifier.
- Throws:
path::PathError – If the identifier cannot be resolved.
-
UserId userIdForName(const UserName &name)
Resolve a platform owner identifier from an owner name.
- Throws:
path::PathError – If the name cannot be resolved.
-
GroupId groupIdForName(const GroupName &name)
Resolve a platform group identifier from a group name.
- Throws:
path::PathError – If the name cannot be resolved.
-
void clearCache() noexcept
Clear all cached lookups.
-
UserLookup()
-
class UserName
A platform user name with an optional domain.
Public Functions
-
UserName() = default
Create an empty user name.
-
inline UserName(const text::String &name, const text::String &domain)
Create a user name with an optional domain.
-
inline bool isEmpty() const noexcept
Test if this user name is empty.
-
std::size_t hash() const noexcept
Get a stable hash for this name.
-
UserName() = default