diff --git a/crates/utils/src/os/unix.rs b/crates/utils/src/os/unix.rs index 05273ecf..dce38318 100644 --- a/crates/utils/src/os/unix.rs +++ b/crates/utils/src/os/unix.rs @@ -13,10 +13,47 @@ // limitations under the License. use super::{DiskInfo, IOStats}; +use nix::sys::statfs::Statfs; use nix::sys::{stat::stat, statfs::statfs}; use std::io::Error; use std::path::Path; +// FreeBSD and OpenBSD return a signed integer for blocks_available. +// Cast to an unsigned integer to use with DiskInfo. +#[cfg(any(target_os = "freebsd", target_os = "openbsd"))] +fn blocks_available(stat: &Statfs) -> u64 { + match stat.blocks_available().try_into() { + Ok(bavail) => bavail, + Err(e) => { + tracing::warn!("blocks_available returned a negative value: Using 0 as fallback. {}", e); + 0 + } + } +} + +// FreeBSD returns a signed integer for files_free. Cast to an unsigned integer +// to use with DiskInfo +#[cfg(target_os = "freebsd")] +fn files_free(stat: &Statfs) -> u64 { + match stat.files_free().try_into() { + Ok(files_free) => files_free, + Err(e) => { + tracing::warn!("files_free returned a negative value: Using 0 as fallback. {}", e); + 0 + } + } +} + +#[cfg(not(target_os = "freebsd"))] +fn files_free(stat: &Statfs) -> u64 { + stat.files_free() +} + +#[cfg(not(any(target_os = "freebsd", target_os = "openbsd")))] +fn blocks_available(stat: &Statfs) -> u64 { + stat.blocks_available() +} + /// Returns total and free bytes available in a directory, e.g. `/`. pub fn get_info(p: impl AsRef) -> std::io::Result { let path_display = p.as_ref().display(); @@ -24,7 +61,7 @@ pub fn get_info(p: impl AsRef) -> std::io::Result { let bsize = stat.block_size() as u64; let bfree = stat.blocks_free(); - let bavail = stat.blocks_available(); + let bavail = blocks_available(&stat); let blocks = stat.blocks(); let reserved = match bfree.checked_sub(bavail) { @@ -60,7 +97,7 @@ pub fn get_info(p: impl AsRef) -> std::io::Result { free, used, files: stat.files(), - ffree: stat.files_free(), + ffree: files_free(&stat), fstype: stat.filesystem_type_name().to_string(), ..Default::default() })