pub mod logger;
pub mod prctl;
mod channel;
mod clone;
mod error;
pub use channel::{Channel, Message};
pub use clone::Clone3;
pub use error::OzonecErr;
use std::{
fs::create_dir_all,
mem,
os::unix::io::{AsRawFd, RawFd},
path::{Path, PathBuf},
};
use anyhow::{bail, Context, Result};
use nix::{
errno::errno,
fcntl::{open, OFlag},
sys::stat::Mode,
NixPath,
};
struct OpenHow(libc::open_how);
bitflags::bitflags! {
struct ResolveFlag: libc::c_ulonglong {
const RESOLVE_BENEATH = libc::RESOLVE_BENEATH;
const RESOLVE_IN_ROOT = libc::RESOLVE_IN_ROOT;
const RESOLVE_NO_MAGICLINKS = libc::RESOLVE_NO_MAGICLINKS;
const RESOLVE_NO_SYMLINKS = libc::RESOLVE_NO_SYMLINKS;
const RESOLVE_NO_XDEV = libc::RESOLVE_NO_XDEV;
}
}
impl OpenHow {
fn new() -> Self {
unsafe { mem::zeroed() }
}
fn flags(mut self, flags: OFlag) -> Self {
let flags = flags.bits() as libc::c_ulonglong;
self.0.flags = flags;
self
}
fn mode(mut self, mode: Mode) -> Self {
let mode = mode.bits() as libc::c_ulonglong;
self.0.mode = mode;
self
}
fn resolve(mut self, resolve: ResolveFlag) -> Self {
let resolve = resolve.bits() as libc::c_ulonglong;
self.0.resolve = resolve;
self
}
}
pub fn openat2_in_root(root: &Path, target: &Path, is_dir: bool) -> Result<RawFd> {
let mut flags = OFlag::O_CLOEXEC;
let mode;
if is_dir {
flags |= OFlag::O_DIRECTORY | OFlag::O_PATH;
mode = Mode::empty();
create_dir_all(root.join(target))
.with_context(|| OzonecErr::CreateDir(target.to_string_lossy().to_string()))?;
} else {
flags |= OFlag::O_CREAT;
mode = Mode::S_IRWXU;
};
let mut open_how = OpenHow::new()
.flags(flags)
.mode(mode)
.resolve(ResolveFlag::RESOLVE_IN_ROOT);
let dirfd = open(root, flags & !OFlag::O_CREAT, Mode::empty())
.with_context(|| OzonecErr::OpenFile(root.to_string_lossy().to_string()))?;
let fd = target
.with_nix_path(|p| unsafe {
libc::syscall(
libc::SYS_openat2,
dirfd.as_raw_fd(),
p.as_ptr(),
&mut open_how as *mut OpenHow,
mem::size_of::<libc::open_how>(),
)
})
.with_context(|| "with_nix_path error")?;
if fd < 0 {
bail!(
"openat2 {} error with RESOLVE_IN_ROOT: {}",
target.display(),
errno()
);
}
Ok(RawFd::try_from(fd)?)
}
pub fn proc_fd_path(dirfd: RawFd) -> PathBuf {
PathBuf::from(format!("/proc/self/fd/{}", dirfd))
}