diff options
Diffstat (limited to 'rust-src/src')
-rw-r--r-- | rust-src/src/bcachefs.rs | 120 | ||||
-rw-r--r-- | rust-src/src/commands/cmd_completions.rs | 19 | ||||
-rw-r--r-- | rust-src/src/commands/cmd_list.rs | 168 | ||||
-rw-r--r-- | rust-src/src/commands/cmd_mount.rs | 251 | ||||
-rw-r--r-- | rust-src/src/commands/logger.rs | 28 | ||||
-rw-r--r-- | rust-src/src/commands/mod.rs | 31 | ||||
-rw-r--r-- | rust-src/src/key.rs | 144 |
7 files changed, 0 insertions, 761 deletions
diff --git a/rust-src/src/bcachefs.rs b/rust-src/src/bcachefs.rs deleted file mode 100644 index 95f5e1f0..00000000 --- a/rust-src/src/bcachefs.rs +++ /dev/null @@ -1,120 +0,0 @@ -mod commands; -mod key; - -use std::ffi::CString; - -use commands::cmd_completions::cmd_completions; -use commands::cmd_list::cmd_list; -use commands::cmd_mount::cmd_mount; -use commands::logger::SimpleLogger; -use bch_bindgen::c; - -#[derive(Debug)] -pub struct ErrnoError(pub 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 {} - -fn handle_c_command(args: Vec<String>, symlink_cmd: Option<&str>) -> i32 { - let mut argv: Vec<_> = args.clone(); - - let cmd = match symlink_cmd { - Some(s) => s.to_string(), - None => argv.remove(1), - }; - - let argc: i32 = argv.len().try_into().unwrap(); - - let argv: Vec<_> = argv - .iter() - .map(|s| CString::new(s.as_str()).unwrap()) - .collect(); - let argv: Vec<_> = argv.iter().map(|s| s.as_ptr()).collect(); - let argv = argv.as_ptr() as *mut *mut i8; - - // The C functions will mutate argv. It shouldn't be used after this block. - unsafe { - match cmd.as_str() { - "--help" => { - c::bcachefs_usage(); - 0 - }, - "data" => c::data_cmds(argc, argv), - "device" => c::device_cmds(argc, argv), - "dump" => c::cmd_dump(argc, argv), - "format" => c::cmd_format(argc, argv), - "fs" => c::fs_cmds(argc, argv), - "fsck" => c::cmd_fsck(argc, argv), - "list_journal" => c::cmd_list_journal(argc, argv), - "kill_btree_node" => c::cmd_kill_btree_node(argc, argv), - "migrate" => c::cmd_migrate(argc, argv), - "migrate-superblock" => c::cmd_migrate_superblock(argc, argv), - "mkfs" => c::cmd_format(argc, argv), - "remove-passphrase" => c::cmd_remove_passphrase(argc, argv), - "reset-counters" => c::cmd_reset_counters(argc, argv), - "set-option" => c::cmd_set_option(argc, argv), - "set-passphrase" => c::cmd_set_passphrase(argc, argv), - "setattr" => c::cmd_setattr(argc, argv), - "show-super" => c::cmd_show_super(argc, argv), - "subvolume" => c::subvolume_cmds(argc, argv), - "unlock" => c::cmd_unlock(argc, argv), - "version" => c::cmd_version(argc, argv), - - #[cfg(fuse)] - "fusemount" => c::cmd_fusemount(argc, argv), - - _ => { - println!("Unknown command {}", cmd); - c::bcachefs_usage(); - 1 - } - } - } -} - -fn main() { - let args: Vec<String> = std::env::args().collect(); - - let symlink_cmd: Option<&str> = if args[0].contains("mkfs") { - Some("mkfs") - } else if args[0].contains("fsck") { - Some("fsck") - } else if args[0].contains("mount.fuse") { - Some("fusemount") - } else if args[0].contains("mount") { - Some("mount") - } else { - None - }; - - if symlink_cmd.is_none() && args.len() < 2 { - println!("missing command"); - unsafe { c::bcachefs_usage() }; - std::process::exit(1); - } - - unsafe { c::raid_init() }; - - log::set_boxed_logger(Box::new(SimpleLogger)).unwrap(); - log::set_max_level(log::LevelFilter::Warn); - - let cmd = match symlink_cmd { - Some(s) => s, - None => args[1].as_str(), - }; - - let ret = match cmd { - "completions" => cmd_completions(args[1..].to_vec()), - "list" => cmd_list(args[1..].to_vec()), - "mount" => cmd_mount(args, symlink_cmd), - _ => handle_c_command(args, symlink_cmd), - }; - - if ret != 0 { - std::process::exit(1); - } -} diff --git a/rust-src/src/commands/cmd_completions.rs b/rust-src/src/commands/cmd_completions.rs deleted file mode 100644 index 53cdd643..00000000 --- a/rust-src/src/commands/cmd_completions.rs +++ /dev/null @@ -1,19 +0,0 @@ -use clap::{Command, CommandFactory, Parser}; -use clap_complete::{generate, Generator, Shell}; -use std::io; - -/// Generate shell completions -#[derive(clap::Parser, Debug)] -pub struct Cli { - shell: Shell, -} - -fn print_completions<G: Generator>(gen: G, cmd: &mut Command) { - generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout()); -} - -pub fn cmd_completions(argv: Vec<String>) -> i32 { - let cli = Cli::parse_from(argv); - print_completions(cli.shell, &mut super::Cli::command()); - 0 -} diff --git a/rust-src/src/commands/cmd_list.rs b/rust-src/src/commands/cmd_list.rs deleted file mode 100644 index cb352916..00000000 --- a/rust-src/src/commands/cmd_list.rs +++ /dev/null @@ -1,168 +0,0 @@ -use atty::Stream; -use log::{error}; -use bch_bindgen::bcachefs; -use bch_bindgen::opt_set; -use bch_bindgen::fs::Fs; -use bch_bindgen::bkey::BkeySC; -use bch_bindgen::btree::BtreeTrans; -use bch_bindgen::btree::BtreeIter; -use bch_bindgen::btree::BtreeNodeIter; -use bch_bindgen::btree::BtreeIterFlags; -use clap::{Parser}; - -fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> { - let trans = BtreeTrans::new(fs); - let mut iter = BtreeIter::new(&trans, opt.btree, opt.start, - BtreeIterFlags::ALL_SNAPSHOTS| - BtreeIterFlags::PREFETCH); - - while let Some(k) = iter.peek_and_restart()? { - if k.k.p > opt.end { - break; - } - - println!("{}", k.to_text(fs)); - iter.advance(); - } - - Ok(()) -} - -fn list_btree_formats(fs: &Fs, opt: Cli) -> anyhow::Result<()> { - let trans = BtreeTrans::new(fs); - let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start, - 0, opt.level, - BtreeIterFlags::PREFETCH); - - while let Some(b) = iter.peek_and_restart()? { - if b.key.k.p > opt.end { - break; - } - - println!("{}", b.to_text(fs)); - iter.advance(); - } - - Ok(()) -} - -fn list_btree_nodes(fs: &Fs, opt: Cli) -> anyhow::Result<()> { - let trans = BtreeTrans::new(fs); - let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start, - 0, opt.level, - BtreeIterFlags::PREFETCH); - - while let Some(b) = iter.peek_and_restart()? { - if b.key.k.p > opt.end { - break; - } - - println!("{}", BkeySC::from(&b.key).to_text(fs)); - iter.advance(); - } - - Ok(()) -} - -fn list_nodes_ondisk(fs: &Fs, opt: Cli) -> anyhow::Result<()> { - let trans = BtreeTrans::new(fs); - let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start, - 0, opt.level, - BtreeIterFlags::PREFETCH); - - while let Some(b) = iter.peek_and_restart()? { - if b.key.k.p > opt.end { - break; - } - - println!("{}", b.ondisk_to_text(fs)); - iter.advance(); - } - - Ok(()) -} - -#[derive(Clone, clap::ValueEnum, Debug)] -enum Mode { - Keys, - Formats, - Nodes, - NodesOndisk, -} - -/// List filesystem metadata in textual form -#[derive(Parser, Debug)] -pub struct Cli { - /// Btree to list from - #[arg(short, long, default_value_t=bcachefs::btree_id::BTREE_ID_extents)] - btree: bcachefs::btree_id, - - /// Btree depth to descend to (0 == leaves) - #[arg(short, long, default_value_t=0)] - level: u32, - - /// Start position to list from - #[arg(short, long, default_value="POS_MIN")] - start: bcachefs::bpos, - - /// End position - #[arg(short, long, default_value="SPOS_MAX")] - end: bcachefs::bpos, - - #[arg(short, long, default_value="keys")] - mode: Mode, - - /// Check (fsck) the filesystem first - #[arg(short, long, default_value_t=false)] - fsck: bool, - - /// Force color on/off. Default: autodetect tty - #[arg(short, long, action = clap::ArgAction::Set, default_value_t=atty::is(Stream::Stdout))] - colorize: bool, - - /// Verbose mode - #[arg(short, long)] - verbose: bool, - - #[arg(required(true))] - devices: Vec<std::path::PathBuf>, -} - -fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> { - let mut fs_opts: bcachefs::bch_opts = Default::default(); - - opt_set!(fs_opts, nochanges, 1); - opt_set!(fs_opts, read_only, 1); - opt_set!(fs_opts, norecovery, 1); - opt_set!(fs_opts, degraded, 1); - opt_set!(fs_opts, errors, bcachefs::bch_error_actions::BCH_ON_ERROR_continue as u8); - - if opt.fsck { - opt_set!(fs_opts, fix_errors, bcachefs::fsck_err_opts::FSCK_FIX_yes as u8); - opt_set!(fs_opts, norecovery, 0); - } - - if opt.verbose { - opt_set!(fs_opts, verbose, 1); - } - - let fs = Fs::open(&opt.devices, fs_opts)?; - - match opt.mode { - Mode::Keys => list_keys(&fs, opt), - Mode::Formats => list_btree_formats(&fs, opt), - Mode::Nodes => list_btree_nodes(&fs, opt), - Mode::NodesOndisk => list_nodes_ondisk(&fs, opt), - } -} - -pub fn cmd_list(argv: Vec<String>) -> i32 { - let opt = Cli::parse_from(argv); - colored::control::set_override(opt.colorize); - if let Err(e) = cmd_list_inner(opt) { - error!("Fatal error: {}", e); - 1 - } else { - 0 - } -} diff --git a/rust-src/src/commands/cmd_mount.rs b/rust-src/src/commands/cmd_mount.rs deleted file mode 100644 index b120c91e..00000000 --- a/rust-src/src/commands/cmd_mount.rs +++ /dev/null @@ -1,251 +0,0 @@ -use atty::Stream; -use bch_bindgen::{bcachefs, bcachefs::bch_sb_handle, opt_set}; -use log::{info, debug, error, LevelFilter}; -use clap::{Parser}; -use uuid::Uuid; -use std::path::PathBuf; -use crate::key; -use crate::key::KeyLocation; -use std::ffi::{CString, c_char, c_void}; -use std::os::unix::ffi::OsStrExt; - -fn mount_inner( - src: String, - target: impl AsRef<std::path::Path>, - fstype: &str, - mountflags: libc::c_ulong, - data: Option<String>, -) -> anyhow::Result<()> { - - // bind the CStrings to keep them alive - let src = CString::new(src)?; - let target = CString::new(target.as_ref().as_os_str().as_bytes())?; - let data = data.map(CString::new).transpose()?; - let fstype = CString::new(fstype)?; - - // convert to pointers for ffi - let src = src.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; - let target = target.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; - let data = data.as_ref().map_or(std::ptr::null(), |data| { - data.as_c_str().to_bytes_with_nul().as_ptr() as *const c_void - }); - let fstype = fstype.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; - - let ret = { - info!("mounting filesystem"); - // REQUIRES: CAP_SYS_ADMIN - unsafe { libc::mount(src, target, fstype, mountflags, data) } - }; - match ret { - 0 => Ok(()), - _ => Err(crate::ErrnoError(errno::errno()).into()), - } -} - -/// Parse a comma-separated mount options and split out mountflags and filesystem -/// specific options. -fn parse_mount_options(options: impl AsRef<str>) -> (Option<String>, libc::c_ulong) { - use either::Either::*; - debug!("parsing mount options: {}", options.as_ref()); - let (opts, flags) = options - .as_ref() - .split(",") - .map(|o| match o { - "dirsync" => Left(libc::MS_DIRSYNC), - "lazytime" => Left(1 << 25), // MS_LAZYTIME - "mand" => Left(libc::MS_MANDLOCK), - "noatime" => Left(libc::MS_NOATIME), - "nodev" => Left(libc::MS_NODEV), - "nodiratime" => Left(libc::MS_NODIRATIME), - "noexec" => Left(libc::MS_NOEXEC), - "nosuid" => Left(libc::MS_NOSUID), - "relatime" => Left(libc::MS_RELATIME), - "remount" => Left(libc::MS_REMOUNT), - "ro" => Left(libc::MS_RDONLY), - "rw" => Left(0), - "strictatime" => Left(libc::MS_STRICTATIME), - "sync" => Left(libc::MS_SYNCHRONOUS), - "" => Left(0), - o @ _ => Right(o), - }) - .fold((Vec::new(), 0), |(mut opts, flags), next| match next { - Left(f) => (opts, flags | f), - Right(o) => { - opts.push(o); - (opts, flags) - } - }); - - ( - if opts.len() == 0 { - None - } else { - Some(opts.join(",")) - }, - flags, - ) -} - -fn mount( - device: String, - target: impl AsRef<std::path::Path>, - options: impl AsRef<str>, -) -> anyhow::Result<()> { - let (data, mountflags) = parse_mount_options(options); - - info!( - "mounting bcachefs filesystem, {}", - target.as_ref().display() - ); - mount_inner(device, target, "bcachefs", mountflags, data) -} - -fn read_super_silent(path: &std::path::PathBuf) -> anyhow::Result<bch_sb_handle> { - // Stop libbcachefs from spamming the output - let _gag = gag::BufferRedirect::stdout().unwrap(); - - let mut opts = bcachefs::bch_opts::default(); - opt_set!(opts, noexcl, 1); - - bch_bindgen::rs::read_super_opts(&path, opts) -} - -fn get_devices_by_uuid(uuid: Uuid) -> anyhow::Result<Vec<(PathBuf, bch_sb_handle)>> { - debug!("enumerating udev devices"); - let mut udev = udev::Enumerator::new()?; - - udev.match_subsystem("block")?; - - let devs = udev - .scan_devices()? - .into_iter() - .filter_map(|dev| dev.devnode().map(ToOwned::to_owned)) - .map(|dev| (dev.clone(), read_super_silent(&dev))) - .filter_map(|(dev, sb)| sb.ok().map(|sb| (dev, sb))) - .filter(|(_, sb)| sb.sb().uuid() == uuid) - .collect(); - Ok(devs) -} - -/// 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 = "ask", verbatim_doc_comment)] - key_location: KeyLocation, - - /// Device, or UUID=<UUID> - dev: String, - - /// 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. - mountpoint: Option<std::path::PathBuf>, - - /// Mount options - #[arg(short, default_value = "")] - options: String, - - /// Force color on/off. Default: autodetect tty - #[arg(short, long, action = clap::ArgAction::Set, default_value_t=atty::is(Stream::Stdout))] - colorize: bool, - - /// Verbose mode - #[arg(short, long, action = clap::ArgAction::Count)] - verbose: u8, -} - -fn devs_str_sbs_from_uuid(uuid: String) -> anyhow::Result<(String, Vec<bch_sb_handle>)> { - debug!("enumerating devices with UUID {}", uuid); - - let devs_sbs = Uuid::parse_str(&uuid) - .map(|uuid| get_devices_by_uuid(uuid))??; - - let devs_str = devs_sbs - .iter() - .map(|(dev, _)| dev.to_str().unwrap()) - .collect::<Vec<_>>() - .join(":"); - - let sbs: Vec<bch_sb_handle> = devs_sbs.iter().map(|(_, sb)| *sb).collect(); - - Ok((devs_str, sbs)) - -} - -fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> { - let (devs, sbs) = if opt.dev.starts_with("UUID=") { - let uuid = opt.dev.replacen("UUID=", "", 1); - devs_str_sbs_from_uuid(uuid)? - } else if opt.dev.starts_with("OLD_BLKID_UUID=") { - let uuid = opt.dev.replacen("OLD_BLKID_UUID=", "", 1); - devs_str_sbs_from_uuid(uuid)? - } else { - let mut sbs = Vec::new(); - - for dev in opt.dev.split(':') { - let dev = PathBuf::from(dev); - sbs.push(read_super_silent(&dev)?); - } - - (opt.dev, sbs) - }; - - if sbs.len() == 0 { - Err(anyhow::anyhow!("No device found from specified parameters"))?; - } else if unsafe { bcachefs::bch2_sb_is_encrypted(sbs[0].sb) } { - key::prepare_key(&sbs[0], opt.key_location)?; - } - - if let Some(mountpoint) = opt.mountpoint { - info!( - "mounting with params: device: {}, target: {}, options: {}", - devs, - mountpoint.to_string_lossy(), - &opt.options - ); - - mount(devs, mountpoint, &opt.options)?; - } else { - info!( - "would mount with params: device: {}, options: {}", - devs, - &opt.options - ); - } - - Ok(()) -} - -pub fn cmd_mount(mut argv: Vec<String>, symlink_cmd: Option<&str>) -> i32 { - // If the bcachefs tool is being called as "bcachefs mount dev ..." (as opposed to via a - // symlink like "/usr/sbin/mount.bcachefs dev ...", then we need to pop the 0th argument - // ("bcachefs") since the CLI parser here expects the device at position 1. - if symlink_cmd.is_none() { - argv.remove(0); - } - - let opt = Cli::parse_from(argv); - - // @TODO : more granular log levels via mount option - log::set_max_level(match opt.verbose { - 0 => LevelFilter::Warn, - 1 => LevelFilter::Trace, - 2_u8..=u8::MAX => todo!(), - }); - - colored::control::set_override(opt.colorize); - if let Err(e) = cmd_mount_inner(opt) { - error!("Fatal error: {}", e); - 1 - } else { - info!("Successfully mounted"); - 0 - } -} diff --git a/rust-src/src/commands/logger.rs b/rust-src/src/commands/logger.rs deleted file mode 100644 index 2cd7b363..00000000 --- a/rust-src/src/commands/logger.rs +++ /dev/null @@ -1,28 +0,0 @@ -use colored::Colorize; -use log::{Level, Metadata, Record}; - -pub struct SimpleLogger; - -impl log::Log for SimpleLogger { - fn enabled(&self, _: &Metadata) -> bool { - true - } - - fn log(&self, record: &Record) { - let debug_prefix = match record.level() { - Level::Error => "ERROR".bright_red(), - Level::Warn => "WARN".bright_yellow(), - Level::Info => "INFO".green(), - Level::Debug => "DEBUG".bright_blue(), - Level::Trace => "TRACE".into(), - }; - println!( - "{} - {}: {}", - debug_prefix, - record.module_path().unwrap_or_default().bright_black(), - record.args() - ); - } - - fn flush(&self) {} -} diff --git a/rust-src/src/commands/mod.rs b/rust-src/src/commands/mod.rs deleted file mode 100644 index e05a0848..00000000 --- a/rust-src/src/commands/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -use clap::Subcommand; - -pub mod logger; -pub mod cmd_mount; -pub mod cmd_list; -pub mod cmd_completions; - -#[derive(clap::Parser, Debug)] -#[command(name = "bcachefs")] -pub struct Cli { - #[command(subcommand)] - subcommands: Subcommands, -} - -#[derive(Subcommand, Debug)] -enum Subcommands { - List(cmd_list::Cli), - Mount(cmd_mount::Cli), - Completions(cmd_completions::Cli), -} - -#[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 - } - }; -} diff --git a/rust-src/src/key.rs b/rust-src/src/key.rs deleted file mode 100644 index 93daa263..00000000 --- a/rust-src/src/key.rs +++ /dev/null @@ -1,144 +0,0 @@ -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, -} - -impl std::str::FromStr for KeyLocation { - type Err = anyhow::Error; - fn from_str(s: &str) -> anyhow::Result<Self> { - match s { - ""|"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 _; - let key_type = c_str!("user"); - - let key_id = unsafe { keyctl_search(keyutils::KEY_SPEC_USER_KEYRING, key_type, key_name, 0) }; - if key_id > 0 { - info!("Key has became available"); - Ok(true) - } else { - match errno::errno().0 { - libc::ENOKEY | libc::EKEYREVOKED => Ok(false), - _ => Err(crate::ErrnoError(errno::errno()).into()), - } - } -} - -fn wait_for_key(uuid: &uuid::Uuid) -> anyhow::Result<()> { - let key_name = std::ffi::CString::new(format!("bcachefs:{}", uuid)).unwrap(); - loop { - if check_for_key(&key_name)? { - break Ok(()); - } - - std::thread::sleep(std::time::Duration::from_secs(1)); - } -} - -const BCH_KEY_MAGIC: &str = "bch**key"; -fn ask_for_key(sb: &bch_sb_handle) -> anyhow::Result<()> { - use bch_bindgen::bcachefs::{self, bch2_chacha_encrypt_key, bch_encrypted_key, bch_key}; - use byteorder::{LittleEndian, ReadBytesExt}; - use std::os::raw::c_char; - - let key_name = std::ffi::CString::new(format!("bcachefs:{}", sb.sb().uuid())).unwrap(); - if check_for_key(&key_name)? { - return Ok(()); - } - - let bch_key_magic = BCH_KEY_MAGIC.as_bytes().read_u64::<LittleEndian>().unwrap(); - let crypt = sb.sb().crypt().unwrap(); - let pass = if atty::is(atty::Stream::Stdin) { - rpassword::read_password_from_tty(Some("Enter passphrase: "))? - } else { - let mut line = String::new(); - std::io::stdin().read_line(&mut line)?; - line - }; - let pass = std::ffi::CString::new(pass.trim_end())?; // bind to keep the CString alive - let mut output: bch_key = unsafe { - bcachefs::derive_passphrase( - crypt as *const _ as *mut _, - pass.as_c_str().to_bytes_with_nul().as_ptr() as *const _, - ) - }; - - let mut key = crypt.key().clone(); - let ret = unsafe { - bch2_chacha_encrypt_key( - &mut output as *mut _, - sb.sb().nonce(), - &mut key as *mut _ as *mut _, - std::mem::size_of::<bch_encrypted_key>() as usize, - ) - }; - if ret != 0 { - Err(anyhow!("chacha decryption failure")) - } else if key.magic != bch_key_magic { - Err(anyhow!("failed to verify the password")) - } else { - let key_type = c_str!("user"); - let ret = unsafe { - bch_bindgen::keyutils::add_key( - key_type, - key_name.as_c_str().to_bytes_with_nul() as *const _ as *const c_char, - &output as *const _ as *const _, - std::mem::size_of::<bch_key>() as usize, - bch_bindgen::keyutils::KEY_SPEC_USER_KEYRING, - ) - }; - if ret == -1 { - Err(anyhow!("failed to add key to keyring: {}", errno::errno())) - } else { - Ok(()) - } - } -} - -pub fn prepare_key(sb: &bch_sb_handle, password: KeyLocation) -> anyhow::Result<()> { - info!("checking if key exists for filesystem {}", sb.sb().uuid()); - match password { - 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")), - } -} |