1use {
2 crate::*,
3 lazy_regex::*,
4 std::path::PathBuf,
5};
6
7static REMOTE_ONLY_FS_TYPES: &[&str] = &[
8 "afs",
9 "coda",
10 "auristorfs",
11 "fhgfs",
12 "gpfs",
13 "ibrix",
14 "ocfs2",
15 "vxfs",
16];
17
18pub type MountId = u32;
20
21#[derive(Debug, Clone)]
23pub struct MountInfo {
24 pub id: Option<MountId>,
25 pub parent: Option<MountId>,
26 pub dev: DeviceId,
27 pub root: PathBuf,
28 pub mount_point: PathBuf,
29 pub options: Vec<MountOption>,
30 pub fs: String, pub fs_type: String,
32 pub bound: bool,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub struct MountOption {
38 pub name: String,
39 pub value: Option<String>,
40}
41
42impl MountOption {
43 pub fn new<S: Into<String>>(
44 name: S,
45 value: Option<S>,
46 ) -> Self {
47 MountOption {
48 name: name.into(),
49 value: value.map(|s| s.into()),
50 }
51 }
52}
53
54impl MountInfo {
55 pub fn dm_name(&self) -> Option<&str> {
57 regex_captures!(r#"^/dev/mapper/([^/]+)$"#, &self.fs).map(|(_, dm_name)| dm_name)
58 }
59 pub fn fs_name(&self) -> Option<&str> {
61 regex_find!(r#"[^\\/]+$"#, &self.fs)
62 }
63 pub fn is_remote(&self) -> bool {
67 self.fs.contains(':')
68 || (self.fs.starts_with("//")
69 && ["cifs", "smb3", "smbfs"].contains(&self.fs_type.as_ref()))
70 || REMOTE_ONLY_FS_TYPES.contains(&self.fs_type.as_ref())
71 || self.fs == "-hosts"
72 }
73 pub fn options_string(&self) -> String {
76 let mut s = String::new();
77 let mut first = true;
78 for option in &self.options {
79 if !first {
80 s.push(',');
81 }
82 s.push_str(&option.name);
83 if let Some(value) = &option.value {
84 s.push('=');
85 s.push_str(value);
86 }
87 first = false;
88 }
89 s
90 }
91 pub fn has_option(
94 &self,
95 name: &str,
96 ) -> bool {
97 for option in &self.options {
98 if option.name == name {
99 return true;
100 }
101 }
102 false
103 }
104 pub fn option_value(
106 &self,
107 name: &str,
108 ) -> Option<&str> {
109 for option in &self.options {
110 if option.name == name {
111 return option.value.as_deref();
112 }
113 }
114 None
115 }
116}