Skip to main content

btrfs_cli/device/
ready.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use btrfs_uapi::device::device_ready;
4use clap::Parser;
5use nix::errno::Errno;
6use std::{ffi::CString, path::PathBuf};
7
8/// Check whether all devices of a multi-device filesystem are present
9///
10/// Opens /dev/btrfs-control and queries the kernel for the given device.
11/// Exits with code 0 if all member devices are present and the filesystem
12/// is ready to mount, or a non-zero code if the device set is incomplete.
13#[derive(Parser, Debug)]
14pub struct DeviceReadyCommand {
15    /// A block device belonging to the multi-device filesystem to check
16    pub device: PathBuf,
17}
18
19impl Runnable for DeviceReadyCommand {
20    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
21        let path_str = self.device.to_str().ok_or_else(|| {
22            anyhow::anyhow!(
23                "device path is not valid UTF-8: '{}'",
24                self.device.display()
25            )
26        })?;
27
28        let cpath = CString::new(path_str).with_context(|| {
29            format!(
30                "device path contains a null byte: '{}'",
31                self.device.display()
32            )
33        })?;
34
35        match device_ready(&cpath) {
36            Ok(()) => {
37                println!("'{}' is ready for mount", self.device.display());
38                Ok(())
39            }
40            Err(Errno::ENOENT) | Err(Errno::ENXIO) => {
41                anyhow::bail!(
42                    "'{}': not all devices are present, filesystem is not ready",
43                    self.device.display()
44                )
45            }
46            Err(e) => Err(e).with_context(|| {
47                format!(
48                    "failed to check device readiness for '{}'",
49                    self.device.display()
50                )
51            }),
52        }
53    }
54}