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#[derive(Parser, Debug)]
14pub struct ScrubStartCommand {
15 #[clap(long, short)]
17 pub readonly: bool,
18
19 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}