Skip to main content

btrfs_cli/qgroup/
remove.rs

1use 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/// Remove the relation between child qgroup SRC and DST
8#[derive(Parser, Debug)]
9pub struct QgroupRemoveCommand {
10    /// Source qgroup id (e.g. "0/5")
11    pub src: String,
12
13    /// Destination qgroup id (e.g. "1/0")
14    pub dst: String,
15
16    /// Path to a mounted btrfs filesystem
17    pub path: PathBuf,
18
19    /// Schedule quota rescan if needed (default)
20    #[clap(long, conflicts_with = "no_rescan")]
21    pub rescan: bool,
22
23    /// Don't schedule quota rescan
24    #[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        // Default behaviour (neither flag given) is to rescan.
57        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}