diff --git a/Cargo.toml b/Cargo.toml index dc453fc..76e70da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,5 @@ license = "MIT/Apache 2.0" edition = "2018" [dependencies] +ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" } libc = "0.2.116" diff --git a/src/lib.rs b/src/lib.rs index 7783976..e57233e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,3 +67,45 @@ unsafe extern "C" fn clock_gettime( retval } + +#[no_mangle] +unsafe extern "C" fn getrandom( + buf: *mut libc::c_void, + mut buflen: libc::size_t, + flags: libc::c_uint, +) -> libc::ssize_t { + // Based on https://man7.org/linux/man-pages/man2/getrandom.2.html + // Technically we only have one source (no true /dev/random), but the + // behavior should be more expected this way. + let maxlen = if flags & libc::GRND_RANDOM != 0 { + 512 + } else { + 0x1FFFFFF + }; + buflen = buflen.min(maxlen); + + let ret = ctru_sys::PS_GenerateRandomBytes(buf, buflen as libc::c_uint); + + // avoid conflicting a real POSIX errno by using a value < 0 + // should we define this in ctru-sys somewhere or something? + const ECTRU: libc::c_int = -1; + + if ctru_sys::R_SUCCEEDED(ret) { + // safe because above ensures buflen < isize::MAX + buflen as libc::ssize_t + } else { + // best-effort attempt at translating return codes + *__errno() = match ctru_sys::R_SUMMARY(ret) as libc::c_uint { + ctru_sys::RS_WOULDBLOCK => libc::EAGAIN, + ctru_sys::RS_INVALIDARG | ctru_sys::RS_WRONGARG => { + match ctru_sys::R_DESCRIPTION(ret) as libc::c_uint { + // most likely user error, forgot to initialize PS module + ctru_sys::RD_INVALID_HANDLE => ECTRU, + _ => libc::EINVAL, + } + } + _ => ECTRU, + }; + -1 + } +}