summaryrefslogtreecommitdiff
path: root/rust-src/mount/src/lib.rs
blob: f296456151a22558eec3e4846a76fc6d456f3bfb (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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use anyhow::anyhow;
use clap::Parser;
use uuid::Uuid;

pub mod err {
    pub enum GError {
        Unknown {
            message: std::borrow::Cow<'static, String>,
        },
    }
    pub type GResult<T, E, OE> = ::core::result::Result<::core::result::Result<T, E>, OE>;
    pub type Result<T, E> = GResult<T, E, GError>;
}

#[macro_export]
macro_rules! c_str {
    ($lit:expr) => {
        unsafe {
            std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr() as *const std::os::raw::c_char)
                .to_bytes_with_nul()
                .as_ptr() as *const std::os::raw::c_char
        }
    };
}

#[derive(Debug)]
struct ErrnoError(errno::Errno);
impl std::fmt::Display for ErrnoError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        self.0.fmt(f)
    }
}
impl std::error::Error for ErrnoError {}

#[derive(Clone, Debug)]
pub enum KeyLocation {
    Fail,
    Wait,
    Ask,
}

#[derive(Clone, Debug)]
pub struct KeyLoc(pub Option<KeyLocation>);
impl std::ops::Deref for KeyLoc {
    type Target = Option<KeyLocation>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl std::str::FromStr for KeyLoc {
    type Err = anyhow::Error;
    fn from_str(s: &str) -> anyhow::Result<Self> {
        // use anyhow::anyhow;
        match s {
            "" => Ok(KeyLoc(None)),
            "fail" => Ok(KeyLoc(Some(KeyLocation::Fail))),
            "wait" => Ok(KeyLoc(Some(KeyLocation::Wait))),
            "ask" => Ok(KeyLoc(Some(KeyLocation::Ask))),
            _ => Err(anyhow!("invalid password option")),
        }
    }
}

fn parse_fstab_uuid(uuid_raw: &str) -> Result<Uuid, uuid::Error> {
    let mut uuid = String::from(uuid_raw);
    if uuid.starts_with("UUID=") {
        uuid = uuid.replacen("UUID=", "", 1);
    }
    return Uuid::parse_str(&uuid);
}

/// Mount a bcachefs filesystem by its UUID.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
    /// Where the password would be loaded from.
    ///
    /// Possible values are:
    /// "fail" - don't ask for password, fail if filesystem is encrypted;
    /// "wait" - wait for password to become available before mounting;
    /// "ask" -  prompt the user for password;
    #[arg(short, long, default_value = "", verbatim_doc_comment)]
    pub key_location: KeyLoc,

    /// External UUID of the bcachefs filesystem
    ///
    /// Accepts the UUID as is or as fstab style UUID=<UUID>
    #[arg(value_parser=parse_fstab_uuid)]
    pub uuid: uuid::Uuid,

    /// Where the filesystem should be mounted. If not set, then the filesystem
    /// won't actually be mounted. But all steps preceeding mounting the
    /// filesystem (e.g. asking for passphrase) will still be performed.
    pub mountpoint: Option<std::path::PathBuf>,

    /// Mount options
    #[arg(short, default_value = "")]
    pub options: String,
}

pub mod filesystem;
pub mod key;

// pub fn mnt_in_use()

#[test]
fn verify_cli() {
    use clap::CommandFactory;
    Cli::command().debug_assert()
}