use crate::{
RunContext, Runnable,
util::{open_path, parse_qgroupid},
};
use anyhow::{Context, Result, bail};
use clap::Parser;
use nix::errno::Errno;
use std::{os::unix::io::AsFd, path::PathBuf};
#[derive(Parser, Debug)]
pub struct QgroupRemoveCommand {
pub src: String,
pub dst: String,
pub path: PathBuf,
#[clap(long, conflicts_with = "no_rescan")]
pub rescan: bool,
#[clap(long)]
pub no_rescan: bool,
}
impl Runnable for QgroupRemoveCommand {
fn run(&self, _ctx: &RunContext) -> Result<()> {
let src = parse_qgroupid(&self.src)?;
let dst = parse_qgroupid(&self.dst)?;
let file = open_path(&self.path)?;
let fd = file.as_fd();
let needs_rescan = match btrfs_uapi::quota::qgroup_remove(fd, src, dst)
{
Ok(needs_rescan) => needs_rescan,
Err(Errno::ENOTCONN) => {
bail!("quota not enabled on '{}'", self.path.display())
}
Err(e) => {
return Err(e).with_context(|| {
format!(
"failed to remove qgroup relation '{}' from '{}' on '{}'",
self.src,
self.dst,
self.path.display()
)
});
}
};
let do_rescan = !self.no_rescan;
if needs_rescan {
if do_rescan {
btrfs_uapi::quota::quota_rescan(fd).with_context(|| {
format!(
"failed to schedule quota rescan on '{}'",
self.path.display()
)
})?;
println!("Quota data changed, rescan scheduled");
} else {
eprintln!(
"WARNING: quotas may be inconsistent, rescan needed on '{}'",
self.path.display()
);
}
}
Ok(())
}
}