summaryrefslogtreecommitdiff
path: root/src/getrandom_linux.c
diff options
context:
space:
mode:
authorNils Maier <maierman@web.de>2015-02-06 17:33:22 +0100
committerNils Maier <maierman@web.de>2015-02-07 17:18:45 +0100
commitba0e32abaecedf3939905bd316336f313b3dd745 (patch)
tree16df1163a667b23a7c2f5211b6d7a3324db2d614 /src/getrandom_linux.c
parent9cbbe9f1bbb6d05b46fbf54b5c26cec62888ea79 (diff)
Handle linux getrandom returning EINTR on interrupts/signals
Also handle ENOTSUP failures where aria2 was build with linux headers newer than the actual running kernel. Fixes GH-336
Diffstat (limited to 'src/getrandom_linux.c')
-rw-r--r--src/getrandom_linux.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/src/getrandom_linux.c b/src/getrandom_linux.c
index 85314fd6..cbf4c32a 100644
--- a/src/getrandom_linux.c
+++ b/src/getrandom_linux.c
@@ -37,14 +37,42 @@
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/random.h>
+#include <errno.h>
+#include <linux/errno.h>
+#include <stdint.h>
+#include <stdio.h>
#include "config.h"
#include "getrandom_linux.h"
int getrandom_linux(void *buf, size_t buflen) {
+ int rv = 0;
+ uint8_t* p = buf;
+ while (buflen) {
+ int read;
#ifdef HAVE_GETRANDOM
- return getrandom(buf, buflen, 0);
+ read = getrandom(p, buflen, 0);
#else // HAVE_GETRANDOM
- return syscall(SYS_getrandom, buf, buflen, 0);
+ read = syscall(SYS_getrandom, p, buflen, 0);
+ /* Some libc impl. might mess this up */
+ if (read == -EINTR || read == -ERESTART) {
+ errno = EINTR;
+ read = -1;
+ }
+ if (read < -1) {
+ errno = -read;
+ read = -1;
+ }
#endif // HAVE_GETRANDOM
+ if (read < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return -1;
+ }
+ p += read;
+ rv += read;
+ buflen -= read;
+ }
+ return rv;
}