-rw-r--r-- 1672 librandombytes-20240318/kernel/getrandom_wrapper.c raw
// version 20230126
// public domain
// djb
// planned long-term cleanup:
// once all systems support getrandom() via sys/random.h,
// get rid of the other options and the SIGSYS handling
#include <unistd.h>
// automatic-alternatives 5
#ifdef getrandom_wrapper_5
#include "getrandom_wrapper.h"
int getrandom_wrapper_ready(void)
{
return 0;
}
void getrandom_wrapper(void *x,long long xbytes)
{
for (;;) pause();
}
#else
#include <errno.h>
#include <signal.h>
#ifdef getrandom_wrapper_1
#include <sys/random.h>
#endif
#ifdef getrandom_wrapper_2
#include <linux/random.h>
#endif
#ifdef getrandom_wrapper_3
#include <syscall.h>
#define getrandom(a,b,c) syscall(SYS_getrandom,a,b,c)
#endif
#ifdef getrandom_wrapper_4
#include <syscall.h>
#define getrandom(a,b,c) syscall(__NR_getrandom,a,b,c)
#endif
#include "getrandom_wrapper.h"
static int getrandom_wrapper_ready_core(void)
{
char ch;
int r;
for (;;) {
errno = 0;
r = getrandom(&ch,1,0);
if (r == 1) return 1;
if (r == -1 && errno == ENOSYS) return 0;
if (r == -1 && errno == EPERM) return 0; // QNAP bug
if (r == -1 && errno == EINVAL) return 0;
}
}
int getrandom_wrapper_ready(void)
{
struct sigaction old_sigsys;
int result;
sigaction(SIGSYS,0,&old_sigsys);
signal(SIGSYS,SIG_IGN);
result = getrandom_wrapper_ready_core();
sigaction(SIGSYS,&old_sigsys,0);
return result;
}
void getrandom_wrapper(void *x,long long xbytes)
{
while (xbytes > 0) {
int todo = 1048576;
if (xbytes < 1048576) todo = xbytes;
todo = getrandom(x,todo,0);
if (todo < 1) {
sleep(1);
continue;
}
x += todo;
xbytes -= todo;
}
}
#endif