use std::sync::{LazyLock, Once, OnceLock};
use libc::c_ulong;
use libseccomp::ScmpArch;
use crate::hash::SydHashMap;
pub type Ioctl = c_ulong;
pub type IoctlList = &'static [(&'static str, Ioctl)];
include!("ioctl/ioctls_aarch64.rs");
include!("ioctl/ioctls_arm.rs");
include!("ioctl/ioctls_loongarch64.rs");
include!("ioctl/ioctls_m68k.rs");
include!("ioctl/ioctls_mips.rs");
include!("ioctl/ioctls_mips64.rs");
include!("ioctl/ioctls_mips64n32.rs");
include!("ioctl/ioctls_mipsel.rs");
include!("ioctl/ioctls_mipsel64.rs");
include!("ioctl/ioctls_mipsel64n32.rs");
include!("ioctl/ioctls_ppc.rs");
include!("ioctl/ioctls_ppc64.rs");
include!("ioctl/ioctls_ppc64le.rs");
include!("ioctl/ioctls_riscv64.rs");
include!("ioctl/ioctls_s390.rs");
include!("ioctl/ioctls_s390x.rs");
include!("ioctl/ioctls_x32.rs");
include!("ioctl/ioctls_x86.rs");
include!("ioctl/ioctls_x8664.rs");
const ARCH_TABLES: &[(ScmpArch, IoctlList)] = &[
(ScmpArch::Aarch64, IOCTL_ARCH_AARCH64),
(ScmpArch::Arm, IOCTL_ARCH_ARM),
(ScmpArch::Loongarch64, IOCTL_ARCH_LOONGARCH64),
(ScmpArch::M68k, IOCTL_ARCH_M68K),
(ScmpArch::Mips, IOCTL_ARCH_MIPS),
(ScmpArch::Mips64, IOCTL_ARCH_MIPS64),
(ScmpArch::Mips64N32, IOCTL_ARCH_MIPS64N32),
(ScmpArch::Mipsel, IOCTL_ARCH_MIPSEL),
(ScmpArch::Mipsel64, IOCTL_ARCH_MIPSEL64),
(ScmpArch::Mipsel64N32, IOCTL_ARCH_MIPSEL64N32),
(ScmpArch::Ppc, IOCTL_ARCH_PPC),
(ScmpArch::Ppc64, IOCTL_ARCH_PPC64),
(ScmpArch::Ppc64Le, IOCTL_ARCH_PPC64LE),
(ScmpArch::Riscv64, IOCTL_ARCH_RISCV64),
(ScmpArch::S390, IOCTL_ARCH_S390),
(ScmpArch::S390X, IOCTL_ARCH_S390X),
(ScmpArch::X32, IOCTL_ARCH_X32),
(ScmpArch::X86, IOCTL_ARCH_X86),
(ScmpArch::X8664, IOCTL_ARCH_X8664),
];
pub type IoctlNamesMap = SydHashMap<Ioctl, Vec<&'static str>>;
pub type IoctlValueMap = SydHashMap<&'static str, Ioctl>;
type ArchNamesMap = SydHashMap<ScmpArch, IoctlNamesMap>;
type ArchValueMap = SydHashMap<ScmpArch, IoctlValueMap>;
static INIT: Once = Once::new();
static NAMES_MAP: OnceLock<ArchNamesMap> = OnceLock::new();
static VALUE_MAP: OnceLock<ArchValueMap> = OnceLock::new();
fn build_maps() -> (ArchNamesMap, ArchValueMap) {
let mut v2n_outer = ArchNamesMap::default();
let mut n2v_outer = ArchValueMap::default();
for &(arch, table) in ARCH_TABLES {
let v2n = v2n_outer.entry(arch).or_insert_with(IoctlNamesMap::default);
let n2v = n2v_outer.entry(arch).or_insert_with(IoctlValueMap::default);
for &(name, val) in table {
let val = Ioctl::from(val);
v2n.entry(val).or_default().push(name);
n2v.entry(name).or_insert(val);
}
for names in v2n.values_mut() {
names.sort_unstable();
names.dedup();
}
}
(v2n_outer, n2v_outer)
}
#[inline]
fn ensure_init() {
INIT.call_once(|| {
let (a, b) = build_maps();
let _ = NAMES_MAP.set(a);
let _ = VALUE_MAP.set(b);
});
}
pub fn ioctl_map_get(arch: ScmpArch) -> Option<IoctlNamesMap> {
ensure_init();
NAMES_MAP.get().and_then(|outer| outer.get(&arch)).cloned()
}
#[inline]
pub fn ioctl_names_get(value: Ioctl, arch: ScmpArch) -> Option<Vec<&'static str>> {
ensure_init();
NAMES_MAP
.get()
.and_then(|outer| outer.get(&arch))
.and_then(|inner| inner.get(&value))
.cloned()
}
#[inline]
pub fn ioctl_value_get(name: &str, arch: ScmpArch) -> Option<Ioctl> {
ensure_init();
VALUE_MAP
.get()
.and_then(|outer| outer.get(&arch))
.and_then(|inner| inner.get(name))
.copied()
}
pub static TCGETS2: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCGETS2", ScmpArch::native()));
pub static TCSETS2: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCSETS2", ScmpArch::native()));
pub static TCSETSW2: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCSETSW2", ScmpArch::native()));
pub static TCSETSF2: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCSETSF2", ScmpArch::native()));
pub static TCGETS: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCGETS", ScmpArch::native()));
pub static TCSETS: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCSETS", ScmpArch::native()));
pub static TCSETSW: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCSETSW", ScmpArch::native()));
pub static TCSETSF: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TCSETSF", ScmpArch::native()));
pub static TIOCGWINSZ: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCGWINSZ", ScmpArch::native()));
pub static TIOCSWINSZ: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCSWINSZ", ScmpArch::native()));
pub static TIOCGEXCL: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCGEXCL", ScmpArch::native()));
pub static TIOCEXCL: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCEXCL", ScmpArch::native()));
pub static TIOCNXCL: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCNXCL", ScmpArch::native()));
pub static TIOCSETD: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCSETD", ScmpArch::native()));
pub static TIOCSTI: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCSTI", ScmpArch::native()));
pub static TIOCCONS: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCCONS", ScmpArch::native()));
pub static TIOCLINUX: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCLINUX", ScmpArch::native()));
pub static TIOCGPTPEER: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("TIOCGPTPEER", ScmpArch::native()));
pub static FIOQSIZE: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("FIOQSIZE", ScmpArch::native()));
pub static FIFREEZE: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("FIFREEZE", ScmpArch::native()));
pub static FITHAW: LazyLock<Option<Ioctl>> =
LazyLock::new(|| ioctl_value_get("FITHAW", ScmpArch::native()));