Skip to main content

btrfs_cli/scrub/
status.rs

1use crate::{Format, Runnable, util::human_bytes};
2use anyhow::{Context, Result};
3use btrfs_uapi::{
4    device::device_info_all, filesystem::filesystem_info, scrub::scrub_progress,
5};
6use clap::Parser;
7use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
8
9/// Show the status of a running or finished scrub
10#[derive(Parser, Debug)]
11pub struct ScrubStatusCommand {
12    /// Show stats per device
13    #[clap(long, short)]
14    pub device: bool,
15
16    /// Path to a mounted btrfs filesystem or a device
17    pub path: PathBuf,
18}
19
20impl Runnable for ScrubStatusCommand {
21    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
22        let file = File::open(&self.path).with_context(|| {
23            format!("failed to open '{}'", self.path.display())
24        })?;
25        let fd = file.as_fd();
26
27        let fs = filesystem_info(fd).with_context(|| {
28            format!(
29                "failed to get filesystem info for '{}'",
30                self.path.display()
31            )
32        })?;
33        let devices = device_info_all(fd, &fs).with_context(|| {
34            format!("failed to get device info for '{}'", self.path.display())
35        })?;
36
37        println!("UUID: {}", fs.uuid.as_hyphenated());
38
39        let mut any_running = false;
40        let mut fs_totals = btrfs_uapi::scrub::ScrubProgress::default();
41
42        for dev in &devices {
43            match scrub_progress(fd, dev.devid).with_context(|| {
44                format!("failed to get scrub progress for device {}", dev.devid)
45            })? {
46                None => {
47                    if self.device {
48                        println!(
49                            "device {} ({}): no scrub in progress",
50                            dev.devid, dev.path
51                        );
52                    }
53                }
54                Some(progress) => {
55                    any_running = true;
56                    super::accumulate(&mut fs_totals, &progress);
57                    if self.device {
58                        super::print_progress_summary(
59                            &progress, dev.devid, &dev.path,
60                        );
61                    }
62                }
63            }
64        }
65
66        if !any_running {
67            println!("\tno scrub in progress");
68        } else if !self.device {
69            // Show filesystem-level summary when not in per-device mode.
70            println!(
71                "Bytes scrubbed:   {}",
72                human_bytes(fs_totals.bytes_scrubbed())
73            );
74            super::print_error_summary(&fs_totals);
75        }
76
77        Ok(())
78    }
79}