Chapter 18 17 min read

OS

stdlib::os exposes the host machine and the running process's identity: which OS and CPU you compiled for, the process ID, the current working directory, the executable's path, hardware facts (CPU count, RAM, uptime), platform-native standard directories, terminal detection, and a one-shot shell escape.

Functions come in two flavors:

  • Compile-time facts return a value directly (string / bool / i32). These cannot meaningfully fail: os_name, os_arch, the os_is_* predicates, the separators, os_pid, and os_is_tty.
  • Runtime queries return a !T Result. Each Err carries a human-readable reason, and several are Err on platforms that don't expose the metric (e.g. os_ppid/os_uid/os_gid/os_loadavg_1m on Windows).

Import

import stdlib::os::*;

Full catalog

All 36 public items at a glance. The Fails? column flags which return !T and on which platform the call typically becomes Err.

Function Signature Fails? Description
os_name fn os_name() -> string never OS family string.
os_arch fn os_arch() -> string never CPU architecture string.
os_is_windows fn os_is_windows() -> bool never true on Windows.
os_is_posix fn os_is_posix() -> bool never true on Linux/macOS/*BSD.
os_is_linux fn os_is_linux() -> bool never true only on Linux.
os_is_macos fn os_is_macos() -> bool never true only on macOS.
os_has_async_io fn os_has_async_io() -> bool never true when the epoll/kqueue reactor is wired.
os_has_reuseport_balance fn os_has_reuseport_balance() -> bool never true when SO_REUSEPORT balances accepts (Linux).
os_path_sep fn os_path_sep() -> string never \ on Windows, / else.
os_line_sep fn os_line_sep() -> string never \r\n on Windows, \n else.
os_path_list_sep fn os_path_list_sep() -> string never ; on Windows, : else.
os_pid fn os_pid() -> i32 never Current process ID.
os_ppid fn os_ppid() -> !i32 Windows Parent process ID.
os_uid fn os_uid() -> !i32 Windows POSIX user ID.
os_gid fn os_gid() -> !i32 Windows POSIX group ID.
os_username fn os_username() -> !string rare Login name.
os_hostname fn os_hostname() -> !string rare Machine host name.
os_kernel_version fn os_kernel_version() -> !string rare uname -r / Windows build.
os_cwd fn os_cwd() -> !string rare Current working directory.
os_chdir fn os_chdir(path: string) -> ! yes Change working directory (no value).
os_exe_path fn os_exe_path() -> !string rare Absolute path of the binary.
os_exe_dir fn os_exe_dir() -> !string rare Directory of the binary.
os_cpu_count fn os_cpu_count() -> !i32 rare Logical CPUs.
os_cpu_count_physical fn os_cpu_count_physical() -> !i32 rare Physical cores (falls back to logical).
os_page_size fn os_page_size() -> !i32 rare VM page size in bytes.
os_memory_total fn os_memory_total() -> !u64 rare Total physical RAM (bytes).
os_memory_free fn os_memory_free() -> !u64 macOS/BSD Available RAM (bytes).
os_uptime_secs fn os_uptime_secs() -> !u64 rare Seconds since boot.
os_loadavg_1m fn os_loadavg_1m() -> !f64 Windows 1-minute load average.
os_temp_dir fn os_temp_dir() -> !string rare Per-user temp dir.
os_home_dir fn os_home_dir() -> !string rare User home dir.
os_config_dir fn os_config_dir() -> !string rare Per-user config base dir.
os_cache_dir fn os_cache_dir() -> !string rare Per-user cache base dir.
os_data_dir fn os_data_dir() -> !string rare Per-user data base dir.
os_is_tty fn os_is_tty(fd: i32) -> bool never true if fd is a terminal.
os_shell fn os_shell(cmd: string) -> !i32 spawn-fail Run cmd through the OS shell.

Platform identity (compile-time, infallible)

These reflect the build target — the platform the binary was compiled for — and never fail.

Function Signature Description
os_name fn os_name() -> string OS family: "linux", "windows", "macos", "freebsd", "openbsd", "netbsd", or "unknown".
os_arch fn os_arch() -> string CPU arch: "x86_64", "aarch64", "arm", "x86", "riscv64", or "unknown".
os_is_windows fn os_is_windows() -> bool true on Windows.
os_is_posix fn os_is_posix() -> bool true on POSIX-y systems (Linux, macOS, *BSD); false on Windows.
os_is_linux fn os_is_linux() -> bool true only on Linux.
os_is_macos fn os_is_macos() -> bool true only on macOS / Darwin (os_is_posix() is also true).
os_has_async_io fn os_has_async_io() -> bool true when the async I/O reactor (epoll/kqueue) is wired; false where I/O falls back to blocking sync.
os_has_reuseport_balance fn os_has_reuseport_balance() -> bool true when SO_REUSEPORT actually load-balances accepts (Linux only today).
os_path_sep fn os_path_sep() -> string Path component separator: \ on Windows, / elsewhere.
os_line_sep fn os_line_sep() -> string Line ending: "\r\n" on Windows, "\n" elsewhere.
os_path_list_sep fn os_path_list_sep() -> string PATH-list separator: ; on Windows, : elsewhere.
import stdlib::os::*;

fn main() -> i32 {
    println!("os:", os_name());
    println!("arch:", os_arch());
    if os_is_windows() {
        println!("on windows, sep =", os_path_sep());
    } else {
        println!("on posix, sep =", os_path_sep());
    }
    if os_is_linux() { println!("linux"); }
    if os_is_macos() { println!("macos"); }
    if os_is_posix() { println!("posix"); }
    println!("path list sep:", os_path_list_sep());
    let line: string = format!("hello{}", os_line_sep());
    println!(line);
    if os_has_async_io() { println!("reactor active"); }
    if os_has_reuseport_balance() { println!("reuseport balances"); }
    return 0;
}

Dispatching on os_name

match only matches enum variants / some/none / _not string literals. To branch on the OS family, compare with .eq in an if/else chain:

import stdlib::os::*;

fn opener() -> string {
    let n: string = os_name();
    if n.eq("macos")   { return "open"; }
    if n.eq("windows") { return "start"; }
    return "xdg-open";
}

fn main() -> i32 {
    println!("url opener for", os_name(), "is", opener());

    let sep: string = os_line_sep();
    let doc: string = format!("line1{}line2{}", sep, sep);
    println!(doc);
    return 0;
}

Runtime branching on the reactor

os_has_async_io lets a server decide whether it is safe to spawn a coroutine per connection (true with a reactor) or must serve serially inline (the only correct behaviour when read/write block the calling thread):

if os_has_async_io() { spawn handle(c); }
else                 { handle(c); }

os_has_reuseport_balance is the companion for worker pools: when true, each worker can bind_reuseport and let the kernel balance accepts; when false, bind one shared listener and have N threads accept() on it.

Splitting $PATH

Use os_path_list_sep when splitting $PATH / %PATH% — it is ; on Windows but : on POSIX, and hard-coding either breaks the other platform:

import stdlib::os::*;
import stdlib::env::*;

fn main() -> i32 {
    let path: string = env_get("PATH");
    let sep: string = os_path_list_sep();          // ";" on Windows, ":" else
    let dirs: *Vector<string> = path.split(sep);
    println!("PATH has", dirs.len(), "entries");

    let mut i: i32 = 0;
    while i < dirs.len() {
        let d: string = dirs.get(i);
        if !d.eq("") { println!("  ", d); }
        i = i + 1;
    }
    return 0;
}

Process identity

Function Signature Description
os_pid fn os_pid() -> i32 Current process ID. Always positive; never fails.
os_ppid fn os_ppid() -> !i32 Parent process ID. Err("ppid not available") on Windows.
os_uid fn os_uid() -> !i32 POSIX user ID. Err on Windows (no numeric UID).
os_gid fn os_gid() -> !i32 POSIX group ID. Err on Windows.
os_username fn os_username() -> !string Login name ($USER/getpwuid on POSIX, GetUserNameA on Windows).
os_hostname fn os_hostname() -> !string Machine host name.
os_kernel_version fn os_kernel_version() -> !string uname -r on POSIX; <major>.<minor>.<build> on Windows.

os_pid returns a bare i32 — no Result to unwrap. The rest return !T; read .ok, .val, and .err:

import stdlib::os::*;

fn main() -> i32 {
    println!("pid       :", os_pid());            // bare i32, infallible

    let pp: !i32 = os_ppid();                     // Err on Windows
    if pp.ok { println!("ppid      :", pp.val); }
    else     { println!("ppid      :", pp.err); }

    let u: !i32 = os_uid();                        // Err on Windows
    if u.ok  { println!("uid       :", u.val); }

    let g: !i32 = os_gid();                        // Err on Windows
    if g.ok  { println!("gid       :", g.val); }

    let user: !string = os_username();
    if user.ok { println!("user      :", user.val); }

    let host: !string = os_hostname();
    if host.ok { println!("host      :", host.val); }

    let kv: !string = os_kernel_version();
    if kv.ok   { println!("kernel    :", kv.val); }

    // uid == 0 means root on POSIX.
    if u.ok && u.val == 0 { println!("(running as root)"); }
    return 0;
}

Current directory and executable

Function Signature Description
os_cwd fn os_cwd() -> !string Current working directory, no trailing separator.
os_chdir fn os_chdir(path: string) -> ! Change the process's working directory. Success carries no value — check r.ok.
os_exe_path fn os_exe_path() -> !string Absolute path of the running executable.
os_exe_dir fn os_exe_dir() -> !string Directory portion of os_exe_path, no trailing separator.

os_chdir returns a valueless Result (!). On success there is nothing to read; on failure (missing path, no permission) r.ok is false and r.err holds the reason.

A robust pattern is to save the cwd, change into a scratch directory, then restore it — the working directory is process-global, so leaving it changed surprises the rest of your program:

import stdlib::os::*;

fn main() -> i32 {
    let saved: !string = os_cwd();
    if !saved.ok { println!("no cwd:", saved.err); return 1; }
    println!("start:", saved.val);

    let tmp: !string = os_temp_dir();
    if tmp.ok {
        let c: ! = os_chdir(tmp.val);
        if c.ok {
            let now: !string = os_cwd();
            if now.ok { println!("moved to:", now.val); }
        } else {
            println!("chdir failed:", c.err);
        }
    }

    // Always restore.
    let back: ! = os_chdir(saved.val);
    if !back.ok { println!("restore failed:", back.err); }
    return 0;
}

Finding resources next to the binary

os_exe_dir is the reliable way to locate files shipped alongside your executable, independent of the cwd the user launched from. Build the path with os_path_sep so it works on both Windows and POSIX:

import stdlib::os::*;

fn main() -> i32 {
    let exe: !string = os_exe_path();
    if exe.ok { println!("running:", exe.val); }

    let dir: !string = os_exe_dir();
    if dir.ok {
        let asset: string = format!("{}{}assets{}logo.png",
            dir.val, os_path_sep(), os_path_sep());
        println!("asset:", asset);
    } else {
        println!("exe dir unavailable:", dir.err);
    }
    return 0;
}

Hardware

All hardware queries return Results. CPU/page counts are !i32; memory and uptime are !u64; load average is !f64.

Function Signature Description
os_cpu_count fn os_cpu_count() -> !i32 Logical CPUs available to the process.
os_cpu_count_physical fn os_cpu_count_physical() -> !i32 Physical cores; falls back to os_cpu_count() when unavailable.
os_page_size fn os_page_size() -> !i32 Virtual memory page size in bytes (typically 4096; 16384 on Apple Silicon).
os_memory_total fn os_memory_total() -> !u64 Total physical RAM in bytes.
os_memory_free fn os_memory_free() -> !u64 Available physical RAM in bytes (snapshot; best-effort on macOS/BSD).
os_uptime_secs fn os_uptime_secs() -> !u64 Seconds since system boot.
os_loadavg_1m fn os_loadavg_1m() -> !f64 1-minute load average. POSIX-only — Err on Windows.

A common use is sizing a worker pool from the CPU count while defaulting safely when the query fails:

import stdlib::os::*;

fn main() -> i32 {
    let cpus: !i32 = os_cpu_count();
    let workers: i32 = if cpus.ok { cpus.val } else { 1 };
    println!("spawning", workers, "workers");

    let phys: !i32 = os_cpu_count_physical();
    if phys.ok { println!("physical cores:", phys.val); }

    let pg: !i32 = os_page_size();
    if pg.ok { println!("page size:", pg.val, "bytes"); }

    let total: !u64 = os_memory_total();
    if total.ok { println!("RAM MiB :", (total.val / 1024 / 1024) as i32); }

    let free: !u64 = os_memory_free();
    if free.ok { println!("free MiB:", (free.val / 1024 / 1024) as i32); }

    let up: !u64 = os_uptime_secs();
    if up.ok { println!("uptime  :", (up.val / 3600) as i32, "h"); }

    let load: !f64 = os_loadavg_1m();      // Err on Windows
    if load.ok { println!("load 1m :", load.val); }
    else       { println!("load 1m :", load.err); }
    return 0;
}

Standard directories (platform-native)

Each returns a base directory; append your app name. Resolution differs per platform:

Function Signature Linux macOS Windows
os_temp_dir fn os_temp_dir() -> !string $TMPDIR or /tmp $TMPDIR or /tmp %TEMP%
os_home_dir fn os_home_dir() -> !string $HOME (fallback getpwuid) same %USERPROFILE%
os_config_dir fn os_config_dir() -> !string $XDG_CONFIG_HOME or ~/.config ~/Library/Application Support %APPDATA%
os_cache_dir fn os_cache_dir() -> !string $XDG_CACHE_HOME or ~/.cache ~/Library/Caches %LOCALAPPDATA%
os_data_dir fn os_data_dir() -> !string $XDG_DATA_HOME or ~/.local/share ~/Library/Application Support %APPDATA%
import stdlib::os::*;

fn main() -> i32 {
    let tmp: !string = os_temp_dir();
    if tmp.ok { println!("temp:", tmp.val); }

    let home: !string = os_home_dir();
    if home.ok { println!("home:", home.val); }

    let cfg: !string = os_config_dir();
    if cfg.ok { println!("config:", cfg.val); }

    let cache: !string = os_cache_dir();
    if cache.ok { println!("cache:", cache.val); }

    let data: !string = os_data_dir();
    if data.ok { println!("data:", data.val); }

    return 0;
}

A reusable per-app path helper

Wrap the base-dir lookup behind a function that returns !string and propagate the error with ? — the caller gets one clean Result:

import stdlib::os::*;

fn config_path(app: string, file: string) -> !string {
    let base: string = os_config_dir()?;          // propagate Err
    return ok(format!("{}{}{}{}{}", base, os_path_sep(), app, os_path_sep(), file));
}

fn main() -> i32 {
    let p: !string = config_path("myapp", "settings.toml");
    if p.ok { println!("config at:", p.val); }
    else     { println!("could not resolve config dir:", p.err); }
    return 0;
}

IO state

os_is_tty

fn os_is_tty(fd: i32) -> bool

true if the file descriptor is a terminal. fd: 0 = stdin, 1 = stdout, 2 = stderr. Use it before emitting ANSI color escapes — output piped to a file or another process should stay plain:

import stdlib::os::*;

fn paint(msg: string) -> string {
    if os_is_tty(1) { return format!("\x1b[32m{}\x1b[0m", msg); }
    return msg;
}

fn main() -> i32 {
    println!(paint("build succeeded"));
    if !os_is_tty(0) { println!("(stdin is not interactive)"); }
    return 0;
}

Subprocess quick — one-liner shell escape

os_shell

fn os_shell(cmd: string) -> !i32

Runs cmd through the OS shell (cmd /c on Windows, /bin/sh -c elsewhere). Returns Ok(exit_code) (0 = success) or Err only if the shell itself failed to launch. Output streams are inherited; capturing output requires shell-level redirection inside cmd.

import stdlib::os::*;

fn main() -> i32 {
    let r: !i32 = os_shell("exit 3");
    if r.ok {
        if r.val == 0 { println!("command succeeded"); }
        else          { println!("command exited non-zero:", r.val); }
    } else {
        println!("shell did not spawn:", r.err);
    }
    return 0;
}

See also

  • stdlib::env — command-line args, environment variable get/set, and exit.
  • stdlib::fs — reading/writing files and creating the app directories resolved here.
  • stdlib::io — the stdin/stdout/stderr handles gated by os_is_tty.
  • stdlib::process — the full Command builder that os_shell is a shortcut for.