use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::{self, Write}; use std::path::PathBuf; use rustix::fs::{FileType, Mode, OFlags, ResolveFlags, fstat, openat2}; use crate::IgnoredWorkspace; use crate::filesystem::RouterConfiguration; pub const PRIVATE_ROUTER_ROLE: &str = "--lazaret-private-ignored-workspace-router-v1"; #[must_use] pub fn dispatch_private_router(arguments: &[OsString]) -> Option> { if arguments .first() .is_none_or(|argument| argument != PRIVATE_ROUTER_ROLE) { return None; } Some(parse(arguments).and_then(run)) } struct Arguments { workspace_fd: i32, workspace_label: PathBuf, isolated_fd: i32, mountpoint: PathBuf, global_excludes: Option, isolate_ignored: bool, threads: usize, } fn parse(arguments: &[OsString]) -> io::Result { let mut arguments = arguments.iter().skip(1); let workspace_fd = number(named(&mut arguments, "--workspace-fd")?)?; let workspace_label = PathBuf::from(named(&mut arguments, "--workspace-label")?); let isolated_fd = number(named(&mut arguments, "--isolated-fd")?)?; let mountpoint = PathBuf::from(named(&mut arguments, "--mountpoint")?); let global_excludes = match named(&mut arguments, "--global-excludes")? { value if value.is_empty() => None, value => Some(PathBuf::from(value)), }; let isolate_ignored = match named(&mut arguments, "--isolate-ignored")?.to_str() { Some("true") => true, Some("false") => false, _ => return Err(io::Error::other("router isolation mode is invalid")), }; let threads = number(named(&mut arguments, "--threads")?)?; if arguments.next().is_some() || threads == 0 { return Err(io::Error::other("router arguments are invalid")); } Ok(Arguments { workspace_fd, workspace_label, isolated_fd, mountpoint, global_excludes, isolate_ignored, threads, }) } fn run(arguments: Arguments) -> io::Result<()> { let workspace = inherited_exact_directory(arguments.workspace_fd, &arguments.workspace_label)?; let isolated = inherited(arguments.isolated_fd)?; IgnoredWorkspace::serve_from_authorities( RouterConfiguration { workspace_label: arguments.workspace_label, workspace, isolated_state: isolated, mountpoint: arguments.mountpoint, global_excludes: arguments.global_excludes, isolate_ignored: arguments.isolate_ignored, threads: arguments.threads, }, || { let mut output = io::stdout().lock(); output.write_all(b"ready\n")?; output.flush() }, ) } fn inherited_exact_directory(descriptor: i32, label: &std::path::Path) -> io::Result { let inherited = inherited(descriptor)?; let expected = fstat(&inherited)?; let reopened = File::from(openat2( rustix::fs::CWD, label, OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC | OFlags::NOFOLLOW, Mode::empty(), ResolveFlags::NO_MAGICLINKS | ResolveFlags::NO_SYMLINKS, )?); let observed = fstat(&reopened)?; if expected.st_dev != observed.st_dev || expected.st_ino != observed.st_ino || !FileType::from_raw_mode(observed.st_mode).is_dir() { return Err(io::Error::other( "namespace-local workspace differs from inherited authority", )); } Ok(reopened) } fn inherited(descriptor: i32) -> io::Result { if descriptor < 0 { return Err(io::Error::other("router descriptor is invalid")); } File::open(format!("/proc/self/fd/{descriptor}")) } fn named<'a>( arguments: &mut impl Iterator, name: &str, ) -> io::Result<&'a OsString> { if arguments.next().is_none_or(|argument| argument != name) { return Err(io::Error::other(format!( "router argument {name} is missing" ))); } arguments .next() .ok_or_else(|| io::Error::other(format!("router argument {name} has no value"))) } fn number(value: &OsStr) -> io::Result where T: std::str::FromStr, { value .to_str() .and_then(|value| value.parse().ok()) .ok_or_else(|| io::Error::other("router numeric argument is invalid")) } #[cfg(test)] mod tests { use super::*; #[test] fn exact_private_arguments_parse() { let arguments = valid_arguments(); let parsed = parse(&arguments).unwrap(); assert_eq!(parsed.workspace_fd, 3); assert_eq!(parsed.isolated_fd, 4); assert_eq!(parsed.threads, 2); assert!(parsed.isolate_ignored); } #[test] fn malformed_private_arguments_are_refused() { let mut extra = valid_arguments(); extra.push("unexpected".into()); assert!(parse(&extra).is_err()); let mut zero_threads = valid_arguments(); *zero_threads.last_mut().unwrap() = "0".into(); assert!(parse(&zero_threads).is_err()); let mut missing = valid_arguments(); missing.remove(2); assert!(parse(&missing).is_err()); } fn valid_arguments() -> Vec { [ PRIVATE_ROUTER_ROLE, "--workspace-fd", "3", "--workspace-label", "/workspace", "--isolated-fd", "4", "--mountpoint", "/runtime/workspace", "--global-excludes", "", "--isolate-ignored", "true", "--threads", "2", ] .into_iter() .map(OsString::from) .collect() } }