//
// Syd: rock-solid application kernel
// src/utils/syd-cap.rs: Print information on Linux capabilities
//
// Copyright (c) 2024, 2025 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::process::ExitCode;

use serde_json::Map;
use syd::caps::CapSet;

// 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::*;

    syd::set_sigpipe_dfl()?;

    // Parse CLI options.
    let mut parser = lexopt::Parser::from_env();
    #[expect(clippy::never_loop)]
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') => {
                help();
                return Ok(ExitCode::SUCCESS);
            }
            _ => return Err(arg.unexpected().into()),
        }
    }

    let mut cap = Map::new();
    for set in [
        CapSet::Bounding,
        CapSet::Permitted,
        CapSet::Inheritable,
        CapSet::Ambient,
        CapSet::Effective,
    ] {
        let mut vec = Vec::new();

        #[expect(clippy::disallowed_methods)]
        for flag in syd::caps::Capabilities::all() {
            let cap: syd::caps::Capability = flag.try_into().unwrap();
            if syd::caps::has_cap(None, set, cap).expect("syd::caps::has_cap") {
                vec.push(serde_json::Value::String(cap.to_string()));
            }
        }
        cap.insert(set2name(set), serde_json::Value::Array(vec));
    }

    #[expect(clippy::disallowed_methods)]
    let cap = serde_json::to_string_pretty(&cap).unwrap();
    println!("{cap}");

    Ok(ExitCode::SUCCESS)
}

fn set2name(set: CapSet) -> String {
    match set {
        CapSet::Ambient => "ambient",
        CapSet::Bounding => "bounding",
        CapSet::Effective => "effective",
        CapSet::Inheritable => "inheritable",
        CapSet::Permitted => "permitted",
    }
    .to_string()
}

fn help() {
    println!("Usage: syd-cap [-h]");
    println!("Print information on Linux capabilities.");
}
