aboutsummaryrefslogtreecommitdiffstats
path: root/zone_zfs/src/zfs.rs
blob: b1c4ed25ee4228fa7545a75cb95bcdf363652056 (plain)
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
use figment::{Figment, Provider};
use std::path::PathBuf;
use std::process::Command;

use crate::{Config, Error, FileSystem, Result};

#[derive(Default, Debug)]
pub struct ZFS {
    pub config: Config,
}

impl ZFS {
    pub fn new() -> Result<Self> {
        Self::custom(Config::figment())
    }

    pub fn custom<T: Provider>(provider: T) -> Result<Self> {
        Config::from(Figment::from(provider))
            .map_err(Error::from)
            .map(|config| Self { config })
    }

    #[cfg(feature = "chrono")]
    pub fn clone_from_latest(&self, name: PathBuf, parent: PathBuf) -> Result<FileSystem> {
        self.get_file_system(parent)?
            .get_latest_snapshot()?
            .ok_or_else(|| Error::Snapshot("No snapshot found".into()))?
            .clone_new(name)
    }

    pub fn get_file_systems(&self) -> Result<Vec<FileSystem>> {
        Command::new("zfs")
            .arg("list")
            .arg("-H")
            .arg("-o")
            .arg("name")
            .output()
            .map(|o| String::from_utf8(o.stdout))?
            .map_err(Error::from)
            .map(|s| {
                s.lines()
                    .into_iter()
                    .filter_map(|l| l.split_once(' ').map(|s| (s.0.trim(), s.1.trim())))
                    .filter_map(|(dataset, mountpoint)| {
                        let mountpoint = if mountpoint == "none" {
                            PathBuf::from(mountpoint)
                        } else {
                            self.config.mountpoint.to_owned()
                        };

                        FileSystem::builder()
                            .mountpoint(mountpoint)
                            .dataset(dataset)
                            .to_file_system()
                            .ok()
                    })
                    .collect()
            })
    }

    pub fn get_file_system(&self, name: PathBuf) -> Result<FileSystem> {
        self.get_file_systems()?
            .into_iter()
            .find(|fs| fs.dataset().ends_with(&name))
            .ok_or_else(|| Error::FileSystem("No file system found".into()))
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn zfs_list() {
        use super::*;
        assert!(ZFS::new().unwrap().get_file_systems().is_ok());
    }
}