Skip to main content

libbsd_sys/
lib.rs

1//! Raw FFI bindings to libbsd.
2//!
3//! This crate provides `extern "C"` declarations for the functions and types
4//! exported by [libbsd](https://libbsd.freedesktop.org/), a library that
5//! provides commonly-used BSD functions on GNU/Linux systems.
6//!
7//! # Platform support
8//!
9//! On **macOS**, **FreeBSD**, **OpenBSD**, and **NetBSD**,
10//! most of these functions are already part of the system C library, so no
11//! additional library is needed.
12//!
13//! On **Linux**, the crate uses `pkg-config` at build time to locate libbsd.
14//! On Debian/Ubuntu, install the development headers with:
15//!
16//! ```sh
17//! apt install libbsd-dev
18//! ```
19//!
20//! On **Windows** and other unsupported platforms, this crate is empty.
21//!
22//! # Conditional compilation
23//!
24//! Functions that only exist in libbsd (not on any BSD natively) are gated
25//! behind `#[cfg(target_os = "linux")]`. Functions available on the BSDs but
26//! not macOS are gated behind `#[cfg(not(target_os = "macos"))]`.
27//!
28//! The `strnvis` and `strnunvis` functions have different parameter orders
29//! depending on whether the platform follows the NetBSD convention (macOS,
30//! NetBSD, OpenBSD) or the FreeBSD convention (FreeBSD, Linux/libbsd).
31
32#![no_std]
33#![allow(non_camel_case_types)]
34
35#[cfg(not(target_os = "windows"))]
36mod imp;
37#[cfg(not(target_os = "windows"))]
38pub use imp::*;
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn smoke_arc4random() {
46        unsafe {
47            let _ = arc4random();
48        }
49    }
50
51    #[test]
52    fn smoke_strlcpy() {
53        let src = b"hello\0";
54        let mut dst = [0u8; 16];
55        unsafe {
56            let n = strlcpy(
57                dst.as_mut_ptr().cast(),
58                src.as_ptr().cast(),
59                dst.len() as size_t,
60            );
61            assert_eq!(n, 5);
62            assert_eq!(&dst[..6], b"hello\0");
63        }
64    }
65
66    #[test]
67    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
68    fn smoke_humanize_number() {
69        let mut buf = [0u8; 16];
70        unsafe {
71            let ret = humanize_number(
72                buf.as_mut_ptr().cast(),
73                buf.len() as size_t,
74                1024 * 1024,
75                b"\0".as_ptr().cast(),
76                HN_AUTOSCALE,
77                HN_DECIMAL | HN_NOSPACE | HN_B,
78            );
79            assert!(ret >= 0);
80        }
81    }
82
83    #[test]
84    fn smoke_arc4random_uniform() {
85        unsafe {
86            let val = arc4random_uniform(100);
87            assert!(val < 100);
88        }
89    }
90
91    #[test]
92    fn smoke_strtonum() {
93        let s = b"42\0";
94        let mut errstr: *const core::ffi::c_char = core::ptr::null();
95        unsafe {
96            let val = strtonum(s.as_ptr().cast(), 0, 100, &mut errstr);
97            assert_eq!(val, 42);
98            assert!(errstr.is_null());
99        }
100    }
101
102    #[test]
103    fn smoke_getprogname() {
104        unsafe {
105            let name = getprogname();
106            assert!(!name.is_null());
107        }
108    }
109
110    #[test]
111    fn smoke_vis_str() {
112        let src = b"hello\tworld\0";
113        let mut dst = [0u8; 64];
114        unsafe {
115            let ret = strvis(dst.as_mut_ptr().cast(), src.as_ptr().cast(), VIS_TAB);
116            assert!(ret > 0);
117        }
118    }
119}