aboutsummaryrefslogtreecommitdiffstats
path: root/libtest/random.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libtest/random.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/libtest/random.c b/libtest/random.c
new file mode 100644
index 0000000..77e9218
--- /dev/null
+++ b/libtest/random.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+unsigned char *libtest_random_pattern = NULL;
+size_t libtest_random_pattern_length = 0u;
+size_t libtest_random_pattern_offset = 0u;
+
+static ssize_t
+genpattern(void *buf, size_t size)
+{
+ unsigned char *out = buf;
+ size_t n;
+
+ if (size > (size_t)SSIZE_MAX)
+ size = (size_t)SSIZE_MAX;
+
+ if (libtest_random_pattern_length) {
+ while (size) {
+ if (libtest_random_pattern_offset == libtest_random_pattern_length)
+ libtest_random_pattern_offset = 0u;
+ n = libtest_random_pattern_length - libtest_random_pattern_offset;
+ if (n > size)
+ n = size;
+ memcpy(out, &libtest_random_pattern[libtest_random_pattern_offset], n);
+ out = &out[n];
+ size -= n;
+ libtest_random_pattern_offset += n;
+ }
+ } else {
+ for (; size; size--, out++)
+ out[0] = (unsigned char)rand();
+ }
+
+ return (ssize_t)size;
+}
+
+
+#if defined(__linux__)
+int libtest_getrandom_real = 1;
+int libtest_getrandom_error = 0;
+size_t libtest_getrandom_max_return = SIZE_MAX;
+
+ssize_t
+(getrandom)(void *buf, size_t size, unsigned int flags)
+{
+ if (size > libtest_getrandom_max_return)
+ size = libtest_getrandom_max_return;
+
+ if (libtest_getrandom_error) {
+ errno = libtest_getrandom_error;
+ if (libtest_getrandom_error == EINTR)
+ libtest_getrandom_error = 0;
+ return -1;
+ }
+
+ if (!libtest_getrandom_real)
+ return genpattern(buf, size);
+
+# if defined(SYS_getrandom)
+ return syscall(SYS_getrandom, buf, size, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+
+int libtest_getentropy_real = 1;
+int libtest_getentropy_error = 0;
+size_t libtest_getentropy_calls = 0u;
+int libtest_getentropy_jmp_val = 0;
+jmp_buf libtest_getentropy_jmp;
+
+int
+(getentropy)(void *buf, size_t size)
+{
+ unsigned char *out = buf;
+ ssize_t r;
+
+ libtest_getentropy_calls += 1u;
+
+ if (libtest_getentropy_jmp_val)
+ longjmp(libtest_getentropy_jmp, libtest_getentropy_jmp_val);
+
+ if (libtest_getentropy_error) {
+ errno = libtest_getentropy_error;
+ if (libtest_getentropy_error == EINTR)
+ libtest_getentropy_error = 0;
+ return -1;
+ }
+
+ if (size > 256u) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (!libtest_getentropy_real) {
+ r = genpattern(out, size);
+ if (r == (ssize_t)size)
+ return 0;
+ errno = EIO;
+ return -1;
+ }
+
+#if defined(__linux__) && defined(SYS_getrandom)
+ while (size) {
+ r = (ssize_t)syscall(SYS_getrandom, out, size, 0);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno != ENOSYS)
+ errno = EIO;
+ return -1;
+ }
+ out = &out[r];
+ size -= (size_t)r;
+ }
+ return 0;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+
+#else
+
+
+CONST int
+main(void)
+{
+ /* TODO maybe test */
+ return 0;
+}
+
+
+#endif