use anyhow::{bail, Result};
use std::fs;
use std::path::{Path, PathBuf};
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)]
pub struct Mount {
pub device: String,
pub mountpoint: PathBuf,
pub fs: String,
pub options: Vec<String>,
pub dump_level: u8,
pub fsck_passno: u8,
}
pub fn parse_mtab_line(string: &str) -> Result<Mount> {
let mut fields = string.split_ascii_whitespace();
macro_rules! next {
(expecting $lit:literal) => {
if let Some(field) = fields.next() {
field
} else {
bail!("expected {}\n, but got EOL", $lit);
}
};
}
let device = next!(expecting "a device").to_string();
let mountpoint = PathBuf::from(next!(expecting "a mountpoint"));
let fs = next!(expecting "a filesystem type").to_string();
let options = next!(expecting "a list of options")
.split(',')
.map(str::to_string)
.collect();
let dump_level = next!(expecting "an integer").parse()?;
let fsck_passno = next!(expecting "an integer").parse()?;
let mount = Mount {
device,
mountpoint,
fs,
options,
dump_level,
fsck_passno,
};
Ok(mount)
}
pub fn read_mtab_from<P: AsRef<Path>>(path: P) -> Result<Rc<[Mount]>> {
let lines: Result<Rc<[_]>> = fs::read_to_string(path.as_ref())?
.lines()
.map(parse_mtab_line)
.collect();
let lines = lines?;
Ok(lines)
}
pub fn read_mtab() -> Result<Rc<[Mount]>> {
read_mtab_from("/etc/mtab")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let line = "/dev/sda1 /mnt/indarys ext4 rw,nosuid,nodev 1 2";
let parsed_mount = parse_mtab_line(line).expect("should be parseable");
let manual_mount = Mount {
device: "/dev/sda1".to_string(),
mountpoint: PathBuf::from("/mnt/indarys"),
fs: "ext4".to_string(),
options: vec!["rw".to_string(), "nosuid".to_string(), "nodev".to_string()],
dump_level: 1,
fsck_passno: 2,
};
assert_eq!(parsed_mount, manual_mount);
}
#[cfg(unix)]
#[test]
fn it_really_works() {
assert!(read_mtab().is_ok())
}
}