4

Silly question, I'm probably missing a header, but the man page says I just need #include <linux/random.h>.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <linux/random.h>

#define BITS 8192
#define BYTES (BITS >> 3)

int main() {
    uint8_t array[BYTES];

    printf("started...");
    int r = getrandom(array, BYTES, 0);
    if (r) exit(1);

    return 0;
}

Error is:

chris@purple:~/lunch/bitarray$ make && ./bitarray 
clang -g -Wall -Wpedantic -Werror -std=c11 -O2 -save-temps bitarray.c -o bitarray
bitarray.c:13:10: error: implicit declaration of function 'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
 int r = getrandom(array, (8192 >> 3), 0);
         ^
1 error generated.
Makefile:10: recipe for target 'bitarray' failed
make: *** [bitarray] Error 1

(Also fails in gcc.)

chris@purple:~/lunch/bitarray$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
chris@purple:~/lunch/bitarray$ uname -a
Linux purple 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17:54:43 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 3
    Yup, your compile error is exactly consistent with that function prototype not being in the header. Documentation, eh? – Bathsheba Jul 21 '17 at 12:11
  • @MichaelWalz `chris@purple:~/lunch/bitarray$ make && ./bitarray clang -g -Wall -Wpedantic -Werror -std=c11 -O2 -save-temps bitarray.c -o bitarray bitarray.c:5:10: fatal error: 'sys/random.h' file not found #include ` – fadedbee Jul 21 '17 at 12:13
  • Manpage here says `` - and that's definitely wrong: no such file or directory! – Toby Speight Jul 21 '17 at 12:13
  • Other than the obvious, the *only* thing I can think of here is an "include guard clash". Is the above your real program? – Bathsheba Jul 21 '17 at 12:15
  • @Bathsheba yes. – fadedbee Jul 21 '17 at 12:15
  • 1
    On Debian, the C binding doesn't seem to be defined - try `grep --color -nH -r getrandom /usr/include/` to show. That turns up the `SYSCALL()` macro, but no C function. Does the install enable that only if you have a new enough kernel, perhaps? – Toby Speight Jul 21 '17 at 12:17
  • Probably there is no `getrandom` function declared in your `linux/random.h`. You can check this easily on your system. – Jabberwocky Jul 21 '17 at 12:17
  • There is no `getrandom` function declared anywhere under '/usr/include'. But the manpage is there and the kernel is new enough. Same as Debian. – fadedbee Jul 21 '17 at 12:21
  • @TobySpeight Can I access it directly though the SYSCALL macro in some way? – fadedbee Jul 21 '17 at 12:22
  • 1
    @chrisdew then you probably need to live with that. Or try to google "getrandom not declared linux". – Jabberwocky Jul 21 '17 at 12:24
  • 1
    I've never done it, but something like `syscall(SYS_getrandom, array, BYTES, 0)`. See the `syscall()` man page, and you might need to include ``. Probably worth wrapping in a function (as glibc would) so that you can get strongly-typed arguments again. – Toby Speight Jul 21 '17 at 12:24
  • @TobySpeight Make that an answer and I'll accept it. – fadedbee Jul 21 '17 at 12:29
  • @MichaelWalz Googled and found lots of pages for this bug - I had wrongly assumed that it was my rusty C at fault, not a bad man page/distro. – fadedbee Jul 21 '17 at 12:30
  • Also see: https://shiliangya.blogspot.co.uk/2016/01/linux-ramdom-syscall-not-found.html – fadedbee Jul 21 '17 at 12:31
  • Sorry for the delay - I needed to compile and test before I'm willing to post as answer. – Toby Speight Jul 21 '17 at 12:31

1 Answers1

6

It appears that some Linux systems have a man page for getrandom and the correct syscall definitions, but no C function. It does give you enough to create your own:

// _GNU_SOURCE should be set before *any* includes.
// Alternatively, pass to compiler with -D, or enable GNU extensions
// with -std=gnu11 (or omit -std completely)
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>

int my_getrandom(void *buf, size_t buflen, unsigned int flags)
{
    return (int)syscall(SYS_getrandom, buf, buflen, flags);
}

// remove this when we have a real getrandom():
#define getrandom  my_getrandom
// and replace it with
// #include <linux/random.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define BITS 8192
#define BYTES (BITS >> 3)

int main() {
    uint8_t array[BYTES];

    printf("started...\n");
    int r = getrandom(array, sizeof array, 0);
    return r;
}
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • 1
    Or compile with `-std=gnu11` to enable GNU extensions by default. Using `-std=c11` turns off the extensions unless they're explicitly enabled, which is what your `#define` does. – Jonathan Leffler Jul 21 '17 at 12:39
  • Ah yes, I compile standard C by habit. – Toby Speight Jul 21 '17 at 12:40
  • 1
    I use `-std=c11` by default too. When it matters, I use a header to define the relevant symbols (usually `_XOPEN_VERSION` to enable POSIX features. My code mostly has to work in non-GNU environments (like macOS) so I don't use GNU source all that often. – Jonathan Leffler Jul 21 '17 at 12:44