Skip to main content

btrfs_cli/scrub/
status.rs

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