btrfs_cli/qgroup/
remove.rs1use crate::{Format, Runnable, util::parse_qgroupid};
2use anyhow::{Context, Result, bail};
3use clap::Parser;
4use nix::errno::Errno;
5use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
6
7#[derive(Parser, Debug)]
9pub struct QgroupRemoveCommand {
10 pub src: String,
12
13 pub dst: String,
15
16 pub path: PathBuf,
18
19 #[clap(long, conflicts_with = "no_rescan")]
21 pub rescan: bool,
22
23 #[clap(long)]
25 pub no_rescan: bool,
26}
27
28impl Runnable for QgroupRemoveCommand {
29 fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
30 let src = parse_qgroupid(&self.src)?;
31 let dst = parse_qgroupid(&self.dst)?;
32
33 let file = File::open(&self.path).with_context(|| {
34 format!("failed to open '{}'", self.path.display())
35 })?;
36 let fd = file.as_fd();
37
38 let needs_rescan = match btrfs_uapi::quota::qgroup_remove(fd, src, dst)
39 {
40 Ok(needs_rescan) => needs_rescan,
41 Err(Errno::ENOTCONN) => {
42 bail!("quota not enabled on '{}'", self.path.display())
43 }
44 Err(e) => {
45 return Err(e).with_context(|| {
46 format!(
47 "failed to remove qgroup relation '{}' from '{}' on '{}'",
48 self.src,
49 self.dst,
50 self.path.display()
51 )
52 });
53 }
54 };
55
56 let do_rescan = !self.no_rescan;
58
59 if needs_rescan {
60 if do_rescan {
61 btrfs_uapi::quota::quota_rescan(fd).with_context(|| {
62 format!(
63 "failed to schedule quota rescan on '{}'",
64 self.path.display()
65 )
66 })?;
67 println!("Quota data changed, rescan scheduled");
68 } else {
69 eprintln!(
70 "WARNING: quotas may be inconsistent, rescan needed on '{}'",
71 self.path.display()
72 );
73 }
74 }
75
76 Ok(())
77 }
78}