Skip to main content

btrfs_cli/quota/
status.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use btrfs_uapi::sysfs::SysfsBtrfs;
4use clap::Parser;
5use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
6
7/// Show status information about quota on the filesystem
8#[derive(Parser, Debug)]
9pub struct QuotaStatusCommand {
10    /// Path to a mounted btrfs filesystem
11    pub path: PathBuf,
12
13    /// Only check if quotas are enabled, without printing full status
14    #[clap(long)]
15    pub is_enabled: bool,
16}
17
18fn describe_mode(mode: &str) -> &str {
19    match mode {
20        "qgroup" => "full accounting",
21        "squota" => "simplified accounting",
22        other => other,
23    }
24}
25
26impl Runnable for QuotaStatusCommand {
27    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
28        let file = File::open(&self.path).with_context(|| {
29            format!("failed to open '{}'", self.path.display())
30        })?;
31        let fd = file.as_fd();
32
33        let fs =
34            btrfs_uapi::filesystem::filesystem_info(fd).with_context(|| {
35                format!(
36                    "failed to get filesystem info for '{}'",
37                    self.path.display()
38                )
39            })?;
40
41        let status =
42            SysfsBtrfs::new(&fs.uuid).quota_status().with_context(|| {
43                format!(
44                    "failed to read quota status for '{}'",
45                    self.path.display()
46                )
47            })?;
48
49        if self.is_enabled {
50            if !status.enabled {
51                // Exit with a non-zero code the way the C tool does, without
52                // printing anything.
53                std::process::exit(1);
54            }
55            return Ok(());
56        }
57
58        println!("Quotas on {}:", self.path.display());
59
60        if !status.enabled {
61            println!("  Enabled:                 no");
62            return Ok(());
63        }
64
65        println!("  Enabled:                 yes");
66
67        if let Some(ref mode) = status.mode {
68            println!(
69                "  Mode:                    {} ({})",
70                mode,
71                describe_mode(mode)
72            );
73        }
74
75        if let Some(inconsistent) = status.inconsistent {
76            println!(
77                "  Inconsistent:            {}{}",
78                if inconsistent { "yes" } else { "no" },
79                if inconsistent { " (rescan needed)" } else { "" }
80            );
81        }
82
83        if let Some(override_limits) = status.override_limits {
84            println!(
85                "  Override limits:         {}",
86                if override_limits { "yes" } else { "no" }
87            );
88        }
89
90        if let Some(threshold) = status.drop_subtree_threshold {
91            println!("  Drop subtree threshold:  {}", threshold);
92        }
93
94        if let Some(total) = status.total_count {
95            println!("  Total count:             {}", total);
96        }
97
98        if let Some(level0) = status.level0_count {
99            println!("  Level 0:                 {}", level0);
100        }
101
102        Ok(())
103    }
104}