//
// 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 syd::cookie::safe_uname;

// Set global allocator to GrapheneOS allocator.
#[cfg(all(
    not(coverage),
    not(feature = "prof"),
    not(target_os = "android"),
    target_page_size_4k,
    target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;

// Set global allocator to tcmalloc if profiling is enabled.
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;

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.
        #[expect(clippy::disallowed_methods)]
        let status = serde_json::to_string(&utsname).expect("JSON");
        println!("{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());
    }
    println!("{}", items.join("."));

    Ok(ExitCode::SUCCESS)
}

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