diff --git a/Cargo.toml b/Cargo.toml index 59c391fb..75f5ffd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ async-trait = { version = "0.1", optional = true } tokio = { version = "1.48.0", features = ["rt", "rt-multi-thread"], optional = true } zerocopy = { version = "0.8", features = ["derive"] } nix = { version = "0.30.0", features = ["fs", "user", "poll", "socket", "uio", "mount", "process", "ioctl"] } +lazy_static = "1.5.0" [dev-dependencies] env_logger = "0.11.7" diff --git a/src/mnt/mount_options.rs b/src/mnt/mount_options.rs index 3ab2e0f0..92c24b1f 100644 --- a/src/mnt/mount_options.rs +++ b/src/mnt/mount_options.rs @@ -1,11 +1,21 @@ use std::collections::HashSet; +use std::fmt::Debug; use std::io; use std::io::ErrorKind; +use std::sync::Arc; use crate::SessionACL; +fn default_thread_name_fn(i: usize) -> String { + format!("fuser-{i}") +} + +lazy_static::lazy_static! { + static ref DEFAULT_THREAD_NAME_FN: Arc String + Sync + Send> = Arc::new(default_thread_name_fn); +} + /// Fuser session configuration, including mount options. -#[derive(Debug, Clone, Default, Eq, PartialEq)] +#[derive(Clone)] #[non_exhaustive] pub struct Config { /// Mount options. @@ -18,6 +28,78 @@ pub struct Config { /// This enables more efficient request processing /// when multiple threads are used. Requires Linux 4.5+. pub clone_fd: bool, + /// Use custom thread naming for internal threads + pub thread_name_fn: Arc String + Sync + Send>, +} + +impl Debug for Config { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Config") + .field("mount_options", &self.mount_options) + .field("acl", &self.acl) + .field("n_threads", &self.n_threads) + .field("clone_fd", &self.clone_fd) + .finish() + } +} + +impl Default for Config { + fn default() -> Self { + Self { + mount_options: Vec::default(), + acl: SessionACL::default(), + n_threads: None, + clone_fd: false, + thread_name_fn: DEFAULT_THREAD_NAME_FN.clone(), + } + } +} + +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + self.mount_options == other.mount_options + && self.acl == other.acl + && self.n_threads == other.n_threads + && self.clone_fd == other.clone_fd + && Arc::ptr_eq(&self.thread_name_fn, &other.thread_name_fn) + } +} + +impl Eq for Config {} + +impl Config { + /// Create a new Config with default values. + pub fn new() -> Self { + Self::default() + } + + /// Set the mount options. + pub fn set_mount_options(&mut self, options: Vec) { + self.mount_options = options; + } + + /// Set the ACL. + pub fn set_acl(&mut self, acl: SessionACL) { + self.acl = acl; + } + + /// Set the number of threads. + pub fn set_n_threads(&mut self, n_threads: usize) { + self.n_threads = Some(n_threads); + } + + /// Set whether to use clone_fd. + pub fn set_clone_fd(&mut self, clone_fd: bool) { + self.clone_fd = clone_fd; + } + + /// Set the thread name function. + pub fn set_thread_name_fn( + &mut self, + thread_name_fn: Arc String + Sync + Send>, + ) { + self.thread_name_fn = thread_name_fn; + } } /// Mount options accepted by the FUSE filesystem type diff --git a/src/session.rs b/src/session.rs index 76261db3..06324417 100644 --- a/src/session.rs +++ b/src/session.rs @@ -291,9 +291,10 @@ impl Session { let mut threads = Vec::with_capacity(n_threads); for (i, ch) in channels.into_iter().enumerate() { - let thread_name = format!("fuser-{i}"); + let thread_name = (config.thread_name_fn)(i); + let thread_name_sanitized = thread_name.replace('\0', ""); let event_loop = SessionEventLoop { - thread_name: thread_name.clone(), + thread_name: thread_name_sanitized.clone(), filesystem: filesystem.clone(), ch, allowed, @@ -301,7 +302,7 @@ impl Session { }; threads.push( thread::Builder::new() - .name(thread_name) + .name(thread_name_sanitized) .spawn(move || event_loop.event_loop())?, ); }