1 | //! Implementation for Linux / Android |
2 | use crate::{ |
3 | lazy::LazyBool, |
4 | util_libc::{last_os_error, sys_fill_exact}, |
5 | {use_file, Error}, |
6 | }; |
7 | use core::mem::MaybeUninit; |
8 | |
9 | pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { |
10 | // getrandom(2) was introduced in Linux 3.17 |
11 | static HAS_GETRANDOM: LazyBool = LazyBool::new(); |
12 | if HAS_GETRANDOM.unsync_init(is_getrandom_available) { |
13 | sys_fill_exact(buf:dest, |buf: &mut [MaybeUninit]| unsafe { |
14 | getrandom(buf:buf.as_mut_ptr() as *mut libc::c_void, buflen:buf.len(), flags:0) |
15 | }) |
16 | } else { |
17 | use_file::getrandom_inner(dest) |
18 | } |
19 | } |
20 | |
21 | fn is_getrandom_available() -> bool { |
22 | let res: isize = unsafe { getrandom(buf:core::ptr::null_mut(), buflen:0, flags:libc::GRND_NONBLOCK) }; |
23 | if res < 0 { |
24 | match last_os_error().raw_os_error() { |
25 | Some(libc::ENOSYS) => false, // No kernel support |
26 | Some(libc::EPERM) => false, // Blocked by seccomp |
27 | _ => true, |
28 | } |
29 | } else { |
30 | true |
31 | } |
32 | } |
33 | |
34 | unsafe fn getrandom( |
35 | buf: *mut libc::c_void, |
36 | buflen: libc::size_t, |
37 | flags: libc::c_uint, |
38 | ) -> libc::ssize_t { |
39 | libc::syscall(num:libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t |
40 | } |
41 | |