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 DateTime, 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 and throws PlatformError if the variable does
not exist or the native lookup fails.
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 methods report these portable input errors as ParameterError.
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
Introduction
Subprocess starts and owns one operating-system child process without invoking a command shell.
The executable and each argument are passed as separate values, so shell quoting, expansion, redirection, and pipelines
are never applied.
An owned child is reaped when it exits.
Destroying a Subprocess that is still running first requests termination, waits briefly, then forcefully terminates
and reaps the child.
This makes the type suitable for helpers whose lifetime must not outlive an application scope or test.
startDetached() is the explicit launch-and-forget operation; an internal waiter still prevents a zombie process on
POSIX systems.
Starting a Process
start() requires a direct executable path and an optional StringList of arguments.
It does not search the PATH environment variable.
SubprocessOptions can select a working directory, environment inheritance and changes, standard-input inheritance,
and output handling.
Environment changes are applied after optional inheritance.
A value assigns the variable and std::nullopt removes it.
Variable-name case sensitivity follows the operating system.
Waiting and Termination
wait() blocks until the child exits.
The timed overload returns std::nullopt when its non-negative deadline expires.
isRunning() performs a non-blocking status update.
Once observed, the SubprocessExitStatus remains available through exitStatus().
The processId() accessor returns the identifier assigned at launch and keeps returning it after the child exits.
A moved-from Subprocess returns an invalid identifier.
Use the process-information interfaces described above to inspect a running child through a portable snapshot.
On POSIX, terminate() sends SIGTERM and kill() sends SIGKILL.
Windows has no equivalent graceful process signal, so both operations use native forced process termination.
Normal Windows termination is reported as an exit code; POSIX signal termination is reported separately.
Standard Streams
Standard output and standard error can independently be inherited, discarded, or captured. Standard error can instead be merged into the selected standard-output destination. Standard input can only be inherited or connected to an immediately closed null stream; interactive input piping is intentionally outside this API.
Capture retains a bounded prefix while background readers continue draining the native pipes. This prevents a verbose child from blocking after the capture limit is reached. The default limit is one MiB per stream and the maximum configurable limit is 64 MiB. Use the truncation accessors to detect discarded suffixes. Detached processes cannot use capture because no owner remains to consume the result.
Interface
-
class CpuArchitecture
A supported native CPU architecture.
Public Types
-
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.
- Throws:
err::ParameterError – If
backendis 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.
- Throws:
err::ParameterError – If
nameis invalid.PlatformError – If the variable does not exist or the native lookup fails.
- 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.
value – The new variable value.
- Throws:
err::ParameterError – If
nameorvalueis invalid.PlatformError – If the native operation fails.
-
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.
- Throws:
err::ParameterError – If
nameis invalid.PlatformError – If the native operation fails.
-
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 FileIdentity fromNativeValues(const uint64_t first, const uint64_t second) noexcept
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::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::DateTime startTime() const noexcept
Get the UTC process start time, or an invalid date/time when unavailable.
-
time::DateTime 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
Owns and controls one directly launched operating-system child process.
No method invokes a command shell. Destruction of a running owned process requests termination, waits briefly, then forcefully terminates and reaps it. Use
startDetached()for deliberate launch-and-forget behavior.See: System Services
Public Functions
-
~Subprocess()
Destroy the subprocess owner and ensure a running child is terminated and reaped.
-
Subprocess(Subprocess &&other) noexcept
Move ownership of a subprocess.
-
Subprocess &operator=(Subprocess &&other) noexcept
Replace this subprocess owner by moving another owner into it.
-
ProcessId processId() const noexcept
Get the identifier assigned to the child process.
The identifier remains valid after exit; a moved-from subprocess returns an invalid identifier.
-
bool isRunning()
Test if the child is still running and update cached exit state.
-
const std::optional<SubprocessExitStatus> &exitStatus() const noexcept
Get the cached child exit status, if it has been observed.
-
SubprocessExitStatus wait()
Wait until the child exits and return its status.
- Throws:
PlatformError – If the native wait operation fails.
-
std::optional<SubprocessExitStatus> wait(time::TimeDelta timeout)
Wait up to the given timeout for the child to exit.
- Parameters:
timeout – A non-negative timeout.
- Throws:
err::ParameterError – If
timeoutis negative.PlatformError – If the native wait operation fails.
- Returns:
The exit status, or no value if the timeout expired.
-
void terminate()
Request child termination using the platform’s regular termination mechanism.
- Throws:
PlatformError – If the native operation fails.
-
void kill()
Force the child to terminate.
- Throws:
PlatformError – If the native operation fails.
-
text::String standardError() const
Get the currently captured standard error prefix.
This is empty when standard error was merged into standard output.
-
bool wasStandardOutputTruncated() const noexcept
Test if captured standard output exceeded its configured limit.
-
bool wasStandardErrorTruncated() const noexcept
Test if captured standard error exceeded its configured limit.
Public Static Functions
-
static auto start(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {}) -> Subprocess
Launch an owned subprocess.
- Parameters:
executable – A non-empty valid executable path. No
PATHlookup or shell interpretation is performed.arguments – Arguments following
argv[0]in the child command line.options – Child environment and standard-stream options.
- Throws:
err::ParameterError – If a path, argument, environment entry, or option is invalid.
PlatformError – If native process creation fails.
- Returns:
The owning subprocess object.
-
static void startDetached(const path::Path &executable, const text::StringList &arguments = {}, const SubprocessOptions &options = {})
Launch a subprocess without retaining ownership or process control.
Output capture is not permitted for detached children. An internal waiter prevents POSIX zombies.
- Parameters:
executable – A non-empty valid executable path. No
PATHlookup or shell interpretation is performed.arguments – Arguments following
argv[0]in the child command line.options – Child environment and standard-stream options.
- Throws:
err::ParameterError – If a path, argument, environment entry, or option is invalid.
PlatformError – If native process creation fails.
-
~Subprocess()
-
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.
Environment changes are applied after optional inheritance. Assigning no value removes the variable from the child environment. Names retain the native platform’s case-sensitivity rules.
See: System Services
Public Functions
-
inline const std::optional<path::Path> &workingDirectory() const noexcept
Get the optional child working directory.
-
inline SubprocessOptions &setWorkingDirectory(path::Path value) noexcept
Set the child working directory.
-
inline SubprocessOptions &clearWorkingDirectory() noexcept
Clear the configured child working directory.
-
inline bool inheritsEnvironment() const noexcept
Test if the child inherits the current process environment.
-
inline SubprocessOptions &setInheritEnvironment(const bool value) noexcept
Select whether the child inherits the current process environment.
-
inline const text::StringMap<std::optional<text::String>> &environmentChanges() const noexcept
Get environment assignments and removals applied to the child environment.
-
inline SubprocessOptions &setEnvironmentVariable(const text::String &name, text::String value)
Assign one child environment variable.
-
inline SubprocessOptions &removeEnvironmentVariable(const text::String &name)
Remove one variable from the child environment.
-
inline SubprocessOptions &clearEnvironmentChanges() noexcept
Remove all pending child environment changes.
-
inline bool inheritsStandardInput() const noexcept
Test if the child inherits the parent’s standard input stream.
-
inline SubprocessOptions &setInheritStandardInput(const bool value) noexcept
Select whether the child inherits standard input or receives an immediately closed stream.
-
inline SubprocessOutputMode standardOutputMode() const noexcept
Get the standard output handling mode.
-
inline SubprocessOptions &setStandardOutputMode(const SubprocessOutputMode value) noexcept
Set the standard output handling mode.
-
inline SubprocessOutputMode standardErrorMode() const noexcept
Get the standard error handling mode.
-
inline SubprocessOptions &setStandardErrorMode(const SubprocessOutputMode value) noexcept
Set the standard error handling mode.
-
inline bool mergesStandardError() const noexcept
Test if standard error is redirected into standard output.
-
inline SubprocessOptions &setMergeStandardError(const bool value) noexcept
Select whether standard error is redirected into standard output.
-
inline unit::ByteLength captureLimit() const noexcept
Get the number of bytes retained for each captured output stream.
-
inline SubprocessOptions &setCaptureLimit(const unit::ByteLength value) noexcept
Set the number of bytes retained for each captured output stream.
Public Static Attributes
-
static constexpr auto cDefaultCaptureLimit = unit::ByteLength{1024U * 1024U}
Default number of bytes retained for each captured output stream.
-
static constexpr auto cMaximumCaptureLimit = unit::ByteLength{64U * 1024U * 1024U}
Maximum configurable number of retained bytes for each captured output stream.
-
inline const std::optional<path::Path> &workingDirectory() 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
-
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