From a6fffd3fb57b96e4b4769da2e205f2a2be09a23f Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jeremy@system76.com>
Date: Fri, 22 May 2020 11:50:54 -0600
Subject: [PATCH] Add getrandom and sys/random.h

---
 src/header/mod.rs                   |  1 +
 src/header/sys_random/cbindgen.toml |  9 +++++++++
 src/header/sys_random/mod.rs        | 14 ++++++++++++++
 src/platform/linux/mod.rs           |  4 ++++
 src/platform/pal/mod.rs             |  2 ++
 src/platform/redox/mod.rs           | 28 ++++++++++++++++++++++++++++
 src/platform/test/mod.rs            | 19 +++++++++++++++++++
 7 files changed, 77 insertions(+)
 create mode 100644 src/header/sys_random/cbindgen.toml
 create mode 100644 src/header/sys_random/mod.rs

diff --git a/src/header/mod.rs b/src/header/mod.rs
index 2de117858..81934256d 100644
--- a/src/header/mod.rs
+++ b/src/header/mod.rs
@@ -50,6 +50,7 @@ pub mod _wctype;
 pub mod arch_aarch64_user;
 pub mod arch_x64_user;
 pub mod sys_procfs;
+pub mod sys_random;
 pub mod sys_uio;
 pub mod sys_un;
 pub mod sys_utsname;
diff --git a/src/header/sys_random/cbindgen.toml b/src/header/sys_random/cbindgen.toml
new file mode 100644
index 000000000..d83dd8b5e
--- /dev/null
+++ b/src/header/sys_random/cbindgen.toml
@@ -0,0 +1,9 @@
+sys_includes = ["sys/types.h"]
+include_guard = "_SYS_RANDOM_H"
+language = "C"
+style = "Tag"
+no_includes = true
+cpp_compat = true
+
+[enum]
+prefix_with_name = true
diff --git a/src/header/sys_random/mod.rs b/src/header/sys_random/mod.rs
new file mode 100644
index 000000000..bc90bfa65
--- /dev/null
+++ b/src/header/sys_random/mod.rs
@@ -0,0 +1,14 @@
+use core::slice;
+
+use crate::platform::{Pal, Sys, types::*};
+
+pub const GRND_NONBLOCK: c_uint = 1;
+pub const GRND_RANDOM: c_uint = 2;
+
+#[no_mangle]
+unsafe extern "C" fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t {
+    Sys::getrandom(slice::from_raw_parts_mut(
+        buf as *mut u8,
+        buflen as usize
+    ), flags)
+}
diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 19b908ffe..3115b2805 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -254,6 +254,10 @@ impl Pal for Sys {
         e(unsafe { syscall!(GETPPID) }) as pid_t
     }
 
+    fn getrandom(buf: &mut [u8], flags: c_uint) -> ssize_t {
+        e(unsafe { syscall!(GETRANDOM, buf.as_mut_ptr(), buf.len(), flags) }) as ssize_t
+    }
+
     unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int {
         e(syscall!(GETRLIMIT, resource, rlim)) as c_int
     }
diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs
index 9900e378d..f7984dac6 100644
--- a/src/platform/pal/mod.rs
+++ b/src/platform/pal/mod.rs
@@ -91,6 +91,8 @@ pub trait Pal {
 
     fn getppid() -> pid_t;
 
+    fn getrandom(buf: &mut [u8], flags: c_uint) -> ssize_t;
+
     unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int;
 
     fn gettid() -> pid_t;
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index b77cf63d1..58117dd32 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -13,6 +13,7 @@ use crate::{
         errno::{EINVAL, EIO, EPERM, ERANGE},
         fcntl,
         sys_mman::MAP_ANON,
+        sys_random,
         sys_resource::{rlimit, RLIM_INFINITY},
         sys_stat::stat,
         sys_statvfs::statvfs,
@@ -555,6 +556,33 @@ impl Pal for Sys {
         e(syscall::getppid()) as pid_t
     }
 
+    fn getrandom(buf: &mut [u8], flags: c_uint) -> ssize_t {
+        //TODO: make this a system call?
+
+        let path = if flags & sys_random::GRND_RANDOM != 0 {
+            //TODO: /dev/random equivalent
+            "rand:"
+        } else {
+            "rand:"
+        };
+
+        let mut open_flags = syscall::O_RDONLY | syscall::O_CLOEXEC;
+        if flags & sys_random::GRND_NONBLOCK != 0 {
+            open_flags |= syscall::O_NONBLOCK;
+        }
+
+        let fd = e(syscall::open(path, open_flags));
+        if fd == !0 {
+            return -1;
+        }
+
+        let res = e(syscall::read(fd, buf)) as ssize_t;
+
+        let _ = syscall::close(fd);
+
+        res
+    }
+
     unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int {
         //TODO
         if !rlim.is_null() {
diff --git a/src/platform/test/mod.rs b/src/platform/test/mod.rs
index 01889bb35..d5fb9e047 100644
--- a/src/platform/test/mod.rs
+++ b/src/platform/test/mod.rs
@@ -63,3 +63,22 @@ fn clock_gettime() {
         assert_ne!(timespec.tv_nsec, -1);
     }
 }
+
+//TDOO: everything else
+
+#[test]
+fn getrandom() {
+    use crate::header::sys_random;
+    use crate::platform::types::ssize_t;
+
+    let mut arrays = [[0; 32]; 32];
+    for i in 1..arrays.len() {
+        assert_eq!(Sys::getrandom(&mut arrays[i], 0), arrays[i].len() as ssize_t);
+
+        for j in 0..arrays.len() {
+            if i != j {
+                assert_ne!(&arrays[i], &arrays[j]);
+            }
+        }
+    }
+}
-- 
GitLab