sys_mount/
supported.rs

1// Copyright 2018-2022 System76 <info@system76.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use std::{
5    fs::File,
6    io::{self, BufRead, BufReader},
7};
8
9/// Data structure for validating if a filesystem argument is valid, and used within
10/// automatic file system mounting.
11#[derive(Clone, Debug)]
12#[allow(clippy::module_name_repetitions)]
13pub struct SupportedFilesystems {
14    nodev: Vec<bool>,
15    fs: Vec<String>,
16}
17
18impl SupportedFilesystems {
19    /// Detects available supported file systems on the system
20    ///
21    /// # Errors
22    ///
23    /// - On failure to open `/proc/filesystems`
24    pub fn new() -> io::Result<Self> {
25        let mut fss = Vec::with_capacity(64);
26        let mut nodevs = Vec::with_capacity(64);
27
28        for line in BufReader::new(File::open("/proc/filesystems")?).lines() {
29            let line = line?;
30            let mut line = line.split_whitespace();
31            let (nodev, fs) = match (line.next(), line.next()) {
32                (Some(fs), None) => (false, fs),
33                (Some("nodev"), Some(fs)) => (true, fs),
34                _ => continue,
35            };
36
37            nodevs.push(nodev);
38            fss.push(fs.to_owned());
39        }
40
41        Ok(SupportedFilesystems {
42            nodev: nodevs,
43            fs: fss,
44        })
45    }
46
47    /// Check if a provided file system is valid on this system.
48    ///
49    /// ```rust
50    /// extern crate sys_mount;
51    ///
52    /// use sys_mount::SupportedFilesystems;
53    ///
54    /// fn main() {
55    ///     let supports = SupportedFilesystems::new().unwrap();
56    ///     println!("btrfs is {}", if supports.is_supported("btrfs") {
57    ///         "supported"
58    ///     } else {
59    ///         "not supported"
60    ///     });
61    /// }
62    /// ```
63    #[must_use]
64    pub fn is_supported(&self, fs: &str) -> bool {
65        self.fs.iter().any(|s| s.as_str() == fs)
66    }
67
68    /// Iterate through file systems which are not associated with physical devices.
69    #[must_use]
70    pub fn nodev_file_systems<'a>(&'a self) -> Box<dyn Iterator<Item = &str> + 'a> {
71        // TODO: When we can, switch to `impl Iterator`.
72        let iter = self.nodev.iter().enumerate().filter_map(move |(id, &x)| {
73            if x {
74                Some(self.fs[id].as_str())
75            } else {
76                None
77            }
78        });
79
80        Box::new(iter)
81    }
82
83    /// Iterate through file systems which are associated with physical devices.
84    #[must_use]
85    pub fn dev_file_systems<'a>(&'a self) -> Box<dyn Iterator<Item = &str> + 'a> {
86        // TODO: When we can, switch to `impl Iterator`.
87        let iter = self.nodev.iter().enumerate().filter_map(move |(id, &x)| {
88            if x {
89                None
90            } else {
91                Some(self.fs[id].as_str())
92            }
93        });
94
95        Box::new(iter)
96    }
97}