use std::process::Command;
#[derive(Debug, serde::Serialize)]
pub struct BtrfsSpace {
pub total_bytes: u128,
pub used_bytes: u128,
pub free_bytes: u128,
}
pub fn get_space(path: &str) -> Result<BtrfsSpace, String> {
let output = Command::new("btrfs")
.args(["filesystem", "usage", "--raw", path])
.output()
.map_err(|e| e.to_string())?;
if !output.status.success() {
return Err(String::from_utf8_lossy(&output.stderr).to_string());
}
let stdout = String::from_utf8_lossy(&output.stdout);
derive_space(&stdout).ok_or("Failed to parse space info".into())
}
fn derive_space(output: &str) -> Option<BtrfsSpace> {
let mut used_bytes: Option<u128> = None;
let mut free_bytes: Option<u128> = None;
for line in output.lines() {
let line = line.trim();
if line.starts_with("Used:") {
if let Some(value) = line.split(':').nth(1) {
let number = value.trim().split_whitespace().next()?;
used_bytes = number.parse().ok();
}
}
if line.starts_with("Free (estimated):") {
if let Some(value) = line.split(':').nth(1) {
let number = value.trim().split_whitespace().next()?;
free_bytes = number.parse().ok();
}
}
}
Some(BtrfsSpace {
total_bytes: used_bytes? + free_bytes?,
used_bytes: used_bytes?,
free_bytes: free_bytes?,
})
}