use std::{
io,
os::{fd::AsFd, unix::io::AsRawFd},
};
use libc::u_long;
use crate::common::CapRights;
const CAP_IOCTLS_ALL: isize = isize::MAX;
#[derive(Clone, Debug, Default)]
pub struct IoctlsBuilder(Vec<u_long>);
impl IoctlsBuilder {
pub fn new() -> IoctlsBuilder {
IoctlsBuilder::default()
}
#[allow(missing_docs)]
#[allow(clippy::should_implement_trait)]
#[deprecated(since = "0.4.0", note = "use IoctlsBuilder::allow instead")]
pub fn add(self, right: u_long) -> Self {
self.allow(right)
}
pub fn allow(mut self, right: u_long) -> Self {
self.0.push(right);
self
}
#[allow(missing_docs)]
#[deprecated(
since = "0.4.0",
note = "If you still need this method, please file an issue at https://github.com/dlrobertson/capsicum-rs/issues"
)]
pub fn raw(&self) -> Vec<u_long> {
self.0.clone()
}
#[allow(missing_docs)]
#[deprecated(since = "0.4.0", note = "use IoctlsBuilder::allow instead")]
pub fn remove(self, right: u_long) -> Self {
self.deny(right)
}
pub fn deny(mut self, right: u_long) -> Self {
self.0.retain(|&item| item != right);
self
}
pub fn finalize(self) -> IoctlRights {
IoctlRights::Limited(self.0)
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub enum IoctlRights {
#[default]
Unlimited,
Limited(Vec<u_long>),
}
impl IoctlRights {
#[allow(missing_docs)]
#[deprecated(since = "0.4.0", note = "use IoctlsBuilder insted")]
pub fn new(rights: Vec<u_long>) -> IoctlRights {
IoctlRights::Limited(rights)
}
pub fn from_file<F: AsFd>(f: &F, len: usize) -> io::Result<IoctlRights> {
let mut cmds = Vec::with_capacity(len);
let fd = f.as_fd().as_raw_fd();
unsafe {
let res = libc::cap_ioctls_get(fd, cmds.as_mut_ptr(), len);
if res == CAP_IOCTLS_ALL {
Ok(IoctlRights::Unlimited)
} else if let Ok(rlen) = usize::try_from(res) {
if rlen > len {
panic!("cap_ioctls_get overflowed our buffer")
} else {
cmds.set_len(rlen);
Ok(IoctlRights::Limited(cmds))
}
} else {
Err(io::Error::last_os_error())
}
}
}
}
impl CapRights for IoctlRights {
fn limit<F: AsFd>(&self, f: &F) -> io::Result<()> {
if let IoctlRights::Limited(v) = self {
let len = v.len();
let fd = f.as_fd().as_raw_fd();
unsafe {
if libc::cap_ioctls_limit(fd, v.as_ptr(), len) < 0 {
return Err(io::Error::last_os_error());
}
}
}
Ok(())
}
}