syd 3.58.0

rock-solid application kernel
Documentation
//
// Syd: rock-solid application kernel
// src/utils/syd-uts.rs: Print name and information about the current kernel in JSON format
//
// Copyright (c) 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::process::ExitCode;

use nix::errno::Errno;
use syd::{cookie::safe_uname, printfln};
// Set global allocator to GrapheneOS allocator.
#[cfg(all(
    not(target_os = "android"),
    not(target_arch = "loongarch64"),
    not(target_arch = "riscv64"),
    target_page_size_4k,
    target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;

syd::main! {
    use lexopt::prelude::*;

    // Set SIGPIPE handler to default.
    syd::set_sigpipe_dfl()?;

    // Parse CLI options.
    //
    // Note, option parsing is POSIXly correct:
    // POSIX recommends that no more options are parsed after the first
    // positional argument. The other arguments are then all treated as
    // positional arguments.
    // See: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
    let mut opt_sysname = false;
    let mut opt_nodename = false;
    let mut opt_release = false;
    let mut opt_version = false;
    let mut opt_machine = false;
    let mut opt_domainname = false;

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') => {
                help()?;
                return Ok(ExitCode::SUCCESS);
            }
            Short('s') => opt_sysname = true,
            Short('n') => opt_nodename = true,
            Short('r') => opt_release = true,
            Short('v') => opt_version = true,
            Short('m') => opt_machine = true,
            Short('d') => opt_domainname = true,
            _ => return Err(arg.unexpected().into()),
        }
    }

    // Read UtsName using uname(2) syscall.
    let utsname = safe_uname()?;

    if !(opt_sysname || opt_nodename || opt_release || opt_version || opt_machine || opt_domainname) {
        // No specific fields requested:
        // Print the whole struct as line-oriented JSON.
        let status = serde_json::to_string(&utsname).or(Err(Errno::EINVAL))?;
        printfln!("{status}")?;
        return Ok(ExitCode::SUCCESS);
    }

    // Collect chosen fields and print them dot-separated in order.
    //
    // SAFETY: Unsafe paths are hex-encoded.
    let mut items: Vec<String> = Vec::with_capacity(6);
    if opt_sysname {
        items.push(utsname.sysname().to_string());
    }
    if opt_nodename {
        items.push(utsname.nodename().to_string());
    }
    if opt_release {
        items.push(utsname.release().to_string());
    }
    if opt_version {
        items.push(utsname.version().to_string());
    }
    if opt_machine {
        items.push(utsname.machine().to_string());
    }
    if opt_domainname {
        items.push(utsname.domainname().to_string());
    }
    printfln!("{}", items.join("."))?;

    Ok(ExitCode::SUCCESS)
}

fn help() -> Result<(), Errno> {
    printfln!("Usage: syd-uts [-hdmnrsv]")?;
    printfln!("Print name and information about the current kernel in JSON format.")?;
    printfln!("Use -s to print name of the operating system implementation.")?;
    printfln!("Use -n to print network name of this machine.")?;
    printfln!("Use -r to print release level of the operating system.")?;
    printfln!("Use -v to print version level of the operating system.")?;
    printfln!("Use -m to print machine hardware platform.")?;
    printfln!("Use -d to print NIS or YP domain name of this machine.")?;
    printfln!("Given more than one of -s,-n,-r,-v,-m,-d prints items separated by dot.")?;
    Ok(())
}