use std::{os::fd::RawFd, sync::LazyLock};
use serde::ser::{Serialize, SerializeMap, Serializer};
use crate::{
hash::SydHashMap,
path::PATH_MAX,
sandbox::{Version, ACTION_STR, SANDBOX_CAPS},
};
pub static API_SPEC: LazyLock<Api> = LazyLock::new(|| Api {
root: "/dev/syd".into(),
version: crate::config::API_VERSION,
methods: vec![
Method {
name: "check".into(),
desc: "Check if syd(2) API is available".into(),
..Default::default()
},
Method {
name: "panic".into(),
desc: "Exit immediately with code 127".into(),
path: Some("panic".into()),
..Default::default()
},
Method {
name: "reset".into(),
desc: "Reset sandboxing to the default state".into(),
path: Some("reset".into()),
..Default::default()
},
Method {
name: "ghost".into(),
desc: "Initiate Ghost mode".into(),
path: Some("ghost".into()),
..Default::default()
},
Method {
name: "load".into(),
desc: "Read configuration from the given file descriptor or builtin profile".into(),
path: Some("load".into()),
argv: Some(vec![Arg::FileDes, Arg::Profile]),
argc: Some(vec![1]),
..Default::default()
},
Method {
name: "lock".into(),
desc: "Set the state of the sandbox lock".into(),
path: Some("lock".into()),
argv: Some(vec![Arg::State]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "enabled".into(),
desc: "Check if sandboxing is enabled".into(),
path: Some("sandbox".into()),
base: Some(vec![Arg::Capability]),
op: Some(Operator::Query),
..Default::default()
},
Method {
name: "enable".into(),
desc: "Enable or disable sandboxing".into(),
path: Some("sandbox".into()),
base: Some(vec![Arg::Capability]),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "default".into(),
desc: "Set default action for sandboxing".into(),
path: Some("default".into()),
base: Some(vec![Arg::Capability]),
argv: Some(vec![Arg::Action]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "append_add".into(),
desc: "Add a pattern for append-only sandboxing".into(),
path: Some("append".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Append),
..Default::default()
},
Method {
name: "append_remove".into(),
desc: "Remove a pattern for append-only sandboxing".into(),
path: Some("append".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
..Default::default()
},
Method {
name: "append_clear".into(),
desc: "Remove all matching patterns for append-only sandboxing".into(),
path: Some("append".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Clear),
..Default::default()
},
Method {
name: "block_add".into(),
desc: "Add an IP network to the blocklist".into(),
path: Some("block".into()),
argv: Some(vec![Arg::Cidr]),
argc: Some(vec![1]),
op: Some(Operator::Append),
..Default::default()
},
Method {
name: "block_remove".into(),
desc: "Remove an IP network from the blocklist".into(),
path: Some("block".into()),
argv: Some(vec![Arg::Cidr]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
..Default::default()
},
Method {
name: "block_clear".into(),
desc: "Clear the blocklist".into(),
path: Some("block".into()),
op: Some(Operator::Clear),
..Default::default()
},
Method {
name: "block_merge".into(),
desc: "Aggregate the blocklist".into(),
path: Some("block".into()),
op: Some(Operator::Exec),
..Default::default()
},
Method {
name: "crypt_add".into(),
desc: "Add a pattern for Crypt sandboxing".into(),
path: Some("crypt".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Append),
..Default::default()
},
Method {
name: "crypt_remove".into(),
desc: "Remove a pattern for Crypt sandboxing".into(),
path: Some("crypt".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
..Default::default()
},
Method {
name: "crypt_clear".into(),
desc: "Remove all matching patterns for Crypt sandboxing".into(),
path: Some("crypt".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Clear),
..Default::default()
},
Method {
name: "force_add".into(),
desc: "Add an integrity rule for Force sandboxing".into(),
path: Some("force".into()),
argv: Some(vec![Arg::Path, Arg::Hash, Arg::Action]),
argc: Some(vec![2, 3]),
op: Some(Operator::Append),
exc: Some(
[("$action".into(), vec!["allow".into()])]
.into_iter()
.collect::<SydHashMap<_, _>>(),
),
..Default::default()
},
Method {
name: "force_remove".into(),
desc: "Remove an integrity rule for Force sandboxing".into(),
path: Some("force".into()),
argv: Some(vec![Arg::Path]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
..Default::default()
},
Method {
name: "force_clear".into(),
desc: "Remove all integrity rules for Force sandboxing".into(),
path: Some("force".into()),
op: Some(Operator::Clear),
..Default::default()
},
Method {
name: "ioctl_add".into(),
desc: "Add a request to the ioctl allowlist/denylist".into(),
path: Some("ioctl".into()),
base: Some(vec![Arg::Action]),
argv: Some(vec![Arg::U64]),
argc: Some(vec![1]),
op: Some(Operator::Append),
exc: Some(
[(
"$action".into(),
vec![
"abort".into(),
"exit".into(),
"filter".into(),
"kill".into(),
"panic".into(),
"stop".into(),
"warn".into(),
],
)]
.into_iter()
.collect::<SydHashMap<_, _>>(),
),
..Default::default()
},
Method {
name: "ioctl_remove".into(),
desc: "Remove a request from the ioctl allowlist/denylist".into(),
path: Some("ioctl".into()),
base: Some(vec![Arg::Action]),
argv: Some(vec![Arg::U64]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
exc: Some(
[(
"$action".into(),
vec![
"abort".into(),
"exit".into(),
"filter".into(),
"kill".into(),
"panic".into(),
"stop".into(),
"warn".into(),
],
)]
.into_iter()
.collect::<SydHashMap<_, _>>(),
),
..Default::default()
},
Method {
name: "rule_add".into(),
desc: "Add an access control rule for sandboxing".into(),
base: Some(vec![Arg::Action, Arg::Capability]),
argv: Some(vec![Arg::Rule]),
argc: Some(vec![1]),
op: Some(Operator::Append),
exc: Some(
[(
"$caps".into(),
vec![
"crypt".into(),
"force".into(),
"lock".into(),
"mem".into(),
"pid".into(),
"proxy".into(),
"pty".into(),
"tpe".into(),
],
)]
.into_iter()
.collect::<SydHashMap<_, _>>(),
),
..Default::default()
},
Method {
name: "rule_remove".into(),
desc: "Remove an access control rule for sandboxing".into(),
base: Some(vec![Arg::Action, Arg::Capability]),
argv: Some(vec![Arg::Rule]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
exc: Some(
[(
"$caps".into(),
vec![
"crypt".into(),
"force".into(),
"lock".into(),
"mem".into(),
"pid".into(),
"proxy".into(),
"pty".into(),
"tpe".into(),
],
)]
.into_iter()
.collect::<SydHashMap<_, _>>(),
),
..Default::default()
},
Method {
name: "rule_clear".into(),
desc: "Remove all matching access control rules for sandboxing".into(),
base: Some(vec![Arg::Action, Arg::Capability]),
argv: Some(vec![Arg::Rule]),
argc: Some(vec![1]),
op: Some(Operator::Clear),
exc: Some(
[(
"$caps".into(),
vec![
"crypt".into(),
"force".into(),
"lock".into(),
"mem".into(),
"pid".into(),
"proxy".into(),
"pty".into(),
"tpe".into(),
],
)]
.into_iter()
.collect::<SydHashMap<_, _>>(),
),
..Default::default()
},
Method {
name: "mask_add".into(),
desc: "Add a mask pattern for Read and Write sandboxing".into(),
path: Some("mask".into()),
argv: Some(vec![Arg::Glob, Arg::Path]),
argc: Some(vec![1, 2]),
op: Some(Operator::Append),
..Default::default()
},
Method {
name: "mask_remove".into(),
desc: "Remove a mask pattern for Read and Write sandboxing".into(),
path: Some("mask".into()),
argv: Some(vec![Arg::Glob]),
argc: Some(vec![1]),
op: Some(Operator::Remove),
..Default::default()
},
Method {
name: "mask_clear".into(),
desc: "Removes all mask patterns for Read and Write sandboxing".into(),
path: Some("mask".into()),
op: Some(Operator::Clear),
..Default::default()
},
Method {
name: "mem_max".into(),
desc: "Set maximum per-process memory usage limit for Memory sandboxing".into(),
path: Some("mem/max".into()),
argv: Some(vec![Arg::Hsize]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "mem_vm_max".into(),
desc: "Set maximum per-process virtual memory usage limit for Memory sandboxing".into(),
path: Some("mem/vm_max".into()),
argv: Some(vec![Arg::Hsize]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "pid_max".into(),
desc: "Set maximum process ID limit for PID sandboxing".into(),
path: Some("pid/max".into()),
argv: Some(vec![Arg::Usize]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "segvguard_expiry".into(),
desc: "Set SegvGuard entry expiry timeout in seconds, 0 disables SegvGuard".into(),
path: Some("segvguard/expiry".into()),
argv: Some(vec![Arg::U64]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "segvguard_timeout".into(),
desc: "Set SegvGuard entry suspension timeout in seconds".into(),
path: Some("segvguard/suspension".into()),
argv: Some(vec![Arg::U64]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "segvguard_maxcrashes".into(),
desc: "Set SegvGuard max number of crashes before suspension".into(),
path: Some("segvguard/maxcrashes".into()),
argv: Some(vec![Arg::U8]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "tpe_gid".into(),
desc: "Specify untrusted GID for Trusted Path Execution".into(),
path: Some("tpe/gid".into()),
argv: Some(vec![Arg::Gid, Arg::None]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "tpe_negate".into(),
desc: "Negate GID logic for Trusted Path Execution".into(),
path: Some("tpe/negate".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "tpe_root_owned".into(),
desc: "Ensure directory is root-owned for Trusted Path Execution".into(),
path: Some("tpe/root_owned".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "tpe_user_owned".into(),
desc: "Ensure directory is user-owned or root-owned for Trusted Path Execution".into(),
path: Some("tpe/user_owned".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "cmd_exec".into(),
desc: "Execute a command outside the sandbox".into(),
path: Some("cmd/exec".into()),
argv: Some(vec![Arg::String]),
argc: Some(vec![-1]),
args: Some("\x1F".into()),
op: Some(Operator::Exec),
..Default::default()
},
Method {
name: "allow_unsafe_filename".into(),
desc: "Allow unsafe characters in filenames".into(),
path: Some("trace/allow_unsafe_filename".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_hardlinks".into(),
desc: "Allow unsafe access to hardlinks".into(),
path: Some("trace/allow_unsafe_hardlinks".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_proc_pid_status".into(),
desc: "Allow unfiltered access to proc_pid_status(5)".into(),
path: Some("trace/allow_unsafe_proc_pid_status".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_magiclinks".into(),
desc: "Allow unsafe access to procfs magiclinks".into(),
path: Some("trace/allow_unsafe_magiclinks".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_nopie".into(),
desc: "Allow unsafe execution of non-PIE binaries".into(),
path: Some("trace/allow_unsafe_nopie".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_open_path".into(),
desc: "Allow unsafe continue of O_PATH opens".into(),
path: Some("trace/allow_unsafe_open_path".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_open_kfd".into(),
desc: "Allow unsafe continue of AMD KFD character device opens".into(),
path: Some("trace/allow_unsafe_open_kfd".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_xattr".into(),
desc: "Allow unsafe access to sensitive extensive attributes".into(),
path: Some("trace/allow_unsafe_open_xattr".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_safe_kcapi".into(),
desc: "Allow safe access to kernel cryptography API".into(),
path: Some("trace/allow_safe_kcapi".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsupp_socket".into(),
desc: "Allow access to unsupported socket families".into(),
path: Some("trace/allow_unsupp_socket".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "allow_unsafe_memfd".into(),
desc: "Allow unsafe access to memory file descriptors".into(),
path: Some("trace/allow_unsafe_memfd".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "deny_dotdot".into(),
desc: "Deny .. components in path resolution".into(),
path: Some("trace/deny_dotdot".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "deny_elf32".into(),
desc: "Deny execution of 32-bit ELF binaries".into(),
path: Some("trace/deny_elf32".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "deny_elf_dynamic".into(),
desc: "Deny execution of dynamically linked ELF binaries".into(),
path: Some("trace/deny_elf_dynamic".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "deny_elf_static".into(),
desc: "Deny execution of statically linked ELF binaries".into(),
path: Some("trace/deny_elf_static".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "deny_script".into(),
desc: "Deny execution of scripts".into(),
path: Some("trace/deny_script".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "force_cloexec".into(),
desc: "Force O_CLOEXEC flag on file descriptors".into(),
path: Some("trace/force_cloexec".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "force_rand_fd".into(),
desc: "Force randomized file descriptors".into(),
path: Some("trace/force_rand_fd".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "force_ro_open".into(),
desc: "Deny creating and writing opens".into(),
path: Some("trace/force_ro_open".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "force_no_xdev".into(),
desc: "Force RESOLVE_NO_XDEV at open(2) boundary".into(),
path: Some("trace/force_no_xdev".into()),
argv: Some(vec![Arg::Boolean]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
Method {
name: "force_umask".into(),
desc: "Force given umask mode, -1 to unset".into(),
path: Some("trace/force_umask".into()),
argv: Some(vec![Arg::Mode, Arg::MinusOne]),
argc: Some(vec![1]),
op: Some(Operator::Set),
..Default::default()
},
],
types: vec![
Type {
name: "$str".into(),
desc: "UTF-8 encoded string".into(),
fmt: Some("utf-8".into()),
..Default::default()
},
Type {
name: "$bool".into(),
desc: "Boolean".into(),
enums: Some(vec!["true".into(), "false".into()]),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$u8".into(),
desc: "8-bit unsigned integer".into(),
fmt: Some("int".into()),
limit: Some((u64::from(u8::MIN), u64::from(u8::MAX))),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$usize".into(),
desc: "Pointer-sized unsigned integer".into(),
fmt: Some("int".into()),
limit: Some((usize::MIN as u64, usize::MAX as u64)),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$u64".into(),
desc: "64-bit unsigned integer".into(),
fmt: Some("int".into()),
limit: Some((u64::MIN, u64::MAX)),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$uid".into(),
desc: "User ID type (unsigned integer)".into(),
fmt: Some("int".into()),
limit: Some((u64::from(libc::uid_t::MIN), u64::from(libc::uid_t::MAX))),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$gid".into(),
desc: "Group ID type (unsigned integer)".into(),
fmt: Some("int".into()),
limit: Some((u64::from(libc::gid_t::MIN), u64::from(libc::gid_t::MAX))),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$mode".into(),
desc: "Mode in octal integer literal (base-8)".into(),
fmt: Some("oct".into()),
limit: Some((u64::from(libc::mode_t::MIN), u64::from(libc::mode_t::MAX))),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$path".into(),
desc: "Absolute pathname".into(),
limit: Some((1, PATH_MAX as u64)),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$hsize".into(),
desc: "Human-formatted size".into(),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$state".into(),
desc: "Sandbox lock state".into(),
enums: Some(vec!["on".into(), "off".into(), "exec".into(), "ipc".into()]),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$action".into(),
desc: "Sandbox action".into(),
enums: Some(ACTION_STR.iter().map(|p| p.to_string()).collect::<Vec<_>>()),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$caps".into(),
desc: "Sandbox capabilities".into(),
enums: Some(
SANDBOX_CAPS
.keys()
.map(|p| p.to_string())
.collect::<Vec<_>>(),
),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$cidr".into(),
desc: "CIDR pattern for IP blocklist".into(),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$glob".into(),
desc: "Glob pattern, see PATTERN MATCHING in syd(2)".into(),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$addr".into(),
desc: "Address pattern, see ADDRESS MATCHING in syd(2)".into(),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$rule".into(),
desc: "Sandbox rule".into(),
impls: Some(vec!["$glob".into(), "$addr".into()]),
..Default::default()
},
Type {
name: "$filedes".into(),
desc: "File descriptor".into(),
limit: Some((0, RawFd::MAX as u64)),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$profile".into(),
desc: "Sandbox profile".into(),
enums: Some(vec![
"container".into(),
"core".into(),
"debug".into(),
"enforce".into(),
"ff".into(),
"firefox".into(),
"immutable".into(),
"kvm".into(),
"kvm_native".into(),
"landlock".into(),
"lib".into(),
"linux".into(),
"noipv4".into(),
"noipv6".into(),
"nomem".into(),
"nopie".into(),
"oci".into(),
"off".into(),
"paludis".into(),
"privileged".into(),
"quiet".into(),
"readonly".into(),
"ro".into(),
"silent".into(),
"trace".into(),
"tty".into(),
"tty_native".into(),
"user".into(),
]),
impls: Some(vec!["$str".into()]),
..Default::default()
},
Type {
name: "$hash".into(),
desc: "Hexadecimal file checksum".into(),
impls: Some(vec![
"$crc32".into(),
"$crc64".into(),
"$md5".into(),
"$sha1".into(),
"$sha3_256".into(),
"$sha3_384".into(),
"$sha3_512".into(),
]),
..Default::default()
},
Type {
name: "$crc32".into(),
desc: "Hexadecimal CRC32 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((8, 8)),
..Default::default()
},
Type {
name: "$crc64".into(),
desc: "Hexadecimal CRC64 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((16, 16)),
..Default::default()
},
Type {
name: "$md5".into(),
desc: "Hexadecimal MD5 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((32, 32)),
..Default::default()
},
Type {
name: "$sha1".into(),
desc: "Hexadecimal SHA1 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((40, 40)),
..Default::default()
},
Type {
name: "$sha3_256".into(),
desc: "Hexadecimal SHA3-256 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((64, 64)),
..Default::default()
},
Type {
name: "$sha3_384".into(),
desc: "Hexadecimal SHA3-384 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((96, 96)),
..Default::default()
},
Type {
name: "$sha3_512".into(),
desc: "Hexadecimal SHA3-512 checksum".into(),
fmt: Some("hex".into()),
impls: Some(vec!["$str".into()]),
limit: Some((128, 128)),
..Default::default()
},
],
});
pub struct Api {
root: String,
version: Version,
methods: Vec<Method>,
types: Vec<Type>,
}
impl Serialize for Api {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("root", &self.root)?;
map.serialize_entry("version", &self.version)?;
map.serialize_entry("methods", &self.methods)?;
map.serialize_entry("types", &self.types)?;
map.end()
}
}
#[derive(Debug, Default)]
struct Method {
name: String,
desc: String,
op: Option<Operator>,
path: Option<String>,
base: Option<Vec<Arg>>,
argc: Option<Vec<i8>>,
argv: Option<Vec<Arg>>,
args: Option<String>,
exc: Option<SydHashMap<String, Vec<String>>>,
}
impl Serialize for Method {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(6))?;
map.serialize_entry("name", &self.name)?;
map.serialize_entry("desc", &self.desc)?;
if let Some(ref path) = self.path {
map.serialize_entry("path", path)?;
}
if let Some(ref base) = self.base {
if base.len() == 1 {
map.serialize_entry("base", &base[0])?;
} else {
map.serialize_entry("base", base)?;
}
}
if let Some(ref argv) = self.argv {
if argv.len() == 1 {
map.serialize_entry("argv", &argv[0])?;
} else {
map.serialize_entry("argv", argv)?;
}
}
if let Some(ref argc) = self.argc {
if argc.len() == 1 {
map.serialize_entry("argc", &argc[0])?;
} else {
map.serialize_entry("argc", argc)?;
}
}
if let Some(ref args) = self.args {
map.serialize_entry("args", args)?;
}
if let Some(ref op) = self.op {
map.serialize_entry("op", op)?;
}
if let Some(ref exc) = self.exc {
map.serialize_entry("exc", exc)?;
}
map.end()
}
}
#[derive(Debug, Default)]
struct Type {
name: String,
desc: String,
fmt: Option<String>,
enums: Option<Vec<String>>,
impls: Option<Vec<String>>,
limit: Option<(u64, u64)>,
}
impl Serialize for Type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(5))?;
map.serialize_entry("name", &self.name)?;
map.serialize_entry("desc", &self.desc)?;
if let Some((min, max)) = self.limit {
map.serialize_entry("min", &min)?;
map.serialize_entry("max", &max)?;
}
if let Some(ref fmt) = self.fmt {
map.serialize_entry("fmt", fmt)?;
}
if let Some(ref enums) = self.enums {
if enums.len() == 1 {
map.serialize_entry("enum", &enums[0])?;
} else {
map.serialize_entry("enum", enums)?;
}
}
if let Some(ref impls) = self.impls {
if impls.len() == 1 {
map.serialize_entry("impl", &impls[0])?;
} else {
map.serialize_entry("impl", impls)?;
}
}
map.end()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Operator {
Set, Query, Append, Remove, Clear, Exec, }
impl Serialize for Operator {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
Self::Set => ":",
Self::Query => "?",
Self::Append => "+",
Self::Remove => "-",
Self::Clear => "^",
Self::Exec => "!",
};
serializer.serialize_str(s)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Arg {
MinusOne, None, Glob, Cidr, Path, String, U64, Usize, U8, Gid, Hsize, Mode, Boolean, Hash, Action, Capability, Rule, State, FileDes, Profile, }
impl Serialize for Arg {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::MinusOne => serializer.serialize_str("-1"),
Self::None => serializer.serialize_str("none"),
Self::Glob => serializer.serialize_str("$glob"),
Self::Cidr => serializer.serialize_str("$cidr"),
Self::Path => serializer.serialize_str("$path"),
Self::String => serializer.serialize_str("$str"),
Self::U64 => serializer.serialize_str("$u64"),
Self::Usize => serializer.serialize_str("$usize"),
Self::U8 => serializer.serialize_str("$u8"),
Self::Gid => serializer.serialize_str("$gid"),
Self::Hsize => serializer.serialize_str("$hsize"),
Self::Mode => serializer.serialize_str("$mode"),
Self::Boolean => serializer.serialize_str("$bool"),
Self::Hash => serializer.serialize_str("$hash"),
Self::Action => serializer.serialize_str("$action"),
Self::Capability => serializer.serialize_str("$caps"),
Self::Rule => serializer.serialize_str("$rule"),
Self::State => serializer.serialize_str("$state"),
Self::FileDes => serializer.serialize_str("$filedes"),
Self::Profile => serializer.serialize_str("$profile"),
}
}
}