Skip to main content

btrfs_cli/scrub/
start.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use btrfs_uapi::{
4    device::device_info_all, filesystem::filesystem_info, scrub::scrub_start,
5};
6use clap::Parser;
7use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
8
9/// Start a new scrub on the filesystem or a device.
10///
11/// Scrubs all devices sequentially. This command blocks until the scrub
12/// completes; use Ctrl-C to cancel.
13#[derive(Parser, Debug)]
14pub struct ScrubStartCommand {
15    /// Read-only mode: check for errors but do not attempt repairs
16    #[clap(long, short)]
17    pub readonly: bool,
18
19    /// Path to a mounted btrfs filesystem or a device
20    pub path: PathBuf,
21}
22
23impl Runnable for ScrubStartCommand {
24    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
25        let file = File::open(&self.path).with_context(|| {
26            format!("failed to open '{}'", self.path.display())
27        })?;
28        let fd = file.as_fd();
29
30        let fs = filesystem_info(fd).with_context(|| {
31            format!(
32                "failed to get filesystem info for '{}'",
33                self.path.display()
34            )
35        })?;
36        let devices = device_info_all(fd, &fs).with_context(|| {
37            format!("failed to get device info for '{}'", self.path.display())
38        })?;
39
40        println!("UUID: {}", fs.uuid.as_hyphenated());
41
42        let mut fs_totals = btrfs_uapi::scrub::ScrubProgress::default();
43
44        for dev in &devices {
45            println!("scrubbing device {} ({})", dev.devid, dev.path);
46
47            match scrub_start(fd, dev.devid, self.readonly) {
48                Ok(progress) => {
49                    super::accumulate(&mut fs_totals, &progress);
50                    super::print_progress_summary(
51                        &progress, dev.devid, &dev.path,
52                    );
53                }
54                Err(e) => {
55                    eprintln!("error scrubbing device {}: {e}", dev.devid);
56                }
57            }
58        }
59
60        if devices.len() > 1 {
61            println!("\nFilesystem totals:");
62            super::print_error_summary(&fs_totals);
63        }
64
65        Ok(())
66    }
67}