c-scape 0.22.3

A libc bottom-half implementation in Rust
Documentation
use crate::convert_res;
use core::mem::MaybeUninit;
use core::slice;
#[cfg(not(target_env = "musl"))]
use errno::{set_errno, Errno};
use libc::c_void;

#[cfg(any(target_os = "android", target_os = "linux"))]
#[no_mangle]
unsafe extern "C" fn getrandom(ptr: *mut c_void, len: usize, flags: u32) -> isize {
    libc!(libc::getrandom(ptr, len, flags));

    if len == 0 {
        return 0;
    }

    let flags = rustix::rand::GetRandomFlags::from_bits_retain(flags);
    let buf = slice::from_raw_parts_mut(ptr.cast::<MaybeUninit<u8>>(), len);

    match convert_res(rustix::rand::getrandom(buf, flags)) {
        Some((init, _uninit)) => init.len() as isize,
        None => -1,
    }
}

#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(not(target_env = "musl"))]
#[no_mangle]
unsafe extern "C" fn getentropy(ptr: *mut c_void, len: usize) -> i32 {
    libc!(libc::getentropy(ptr, len));

    if len == 0 {
        return 0;
    }

    if len > 256 {
        set_errno(Errno(libc::EIO));
        return -1;
    }

    let flags = rustix::rand::GetRandomFlags::empty();
    let buf = slice::from_raw_parts_mut(ptr.cast::<MaybeUninit<u8>>(), len);

    let mut filled = 0usize;

    while filled < buf.len() {
        match rustix::rand::getrandom(&mut buf[filled..], flags) {
            Ok((init, _uninit)) => filled += init.len(),
            Err(rustix::io::Errno::INTR) => {}
            Err(err) => {
                set_errno(Errno(err.raw_os_error()));
                return -1;
            }
        }
    }

    0
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(any(target_os = "android", target_os = "linux"))]
    #[test]
    fn test_getentropy() {
        unsafe {
            let mut buf = [0; 257];
            assert_eq!(getentropy(buf.as_mut_ptr().cast(), 257), -1);
            assert_eq!(errno::errno().0, libc::EIO);

            let mut buf = [0; 257];
            assert_eq!(getentropy(buf.as_mut_ptr().cast(), 256), 0);
            assert!(buf.iter().any(|b| *b != 0));
        }
    }
}