1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use {
crate::*,
lazy_regex::*,
std::{
path::PathBuf,
str::{FromStr, SplitWhitespace},
},
};
pub type MountId = u32;
#[derive(Debug, Clone)]
pub struct MountInfo {
pub id: MountId,
pub parent: MountId,
pub dev: DeviceId,
pub root: PathBuf,
pub mount_point: PathBuf,
pub fs: String,
pub fs_type: String,
}
impl FromStr for MountInfo {
type Err = Error;
fn from_str(line: &str) -> Result<Self> {
let mut tokens = line.split_whitespace();
let tokens = &mut tokens;
let id = next(tokens)?.parse()?;
let parent = next(tokens)?.parse()?;
let dev = next(tokens)?.parse()?;
let root = str_to_pathbuf(next(tokens)?);
let mount_point = str_to_pathbuf(next(tokens)?);
skip_until(tokens, "-")?;
let fs_type = next(tokens)?.to_string();
let fs = next(tokens)?.to_string();
Ok(Self {
id,
parent,
dev,
root,
mount_point,
fs,
fs_type,
})
}
}
fn str_to_pathbuf(s: &str) -> PathBuf {
let s = regex_replace_all!(r#"\\0(\d\d)"#, s, |_, n: &str| {
let c = u8::from_str_radix(n, 8).unwrap() as char;
c.to_string()
});
PathBuf::from(s.to_string())
}
fn next<'a, 'b>(split: &'b mut SplitWhitespace<'a>) -> Result<&'a str> {
split.next().ok_or(Error::UnexpectedFormat)
}
fn skip_until<'a, 'b>(split: &'b mut SplitWhitespace<'a>, sep: &'static str) -> Result<()> {
Ok(loop {
if next(split)? == sep {
break;
}
})
}
pub fn read_mountinfo() -> Result<Vec<MountInfo>> {
sys::read_file("/proc/self/mountinfo")?
.trim()
.split('\n')
.map(str::parse)
.inspect(|r| {
if let Err(e) = r {
eprintln!("Error while parsing a mount line: {}", e);
}
})
.collect()
}