Skip to main content

usb_gadget/function/
util.rs

1//! Utils for implementing USB gadget functions.
2
3use std::{
4    collections::HashMap,
5    ffi::{OsStr, OsString},
6    fmt, fs,
7    io::{Error, ErrorKind, Result},
8    os::unix::prelude::{OsStrExt, OsStringExt},
9    path::{Component, Path, PathBuf},
10    sync::{Arc, Mutex, MutexGuard, Once, OnceLock},
11};
12
13use crate::{function::register_remove_handlers, trim_os_str};
14
15/// USB gadget function.
16pub trait Function: fmt::Debug + Send + Sync + 'static {
17    /// Name of the function driver.
18    fn driver(&self) -> OsString;
19
20    /// Function directory.
21    fn dir(&self) -> FunctionDir;
22
23    /// Register the function in configfs at the specified path.
24    fn register(&self) -> Result<()>;
25
26    /// Notifies the function that the USB gadget is about to be removed.
27    fn pre_removal(&self) -> Result<()> {
28        Ok(())
29    }
30
31    /// Notifies the function that the USB gadget has been removed.
32    fn post_removal(&self, _dir: &Path) -> Result<()> {
33        Ok(())
34    }
35}
36
37/// USB function registration state.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
39pub enum State {
40    /// Function is not registered.
41    Unregistered,
42    /// Function is registered but not bound to UDC.
43    Registered,
44    /// Function is registered and bound to UDC.
45    Bound,
46    /// Function was removed and will stay in this state.
47    Removed,
48}
49
50/// Provides access to the status of a USB function.
51#[derive(Clone, Debug)]
52pub struct Status(FunctionDir);
53
54impl Status {
55    /// Registration state.
56    pub fn state(&self) -> State {
57        let inner = self.0.inner.lock().unwrap();
58        match (&inner.dir, inner.dir_was_set, inner.bound) {
59            (None, false, _) => State::Unregistered,
60            (None, true, _) => State::Removed,
61            (Some(_), _, false) => State::Registered,
62            (Some(_), _, true) => State::Bound,
63        }
64    }
65
66    /// Waits for the function to be bound to a UDC.
67    ///
68    /// Returns with a broken pipe error if gadget is removed.
69    #[cfg(feature = "tokio")]
70    pub async fn bound(&self) -> Result<()> {
71        loop {
72            let notifier = self.0.notify.notified();
73            match self.state() {
74                State::Bound => return Ok(()),
75                State::Removed => return Err(Error::new(ErrorKind::BrokenPipe, "gadget was removed")),
76                _ => (),
77            }
78            notifier.await;
79        }
80    }
81
82    /// Waits for the function to be unbound from a UDC.
83    #[cfg(feature = "tokio")]
84    pub async fn unbound(&self) {
85        loop {
86            let notifier = self.0.notify.notified();
87            if self.state() != State::Bound {
88                return;
89            }
90            notifier.await;
91        }
92    }
93
94    /// The USB gadget function directory in configfs, if registered.
95    pub fn path(&self) -> Option<PathBuf> {
96        self.0.inner.lock().unwrap().dir.clone()
97    }
98}
99
100/// USB gadget function directory container.
101///
102/// Stores the directory in configfs of a USB function and provides access methods.
103#[derive(Clone)]
104pub struct FunctionDir {
105    inner: Arc<Mutex<FunctionDirInner>>,
106    #[cfg(feature = "tokio")]
107    notify: Arc<tokio::sync::Notify>,
108}
109
110#[derive(Debug, Default)]
111struct FunctionDirInner {
112    dir: Option<PathBuf>,
113    dir_was_set: bool,
114    bound: bool,
115}
116
117impl fmt::Debug for FunctionDir {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        f.debug_tuple("FunctionDir").field(&*self.inner.lock().unwrap()).finish()
120    }
121}
122
123impl Default for FunctionDir {
124    fn default() -> Self {
125        Self::new()
126    }
127}
128
129impl FunctionDir {
130    /// Creates an empty function directory container.
131    pub fn new() -> Self {
132        Self {
133            inner: Arc::new(Mutex::new(FunctionDirInner::default())),
134            #[cfg(feature = "tokio")]
135            notify: Arc::new(tokio::sync::Notify::new()),
136        }
137    }
138
139    pub(crate) fn set_dir(&self, function_dir: &Path) {
140        let mut inner = self.inner.lock().unwrap();
141        inner.dir = Some(function_dir.to_path_buf());
142        inner.dir_was_set = true;
143
144        #[cfg(feature = "tokio")]
145        self.notify.notify_waiters();
146    }
147
148    pub(crate) fn reset_dir(&self) {
149        self.inner.lock().unwrap().dir = None;
150
151        #[cfg(feature = "tokio")]
152        self.notify.notify_waiters();
153    }
154
155    pub(crate) fn set_bound(&self, bound: bool) {
156        self.inner.lock().unwrap().bound = bound;
157
158        #[cfg(feature = "tokio")]
159        self.notify.notify_waiters();
160    }
161
162    /// Create status accessor.
163    pub fn status(&self) -> Status {
164        Status(self.clone())
165    }
166
167    /// The USB gadget function directory in configfs.
168    pub fn dir(&self) -> Result<PathBuf> {
169        self.inner
170            .lock()
171            .unwrap()
172            .dir
173            .clone()
174            .ok_or_else(|| Error::new(ErrorKind::NotFound, "USB function not registered"))
175    }
176
177    /// Driver name.
178    pub fn driver(&self) -> Result<OsString> {
179        let dir = self.dir()?;
180        let (driver, _instance) = split_function_dir(&dir)
181            .ok_or_else(|| Error::new(ErrorKind::InvalidData, "invalid function directory name"))?;
182        Ok(driver.to_os_string())
183    }
184
185    /// Instance name.
186    pub fn instance(&self) -> Result<OsString> {
187        let dir = self.dir()?;
188        let (_driver, instance) = split_function_dir(&dir)
189            .ok_or_else(|| Error::new(ErrorKind::InvalidData, "invalid function directory name"))?;
190        Ok(instance.to_os_string())
191    }
192
193    /// Path to the specified property.
194    pub fn property_path(&self, name: impl AsRef<Path>) -> Result<PathBuf> {
195        let path = name.as_ref();
196        if path.components().all(|c| matches!(c, Component::Normal(_))) {
197            Ok(self.dir()?.join(path))
198        } else {
199            Err(Error::new(ErrorKind::InvalidInput, "property path must be relative"))
200        }
201    }
202
203    /// Create a subdirectory.
204    pub fn create_dir(&self, name: impl AsRef<Path>) -> Result<()> {
205        let path = self.property_path(name)?;
206        log::debug!("creating directory {}", path.display());
207        fs::create_dir(path)
208    }
209
210    /// Create a subdirectory and its parent directories.
211    pub fn create_dir_all(&self, name: impl AsRef<Path>) -> Result<()> {
212        let path = self.property_path(name)?;
213        log::debug!("creating directories {}", path.display());
214        fs::create_dir_all(path)
215    }
216
217    /// Remove a subdirectory.
218    pub fn remove_dir(&self, name: impl AsRef<Path>) -> Result<()> {
219        let path = self.property_path(name)?;
220        log::debug!("removing directory {}", path.display());
221        fs::remove_dir(path)
222    }
223
224    /// Read a binary property.
225    pub fn read(&self, name: impl AsRef<Path>) -> Result<Vec<u8>> {
226        let path = self.property_path(name)?;
227        let res = fs::read(&path);
228
229        match &res {
230            Ok(value) => {
231                log::debug!("read property {} with value {}", path.display(), String::from_utf8_lossy(value))
232            }
233            Err(err) => log::debug!("reading property {} failed: {}", path.display(), err),
234        }
235
236        res
237    }
238
239    /// Read and trim a string property.
240    pub fn read_string(&self, name: impl AsRef<Path>) -> Result<String> {
241        let mut data = self.read(name)?;
242        while data.last() == Some(&b'\0') || data.last() == Some(&b' ') || data.last() == Some(&b'\n') {
243            data.truncate(data.len() - 1);
244        }
245
246        Ok(String::from_utf8(data).map_err(|err| Error::new(ErrorKind::InvalidData, err))?.trim().to_string())
247    }
248
249    /// Read an trim an OS string property.
250    pub fn read_os_string(&self, name: impl AsRef<Path>) -> Result<OsString> {
251        Ok(trim_os_str(&OsString::from_vec(self.read(name)?)).to_os_string())
252    }
253
254    /// Write a property.
255    ///
256    /// Fails with [`ErrorKind::Unsupported`] if the property is not supported by the kernel.
257    pub fn write(&self, name: impl AsRef<Path>, value: impl AsRef<[u8]>) -> Result<()> {
258        let path = self.property_path(name)?;
259        let value = value.as_ref();
260        log::debug!("setting property {} to {}", path.display(), String::from_utf8_lossy(value));
261        crate::write_attr(&path, value)
262    }
263
264    /// Create a symbolic link.
265    pub fn symlink(&self, target: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
266        let target = self.property_path(target)?;
267        let link = self.property_path(link)?;
268        log::debug!("creating symlink {} -> {}", link.display(), target.display());
269        std::os::unix::fs::symlink(target, link)
270    }
271
272    /// Device major and minor numbers.
273    ///
274    /// Reads the `dev` property from configfs, which contains the device
275    /// numbers in the `major:minor` format.
276    ///
277    /// Not all function types expose a `dev` property.
278    pub fn dev_numbers(&self) -> Result<(u32, u32)> {
279        let dev = self.read_string("dev")?;
280        let Some((major, minor)) = dev.split_once(':') else {
281            return Err(Error::new(ErrorKind::InvalidData, "invalid device number format"));
282        };
283        let major = major.parse().map_err(|err| Error::new(ErrorKind::InvalidData, err))?;
284        let minor = minor.parse().map_err(|err| Error::new(ErrorKind::InvalidData, err))?;
285        Ok((major, minor))
286    }
287
288    /// The device path in `/dev` that corresponds to this function.
289    ///
290    /// Not all function types expose a `dev` property.
291    pub fn dev_path(&self) -> Result<PathBuf> {
292        let (major, minor) = self.dev_numbers()?;
293        dev_path(major, minor)
294    }
295}
296
297/// Find the device path in `/dev` for the given major and minor numbers.
298///
299/// Scans `/dev` (non-recursively) for a character device with matching
300/// device numbers.
301pub fn dev_path(major: u32, minor: u32) -> Result<PathBuf> {
302    use std::os::{linux::fs::MetadataExt, unix::fs::FileTypeExt};
303
304    let target = rustix::fs::makedev(major, minor);
305
306    for entry in fs::read_dir("/dev")? {
307        let Ok(entry) = entry else { continue };
308        let Ok(meta) = entry.metadata() else { continue };
309        if meta.file_type().is_char_device() && meta.st_rdev() == target {
310            return Ok(entry.path());
311        }
312    }
313
314    Err(Error::new(ErrorKind::NotFound, format!("no device file found in /dev for {major}:{minor}")))
315}
316
317/// Split configfs function directory path into driver name and instance name.
318pub fn split_function_dir(function_dir: &Path) -> Option<(&OsStr, &OsStr)> {
319    let name = function_dir.file_name()?;
320    let name = name.as_bytes();
321
322    let dot = name.iter().enumerate().find_map(|(i, c)| if *c == b'.' { Some(i) } else { None })?;
323    let driver = &name[..dot];
324    let instance = &name[dot + 1..];
325
326    Some((OsStr::from_bytes(driver), OsStr::from_bytes(instance)))
327}
328
329/// Handler function for removing function instance.
330type RemoveHandler = Arc<dyn Fn(PathBuf) -> Result<()> + Send + Sync>;
331
332/// Registered handlers for removing function instances.
333static REMOVE_HANDLERS: OnceLock<Mutex<HashMap<OsString, RemoveHandler>>> = OnceLock::new();
334
335/// Registered handlers for removing function instances.
336fn remove_handlers() -> MutexGuard<'static, HashMap<OsString, RemoveHandler>> {
337    let handlers = REMOVE_HANDLERS.get_or_init(|| Mutex::new(HashMap::new()));
338    handlers.lock().unwrap()
339}
340
341/// Initializes handlers for removing function instances.
342pub(crate) fn init_remove_handlers() {
343    static ONCE: Once = Once::new();
344    ONCE.call_once(|| {
345        register_remove_handlers();
346    });
347}
348
349/// Register a function remove handler for the specified function driver.
350pub fn register_remove_handler(
351    driver: impl AsRef<OsStr>, handler: impl Fn(PathBuf) -> Result<()> + Send + Sync + 'static,
352) {
353    remove_handlers().insert(driver.as_ref().to_os_string(), Arc::new(handler));
354}
355
356/// Calls the remove handler for the function directory, if any is registered.
357pub(crate) fn call_remove_handler(function_dir: &Path) -> Result<()> {
358    let Some((driver, _)) = split_function_dir(function_dir) else {
359        return Err(Error::new(ErrorKind::InvalidInput, "invalid function directory"));
360    };
361
362    let handler_opt = remove_handlers().get(driver).cloned();
363    match handler_opt {
364        Some(handler) => handler(function_dir.to_path_buf()),
365        None => Ok(()),
366    }
367}
368
369/// Value channel.
370pub(crate) mod value {
371    use std::{
372        error::Error,
373        fmt,
374        fmt::Display,
375        io, mem,
376        sync::{mpsc, Mutex},
377    };
378
379    /// Value was already sent.
380    #[derive(Debug, Clone)]
381    pub struct AlreadySentError;
382
383    impl Display for AlreadySentError {
384        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
385            write!(f, "value already sent")
386        }
387    }
388
389    impl Error for AlreadySentError {}
390
391    /// Sender of value channel.
392    #[derive(Debug)]
393    pub struct Sender<T>(Mutex<Option<mpsc::Sender<T>>>);
394
395    impl<T> Sender<T> {
396        /// Sends a value.
397        ///
398        /// This can only be called once.
399        pub fn send(&self, value: T) -> Result<(), AlreadySentError> {
400            match self.0.lock().unwrap().take() {
401                Some(tx) => {
402                    let _ = tx.send(value);
403                    Ok(())
404                }
405                None => Err(AlreadySentError),
406            }
407        }
408    }
409
410    /// Value channel receive error.
411    #[derive(Debug, Clone)]
412    pub enum RecvError {
413        /// Value was not yet sent.
414        Empty,
415        /// Sender was dropped without sending a value.
416        Disconnected,
417        /// Value was taken.
418        Taken,
419    }
420
421    impl Display for RecvError {
422        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
423            match self {
424                RecvError::Empty => write!(f, "value was not yet sent"),
425                RecvError::Disconnected => write!(f, "no value was sent"),
426                RecvError::Taken => write!(f, "value was taken"),
427            }
428        }
429    }
430
431    impl Error for RecvError {}
432
433    impl From<mpsc::RecvError> for RecvError {
434        fn from(_err: mpsc::RecvError) -> Self {
435            Self::Disconnected
436        }
437    }
438
439    impl From<mpsc::TryRecvError> for RecvError {
440        fn from(err: mpsc::TryRecvError) -> Self {
441            match err {
442                mpsc::TryRecvError::Empty => Self::Empty,
443                mpsc::TryRecvError::Disconnected => Self::Disconnected,
444            }
445        }
446    }
447
448    impl From<RecvError> for io::Error {
449        fn from(err: RecvError) -> Self {
450            match err {
451                RecvError::Empty => io::Error::new(io::ErrorKind::WouldBlock, err),
452                RecvError::Disconnected => io::Error::new(io::ErrorKind::BrokenPipe, err),
453                RecvError::Taken => io::Error::other(err),
454            }
455        }
456    }
457
458    /// Receiver state.
459    #[derive(Default)]
460    enum State<T> {
461        Receiving(Mutex<mpsc::Receiver<T>>),
462        Received(T),
463        #[default]
464        Taken,
465    }
466
467    /// Receiver of value channel.
468    #[derive(Default)]
469    pub struct Receiver<T>(State<T>);
470
471    impl<T: fmt::Debug> fmt::Debug for Receiver<T> {
472        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
473            match &self.0 {
474                State::Receiving(_) => write!(f, "<uninit>"),
475                State::Received(v) => v.fmt(f),
476                State::Taken => write!(f, "<taken>"),
477            }
478        }
479    }
480
481    impl<T> Receiver<T> {
482        /// Get the value, if it has been sent.
483        pub fn get(&mut self) -> Result<&mut T, RecvError> {
484            match &mut self.0 {
485                State::Receiving(rx) => {
486                    let value = rx.get_mut().unwrap().try_recv()?;
487                    self.0 = State::Received(value);
488                }
489                State::Taken => return Err(RecvError::Taken),
490                _ => (),
491            }
492
493            let State::Received(value) = &mut self.0 else { unreachable!() };
494            Ok(value)
495        }
496
497        /// Wait for the value.
498        #[allow(dead_code)]
499        pub fn wait(&mut self) -> Result<&mut T, RecvError> {
500            if let State::Receiving(rx) = &mut self.0 {
501                let value = rx.get_mut().unwrap().recv()?;
502                self.0 = State::Received(value);
503            }
504
505            self.get()
506        }
507
508        /// Take the value, if it has been sent.
509        #[allow(dead_code)]
510        pub fn take(&mut self) -> Result<T, RecvError> {
511            self.get()?;
512
513            let State::Received(value) = mem::take(&mut self.0) else { unreachable!() };
514            Ok(value)
515        }
516    }
517
518    /// Creates a new value channel.
519    pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
520        let (tx, rx) = mpsc::channel();
521        (Sender(Mutex::new(Some(tx))), Receiver(State::Receiving(Mutex::new(rx))))
522    }
523}