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
18static OPTIONS_NOT_IN_OPTIONS_STRING: &[&str] = &[
21 "removable", ];
23
24pub type MountId = u32;
26
27#[derive(Debug, Clone)]
29pub struct MountInfo {
30 pub id: Option<MountId>,
31 pub parent: Option<MountId>,
32 pub dev: DeviceId,
33 pub root: PathBuf,
34 pub mount_point: PathBuf,
35 pub options: Vec<MountOption>,
36 pub fs: String, pub fs_type: String,
38 pub bound: bool,
40}
41
42#[derive(Debug, Clone, PartialEq)]
43pub struct MountOption {
44 pub name: String,
45 pub value: Option<String>,
46}
47
48impl MountOption {
49 pub fn new<S: Into<String>>(
50 name: S,
51 value: Option<S>,
52 ) -> Self {
53 MountOption {
54 name: name.into(),
55 value: value.map(|s| s.into()),
56 }
57 }
58}
59
60impl MountInfo {
61 pub fn dm_name(&self) -> Option<&str> {
63 regex_captures!(r#"^/dev/mapper/([^/]+)$"#, &self.fs).map(|(_, dm_name)| dm_name)
64 }
65 pub fn fs_name(&self) -> Option<&str> {
67 regex_find!(r#"[^\\/]+$"#, &self.fs)
68 }
69 pub fn is_remote(&self) -> bool {
73 self.fs.contains(':')
74 || (self.fs.starts_with("//")
75 && ["cifs", "smb3", "smbfs"].contains(&self.fs_type.as_ref()))
76 || REMOTE_ONLY_FS_TYPES.contains(&self.fs_type.as_ref())
77 || self.fs == "-hosts"
78 }
79 pub fn options_string(&self) -> String {
85 let mut s = String::new();
86 let mut first = true;
87 for option in &self.options {
88 if OPTIONS_NOT_IN_OPTIONS_STRING
89 .iter()
90 .any(|s| s == &option.name)
91 {
92 continue;
93 }
94 if !first {
95 s.push(',');
96 }
97 s.push_str(&option.name);
98 if let Some(value) = &option.value {
99 s.push('=');
100 s.push_str(value);
101 }
102 first = false;
103 }
104 s
105 }
106 pub fn has_option(
109 &self,
110 name: &str,
111 ) -> bool {
112 for option in &self.options {
113 if option.name == name {
114 return true;
115 }
116 }
117 false
118 }
119 pub fn option_value(
121 &self,
122 name: &str,
123 ) -> Option<&str> {
124 for option in &self.options {
125 if option.name == name {
126 return option.value.as_deref();
127 }
128 }
129 None
130 }
131}