Skip to main content

mtab/
lib.rs

1use anyhow::{bail, Result};
2use std::fs;
3use std::path::{Path, PathBuf};
4use std::rc::Rc;
5
6#[derive(Debug, PartialEq, Eq)]
7pub struct Mount {
8    pub device: String,
9    pub mountpoint: PathBuf,
10    pub fs: String,
11    pub options: Vec<String>,
12    pub dump_level: u8,
13    pub fsck_passno: u8,
14}
15
16pub fn parse_mtab_line(string: &str) -> Result<Mount> {
17    let mut fields = string.split_ascii_whitespace();
18    macro_rules! next {
19        (expecting $lit:literal) => {
20            if let Some(field) = fields.next() {
21                field
22            } else {
23                bail!("expected {}\n, but got EOL", $lit);
24            }
25        };
26    }
27
28    let device = next!(expecting "a device").to_string();
29    let mountpoint = PathBuf::from(next!(expecting "a mountpoint"));
30    let fs = next!(expecting "a filesystem type").to_string();
31    let options = next!(expecting "a list of options")
32        .split(',')
33        .map(str::to_string)
34        .collect();
35    let dump_level = next!(expecting "an integer").parse()?;
36    let fsck_passno = next!(expecting "an integer").parse()?;
37
38    let mount = Mount {
39        device,
40        mountpoint,
41        fs,
42        options,
43        dump_level,
44        fsck_passno,
45    };
46
47    Ok(mount)
48}
49
50pub fn read_mtab_from<P: AsRef<Path>>(path: P) -> Result<Rc<[Mount]>> {
51    let lines: Result<Rc<[_]>> = fs::read_to_string(path.as_ref())?
52        .lines()
53        .map(parse_mtab_line)
54        .collect();
55    let lines = lines?;
56    Ok(lines)
57}
58
59pub fn read_mtab() -> Result<Rc<[Mount]>> {
60    read_mtab_from("/etc/mtab")
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn it_works() {
69        let line = "/dev/sda1 /mnt/indarys ext4 rw,nosuid,nodev 1 2";
70        let parsed_mount = parse_mtab_line(line).expect("should be parseable");
71        let manual_mount = Mount {
72            device: "/dev/sda1".to_string(),
73            mountpoint: PathBuf::from("/mnt/indarys"),
74            fs: "ext4".to_string(),
75            options: vec!["rw".to_string(), "nosuid".to_string(), "nodev".to_string()],
76            dump_level: 1,
77            fsck_passno: 2,
78        };
79        assert_eq!(parsed_mount, manual_mount);
80    }
81
82    #[cfg(unix)]
83    #[test]
84    fn it_really_works() {
85        assert!(read_mtab().is_ok())
86    }
87}