From a613340b26ad88801666362d2824118396f34c38 Mon Sep 17 00:00:00 2001
From: Finn Behrens <me@kloenk.de>
Date: Sun, 12 Nov 2023 17:12:36 +0100
Subject: [PATCH] rust keylocation add none variant and implement ValueEnum

This enables a possible values help in the clap help text.

Signed-Off-By: Finn Behrens <me@kloenk.de>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
 rust-src/src/cmd_mount.rs | 11 +++-------
 rust-src/src/key.rs       | 44 ++++++++++++++++++++++++++-------------
 2 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/rust-src/src/cmd_mount.rs b/rust-src/src/cmd_mount.rs
index 9d58cb3e..17a289ca 100644
--- a/rust-src/src/cmd_mount.rs
+++ b/rust-src/src/cmd_mount.rs
@@ -5,7 +5,7 @@ use clap::{Parser, Subcommand};
 use uuid::Uuid;
 use std::path::PathBuf;
 use crate::{key, transform_c_args};
-use crate::key::KeyLoc;
+use crate::key::KeyLocation;
 use crate::logger::SimpleLogger;
 use std::ffi::{CStr, CString, OsStr, c_int, c_char, c_void};
 use std::os::unix::ffi::OsStrExt;
@@ -137,7 +137,7 @@ pub struct Cli {
     /// "wait" - wait for password to become available before mounting;
     /// "ask" -  prompt the user for password;
     #[arg(short, long, default_value = "ask", verbatim_doc_comment)]
-    key_location:   KeyLoc,
+    key_location:   KeyLocation,
 
     /// Device, or UUID=<UUID>
     dev:            String,
@@ -199,12 +199,7 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> {
     if sbs.len() == 0 {
         Err(anyhow::anyhow!("No device found from specified parameters"))?;
     } else if unsafe { bcachefs::bch2_sb_is_encrypted(sbs[0].sb) } {
-        let key = opt
-            .key_location
-            .0
-            .ok_or_else(|| anyhow::anyhow!("no keyoption specified for locked filesystem"))?;
-
-        key::prepare_key(&sbs[0], key)?;
+        key::prepare_key(&sbs[0], opt.key_location)?;
     }
 
     if let Some(mountpoint) = opt.mountpoint {
diff --git a/rust-src/src/key.rs b/rust-src/src/key.rs
index 9319351e..93daa263 100644
--- a/rust-src/src/key.rs
+++ b/rust-src/src/key.rs
@@ -1,37 +1,50 @@
 use log::{info};
 use bch_bindgen::bcachefs::bch_sb_handle;
+use clap::builder::PossibleValue;
 use crate::c_str;
 use anyhow::anyhow;
 
 #[derive(Clone, Debug)]
 pub enum KeyLocation {
+    None,
     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 {
+impl std::str::FromStr for KeyLocation {
     type Err = anyhow::Error;
     fn from_str(s: &str) -> anyhow::Result<Self> {
         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")),
+            ""|"none" => Ok(KeyLocation::None),
+            "fail"    => Ok(KeyLocation::Fail),
+            "wait"    => Ok(KeyLocation::Wait),
+            "ask"     => Ok(KeyLocation::Ask),
+            _         => Err(anyhow!("invalid password option")),
         }
     }
 }
 
+impl clap::ValueEnum for KeyLocation {
+    fn value_variants<'a>() -> &'a [Self] {
+        &[
+            KeyLocation::None,
+            KeyLocation::Fail,
+            KeyLocation::Wait,
+            KeyLocation::Ask,
+        ]
+    }
+
+    fn to_possible_value(&self) -> Option<PossibleValue> {
+        Some(match self {
+            Self::None => PossibleValue::new("none").alias(""),
+            Self::Fail => PossibleValue::new("fail"),
+            Self::Wait => PossibleValue::new("wait"),
+            Self::Ask => PossibleValue::new("ask"),
+        })
+    }
+}
+
 fn check_for_key(key_name: &std::ffi::CStr) -> anyhow::Result<bool> {
     use bch_bindgen::keyutils::{self, keyctl_search};
     let key_name = key_name.to_bytes_with_nul().as_ptr() as *const _;
@@ -126,5 +139,6 @@ pub fn prepare_key(sb: &bch_sb_handle, password: KeyLocation) -> anyhow::Result<
         KeyLocation::Fail => Err(anyhow!("no key available")),
         KeyLocation::Wait => Ok(wait_for_key(&sb.sb().uuid())?),
         KeyLocation::Ask => ask_for_key(sb),
+        _ => Err(anyhow!("no keyoption specified for locked filesystem")),
     }
 }