1use std::process::Command;
2
3#[derive(Debug, serde::Serialize)]
4pub struct BtrfsSpace {
5 pub total_bytes: u128,
6 pub used_bytes: u128,
7 pub free_bytes: u128,
8}
9
10pub fn get_space(path: &str) -> Result<BtrfsSpace, String> {
11 let output = Command::new("btrfs")
12 .args(["filesystem", "usage", "--raw", path])
13 .output()
14 .map_err(|e| e.to_string())?;
15
16 if !output.status.success() {
17 return Err(String::from_utf8_lossy(&output.stderr).to_string());
18 }
19
20 let stdout = String::from_utf8_lossy(&output.stdout);
21
22 derive_space(&stdout).ok_or("Failed to parse space info".into())
23}
24
25fn derive_space(output: &str) -> Option<BtrfsSpace> {
26 let mut used_bytes: Option<u128> = None;
27 let mut free_bytes: Option<u128> = None;
28
29 for line in output.lines() {
30 let line = line.trim();
31
32 if line.starts_with("Used:") {
33 if let Some(value) = line.split(':').nth(1) {
34 let number = value.trim().split_whitespace().next()?;
35 used_bytes = number.parse().ok();
36 }
37 }
38
39 if line.starts_with("Free (estimated):") {
40 if let Some(value) = line.split(':').nth(1) {
41 let number = value.trim().split_whitespace().next()?;
42 free_bytes = number.parse().ok();
43 }
44 }
45 }
46
47 Some(BtrfsSpace {
48 total_bytes: used_bytes? + free_bytes?,
49 used_bytes: used_bytes?,
50 free_bytes: free_bytes?,
51 })
52}