diff options
Diffstat (limited to 'src/commands/mount.rs')
-rw-r--r-- | src/commands/mount.rs | 172 |
1 files changed, 7 insertions, 165 deletions
diff --git a/src/commands/mount.rs b/src/commands/mount.rs index 883a0d11..d0fd7168 100644 --- a/src/commands/mount.rs +++ b/src/commands/mount.rs @@ -1,6 +1,4 @@ use std::{ - collections::HashMap, - env, ffi::CString, io::{stdout, IsTerminal}, path::{Path, PathBuf}, @@ -8,11 +6,10 @@ use std::{ }; use anyhow::{ensure, Result}; -use bch_bindgen::{bcachefs, bcachefs::bch_sb_handle, opt_set, path_to_cstr}; -use bcachefs::bch_opts; +use bch_bindgen::{bcachefs, bcachefs::bch_sb_handle, path_to_cstr}; use clap::Parser; use log::{debug, error, info}; -use uuid::Uuid; +use crate::device_scan; use crate::{ key::{KeyHandle, Passphrase, UnlockPolicy}, @@ -121,141 +118,6 @@ fn parse_mountflag_options(options: impl AsRef<str>) -> (Option<String>, libc::c ) } -fn read_super_silent(path: impl AsRef<Path>, mut opts: bch_opts) -> anyhow::Result<bch_sb_handle> { - opt_set!(opts, noexcl, 1); - - bch_bindgen::sb_io::read_super_silent(path.as_ref(), opts) -} - -fn device_property_map(dev: &udev::Device) -> HashMap<String, String> { - let rc: HashMap<_, _> = dev - .properties() - .map(|i| { - ( - String::from(i.name().to_string_lossy()), - String::from(i.value().to_string_lossy()), - ) - }) - .collect(); - rc -} - -fn udev_bcachefs_info() -> anyhow::Result<HashMap<String, Vec<String>>> { - let mut info = HashMap::new(); - - if env::var("BCACHEFS_BLOCK_SCAN").is_ok() { - debug!("Checking all block devices for bcachefs super block!"); - return Ok(info); - } - - let mut udev = udev::Enumerator::new()?; - - debug!("Walking udev db!"); - - udev.match_subsystem("block")?; - udev.match_property("ID_FS_TYPE", "bcachefs")?; - - for m in udev - .scan_devices()? - .filter(udev::Device::is_initialized) - .map(|dev| device_property_map(&dev)) - .filter(|m| m.contains_key("ID_FS_UUID") && m.contains_key("DEVNAME")) - { - let fs_uuid = m["ID_FS_UUID"].clone(); - let dev_node = m["DEVNAME"].clone(); - info.insert(dev_node.clone(), vec![fs_uuid.clone()]); - info.entry(fs_uuid).or_insert(vec![]).push(dev_node.clone()); - } - - Ok(info) -} - -fn get_super_blocks(uuid: Uuid, devices: &[String], opts: &bch_opts) -> Vec<(PathBuf, bch_sb_handle)> { - devices - .iter() - .filter_map(|dev| { - read_super_silent(PathBuf::from(dev), *opts) - .ok() - .map(|sb| (PathBuf::from(dev), sb)) - }) - .filter(|(_, sb)| sb.sb().uuid() == uuid) - .collect::<Vec<_>>() -} - -fn get_all_block_devnodes() -> anyhow::Result<Vec<String>> { - let mut udev = udev::Enumerator::new()?; - udev.match_subsystem("block")?; - - let devices = udev - .scan_devices()? - .filter_map(|dev| { - if dev.is_initialized() { - dev.devnode().map(|dn| dn.to_string_lossy().into_owned()) - } else { - None - } - }) - .collect::<Vec<_>>(); - Ok(devices) -} - -fn get_devices_by_uuid( - udev_bcachefs: &HashMap<String, Vec<String>>, - uuid: Uuid, - opts: &bch_opts -) -> anyhow::Result<Vec<(PathBuf, bch_sb_handle)>> { - let devices = { - if !udev_bcachefs.is_empty() { - let uuid_string = uuid.hyphenated().to_string(); - if let Some(devices) = udev_bcachefs.get(&uuid_string) { - devices.clone() - } else { - Vec::new() - } - } else { - get_all_block_devnodes()? - } - }; - - Ok(get_super_blocks(uuid, &devices, opts)) -} - -fn devs_str_sbs_from_uuid( - udev_info: &HashMap<String, Vec<String>>, - uuid: &str, - opts: &bch_opts -) -> 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(udev_info, uuid, opts))??; - - 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 devs_str_sbs_from_device( - udev_info: &HashMap<String, Vec<String>>, - device: &Path, - opts: &bch_opts -) -> anyhow::Result<(String, Vec<bch_sb_handle>)> { - let dev_sb = read_super_silent(device, *opts)?; - - if dev_sb.sb().number_of_devices() == 1 { - Ok((device.as_os_str().to_str().unwrap().to_string(), vec![dev_sb])) - } else { - let uuid = dev_sb.sb().uuid(); - - devs_str_sbs_from_uuid(udev_info, &uuid.to_string(), opts) - } -} - /// If a user explicitly specifies `unlock_policy` or `passphrase_file` then use /// that without falling back to other mechanisms. If these options are not /// used, then search for the key or ask for it. @@ -278,40 +140,20 @@ fn cmd_mount_inner(cli: &Cli) -> Result<()> { let opts = bch_bindgen::opts::parse_mount_opts(None, optstr.as_deref(), true) .unwrap_or_default(); - // Grab the udev information once - let udev_info = udev_bcachefs_info()?; - - let (devices, mut sbs) = - if let Some(("UUID" | "OLD_BLKID_UUID", uuid)) = cli.dev.split_once('=') { - devs_str_sbs_from_uuid(&udev_info, uuid, &opts)? - } else if cli.dev.contains(':') { - // If the device string contains ":" we will assume the user knows the - // entire list. If they supply a single device it could be either the FS - // only has 1 device or it's only 1 of a number of devices which are - // part of the FS. This appears to be the case when we get called during - // fstab mount processing and the fstab specifies a UUID. - - let sbs = cli - .dev - .split(':') - .map(|path| read_super_silent(path, opts)) - .collect::<Result<Vec<_>>>()?; - - (cli.dev.clone(), sbs) - } else { - devs_str_sbs_from_device(&udev_info, Path::new(&cli.dev), &opts)? - }; + let mut sbs = device_scan::scan_sbs(&cli.dev, &opts)?; ensure!(!sbs.is_empty(), "No device(s) to mount specified"); - let first_sb = &sbs[0]; + let devices = device_scan::joined_device_str(&sbs); + + let first_sb = &sbs[0].1; if unsafe { bcachefs::bch2_sb_is_encrypted(first_sb.sb) } { handle_unlock(cli, first_sb)?; } for sb in &mut sbs { unsafe { - bch_bindgen::sb_io::bch2_free_super(sb); + bch_bindgen::sb_io::bch2_free_super(&mut sb.1); } } drop(sbs); |