1use {
2 crate::*,
3 lazy_regex::*,
4 std::path::PathBuf,
5};
6
7#[cfg(unix)]
8static REMOTE_ONLY_FS_TYPES: &[&str] = &[
9 "afs",
10 "coda",
11 "auristorfs",
12 "fhgfs",
13 "gpfs",
14 "ibrix",
15 "ocfs2",
16 "vxfs",
17];
18
19static OPTIONS_NOT_IN_OPTIONS_STRING: &[&str] = &[
22 "removable", ];
24
25pub type MountId = u32;
27
28#[derive(Debug, Clone)]
30pub struct MountInfo {
31 pub id: Option<MountId>,
32 pub parent: Option<MountId>,
33 pub dev: DeviceId,
34 pub root: PathBuf,
35 pub mount_point: PathBuf,
36 pub options: Vec<MountOption>,
37 pub fs: String, pub fs_type: String,
39 pub bound: bool,
41}
42
43#[derive(Debug, Clone, PartialEq)]
44pub struct MountOption {
45 pub name: String,
46 pub value: Option<String>,
47}
48
49impl MountOption {
50 pub fn new<S: Into<String>>(
51 name: S,
52 value: Option<S>,
53 ) -> Self {
54 MountOption {
55 name: name.into(),
56 value: value.map(|s| s.into()),
57 }
58 }
59}
60
61impl MountInfo {
62 pub fn dm_name(&self) -> Option<&str> {
64 regex_captures!(r#"^/dev/mapper/([^/]+)$"#, &self.fs).map(|(_, dm_name)| dm_name)
65 }
66 pub fn fs_name(&self) -> Option<&str> {
68 regex_find!(r#"[^\\/]+$"#, &self.fs)
69 }
70 #[cfg(unix)]
74 pub fn is_remote(&self) -> bool {
75 self.fs.contains(':')
76 || (self.fs.starts_with("//")
77 && ["cifs", "smb3", "smbfs"].contains(&self.fs_type.as_ref()))
78 || REMOTE_ONLY_FS_TYPES.contains(&self.fs_type.as_ref())
79 || self.fs == "-hosts"
80 }
81 pub fn options_string(&self) -> String {
87 let mut s = String::new();
88 let mut first = true;
89 for option in &self.options {
90 if OPTIONS_NOT_IN_OPTIONS_STRING
91 .iter()
92 .any(|s| s == &option.name)
93 {
94 continue;
95 }
96 if !first {
97 s.push(',');
98 }
99 s.push_str(&option.name);
100 if let Some(value) = &option.value {
101 s.push('=');
102 s.push_str(value);
103 }
104 first = false;
105 }
106 s
107 }
108 pub fn has_option(
111 &self,
112 name: &str,
113 ) -> bool {
114 for option in &self.options {
115 if option.name == name {
116 return true;
117 }
118 }
119 false
120 }
121 pub fn option_value(
123 &self,
124 name: &str,
125 ) -> Option<&str> {
126 for option in &self.options {
127 if option.name == name {
128 return option.value.as_deref();
129 }
130 }
131 None
132 }
133}