getrandom/backends/
linux_android_with_fallback.rs1use super::use_file;
3use crate::Error;
4use core::{
5 ffi::c_void,
6 mem::{MaybeUninit, transmute},
7 ptr::{self, NonNull},
8};
9use use_file::utils;
10
11pub use crate::util::{inner_u32, inner_u64};
12
13type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;
14
15const NOT_AVAILABLE: NonNull<c_void> = unsafe { NonNull::new_unchecked(usize::MAX as *mut c_void) };
18
19#[cold]
20#[inline(never)]
21fn init() -> NonNull<c_void> {
22 #[cfg(not(target_env = "musl"))]
24 let raw_ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"getrandom".as_ptr()) };
25 #[cfg(target_env = "musl")]
26 let raw_ptr = {
27 let fptr: GetRandomFn = libc::getrandom;
28 unsafe { transmute::<GetRandomFn, *mut c_void>(fptr) }
29 };
30
31 let res_ptr = match NonNull::new(raw_ptr) {
32 Some(fptr) => {
33 let getrandom_fn = unsafe { transmute::<*mut c_void, GetRandomFn>(fptr.as_ptr()) };
34 let res = unsafe { getrandom_fn(ptr::dangling_mut(), 0, 0) };
36 if cfg!(getrandom_test_linux_fallback) {
37 NOT_AVAILABLE
38 } else if res.is_negative() {
39 match utils::get_errno() {
40 libc::ENOSYS => NOT_AVAILABLE, #[cfg(target_os = "linux")]
45 libc::EPERM => NOT_AVAILABLE, _ => fptr,
47 }
48 } else {
49 fptr
50 }
51 }
52 None => NOT_AVAILABLE,
53 };
54
55 #[cfg(getrandom_test_linux_without_fallback)]
56 if res_ptr == NOT_AVAILABLE {
57 panic!("Fallback is triggered with enabled `getrandom_test_linux_without_fallback`")
58 }
59
60 res_ptr
61}
62
63#[inline(never)]
65fn use_file_fallback(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
66 use_file::fill_inner(dest)
67}
68
69#[inline]
70pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
71 #[path = "../utils/lazy_ptr.rs"]
72 mod lazy;
73
74 static GETRANDOM_FN: lazy::LazyPtr<c_void> = lazy::LazyPtr::new();
75 let fptr = GETRANDOM_FN.unsync_init(init);
76
77 if fptr == NOT_AVAILABLE {
78 use_file_fallback(dest)
79 } else {
80 let getrandom_fn = unsafe { transmute::<*mut c_void, GetRandomFn>(fptr.as_ptr()) };
82 utils::sys_fill_exact(dest, |buf| unsafe {
83 getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0)
84 })
85 }
86}