Skip to main content

btrfs_cli/qgroup/
remove.rs

1use crate::{
2    RunContext, Runnable,
3    util::{open_path, parse_qgroupid},
4};
5use anyhow::{Context, Result, bail};
6use clap::Parser;
7use nix::errno::Errno;
8use std::{os::unix::io::AsFd, path::PathBuf};
9
10/// Remove the relation between child qgroup SRC and DST
11#[derive(Parser, Debug)]
12pub struct QgroupRemoveCommand {
13    /// Source qgroup id (e.g. "0/5")
14    pub src: String,
15
16    /// Destination qgroup id (e.g. "1/0")
17    pub dst: String,
18
19    /// Path to a mounted btrfs filesystem
20    pub path: PathBuf,
21
22    /// Schedule quota rescan if needed (default)
23    #[clap(long, conflicts_with = "no_rescan")]
24    pub rescan: bool,
25
26    /// Don't schedule quota rescan
27    #[clap(long)]
28    pub no_rescan: bool,
29}
30
31impl Runnable for QgroupRemoveCommand {
32    fn run(&self, _ctx: &RunContext) -> Result<()> {
33        let src = parse_qgroupid(&self.src)?;
34        let dst = parse_qgroupid(&self.dst)?;
35
36        let file = open_path(&self.path)?;
37        let fd = file.as_fd();
38
39        let needs_rescan = match btrfs_uapi::quota::qgroup_remove(fd, src, dst)
40        {
41            Ok(needs_rescan) => needs_rescan,
42            Err(Errno::ENOTCONN) => {
43                bail!("quota not enabled on '{}'", self.path.display())
44            }
45            Err(e) => {
46                return Err(e).with_context(|| {
47                    format!(
48                        "failed to remove qgroup relation '{}' from '{}' on '{}'",
49                        self.src,
50                        self.dst,
51                        self.path.display()
52                    )
53                });
54            }
55        };
56
57        // Default behaviour (neither flag given) is to rescan.
58        let do_rescan = !self.no_rescan;
59
60        if needs_rescan {
61            if do_rescan {
62                btrfs_uapi::quota::quota_rescan(fd).with_context(|| {
63                    format!(
64                        "failed to schedule quota rescan on '{}'",
65                        self.path.display()
66                    )
67                })?;
68                println!("Quota data changed, rescan scheduled");
69            } else {
70                eprintln!(
71                    "WARNING: quotas may be inconsistent, rescan needed on '{}'",
72                    self.path.display()
73                );
74            }
75        }
76
77        Ok(())
78    }
79}