fix: disque via statvfs() — valeurs identiques à df

Remplace sysinfo::Disks par un appel direct à libc::statvfs("/").
- used  = (f_blocks − f_bfree) × f_frsize  → correspond à df "Utilisé"
- free  = f_bavail × f_frsize              → correspond à df "Dispo"
- total = f_blocks × f_frsize

Avant (sysinfo) : used comptait les blocs réservés root → surestimation de ~3-4 Go.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gilles Soulier
2026-05-22 20:21:58 +02:00
co-authored by Claude Sonnet 4.6
parent e0ed96309c
commit 243c97d71b
4 changed files with 26 additions and 24 deletions
+1
View File
@@ -250,6 +250,7 @@ dependencies = [
name = "nanometrics-agent" name = "nanometrics-agent"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"libc",
"rumqttc", "rumqttc",
"serde", "serde",
"serde_json", "serde_json",
+1
View File
@@ -19,6 +19,7 @@ codegen-units = 1
[dependencies] [dependencies]
sysinfo = { version = "0.30", default-features = false } sysinfo = { version = "0.30", default-features = false }
libc = "0.2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
toml = "0.8" toml = "0.8"
+2 -4
View File
@@ -1,5 +1,5 @@
use nanometrics_agent::{config, metrics, payload, transport}; use nanometrics_agent::{config, metrics, payload, transport};
use sysinfo::{Components, Disks, Networks, System}; use sysinfo::{Components, Networks, System};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::sync::mpsc; use std::sync::mpsc;
@@ -34,7 +34,6 @@ fn main() {
let mut sys = System::new(); let mut sys = System::new();
let mut networks = Networks::new_with_refreshed_list(); let mut networks = Networks::new_with_refreshed_list();
let mut disks = Disks::new_with_refreshed_list();
let mut components = Components::new_with_refreshed_list(); let mut components = Components::new_with_refreshed_list();
let udp_sender = if cfg.protocols.udp.enabled { let udp_sender = if cfg.protocols.udp.enabled {
@@ -102,9 +101,8 @@ fn main() {
} }
if first_slow || now.duration_since(last_slow).as_secs() >= 60 { if first_slow || now.duration_since(last_slow).as_secs() >= 60 {
disks.refresh();
if cfg.metrics.disk.udp || cfg.metrics.disk.mqtt { if cfg.metrics.disk.udp || cfg.metrics.disk.mqtt {
let (used, free, total) = metrics::disk::get(&disks); let (used, free, total) = metrics::disk::get();
m.hdd_used = Some(used); m.hdd_used = Some(used);
m.hdd_free = Some(free); m.hdd_free = Some(free);
m.hdd_total = Some(total); m.hdd_total = Some(total);
+22 -20
View File
@@ -1,34 +1,36 @@
use sysinfo::Disks; use std::mem::MaybeUninit;
pub fn get(disks: &Disks) -> (u64, u64, u64) { /// Retourne (used, free, total) en octets pour le système de fichiers racine "/".
for disk in disks.list() { /// Utilise statvfs() directement pour correspondre exactement aux chiffres de `df` :
let mount = disk.mount_point().to_string_lossy(); /// - total = f_blocks × f_frsize
if mount == "/" { /// - used = (f_blocks − f_bfree) × f_frsize (blocs effectivement écrits)
let total = disk.total_space(); /// - free = f_bavail × f_frsize (disponible pour utilisateurs non-root)
let free = disk.available_space(); pub fn get() -> (u64, u64, u64) {
let used = total.saturating_sub(free); let path = b"/\0";
return (used, free, total); let mut stat = MaybeUninit::<libc::statvfs>::uninit();
} let ret = unsafe { libc::statvfs(path.as_ptr() as *const libc::c_char, stat.as_mut_ptr()) };
if ret != 0 {
return (0, 0, 0);
} }
if let Some(disk) = disks.list().first() { let stat = unsafe { stat.assume_init() };
let total = disk.total_space(); let bsize = stat.f_frsize as u64;
let free = disk.available_space(); let total = stat.f_blocks.saturating_mul(bsize);
return (total.saturating_sub(free), free, total); let used = stat.f_blocks.saturating_sub(stat.f_bfree).saturating_mul(bsize);
} let free = stat.f_bavail.saturating_mul(bsize);
(0, 0, 0) (used, free, total)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use sysinfo::Disks;
#[test] #[test]
fn test_disk_coherent() { fn test_disk_coherent() {
let disks = Disks::new_with_refreshed_list(); let (used, free, total) = get();
let (used, free, total) = get(&disks); eprintln!("résultat statvfs : used={used} free={free} total={total}");
if total > 0 { if total > 0 {
assert!(used + free <= total + 1024, "used + free > total"); assert!(used + free <= total + 1024 * 1024, "used + free > total");
assert!(total > 0, "total doit être > 0");
} }
} }
} }