//
// Syd: rock-solid application kernel
// src/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, err::SydResult};

fn main() -> SydResult<ExitCode> {
    use lexopt::prelude::*;

    syd::set_sigpipe_dfl()?;

    // Parse CLI options.
    let mut parser = lexopt::Parser::from_env();
    #[allow(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();
        for cap in syd::caps::all() {
            #[allow(clippy::disallowed_methods)]
            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));
    }

    #[allow(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.");
}
