diff options
author | Davidlohr Bueso | 2012-04-05 23:52:04 +0200 |
---|---|---|
committer | Karel Zak | 2012-04-10 13:12:43 +0200 |
commit | fe72459e414e0d1a55f93e0035766d2313362ac2 (patch) | |
tree | c4babbef2b84fcaf03585c98a3cfae84da2fcbd7 | |
parent | lib/blkdev: fix compiler warning [-Wreturn-type] (diff) | |
download | kernel-qcow2-util-linux-fe72459e414e0d1a55f93e0035766d2313362ac2.tar.gz kernel-qcow2-util-linux-fe72459e414e0d1a55f93e0035766d2313362ac2.tar.xz kernel-qcow2-util-linux-fe72459e414e0d1a55f93e0035766d2313362ac2.zip |
lib: random utilities
Add a random number(s) generator specific file. The intial functions are based
on what libuuid provide. I did some modifications like avoid WIN32 checks - this
is util-LINUX.
[kzak@redhat.com: - move jrand_seed to lib/randutils.c
- use TLS for jrand_seed (like original code from libuuid)
- use size_t for buffer sizes
- add close() to random_get_bytes]
Signed-off-by: Davidlohr Bueso <dave@gnu.org>
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r-- | include/randutils.h | 12 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/randutils.c | 120 |
3 files changed, 134 insertions, 0 deletions
diff --git a/include/randutils.h b/include/randutils.h new file mode 100644 index 000000000..dec5e355a --- /dev/null +++ b/include/randutils.h @@ -0,0 +1,12 @@ +#ifndef UTIL_LINUX_RANDUTILS +#define UTIL_LINUX_RANDUTILS + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +extern int random_get_fd(void); +extern void random_get_bytes(void *buf, size_t nbytes); + +#endif diff --git a/lib/Makefile.am b/lib/Makefile.am index c34481de3..fc967fcbd 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -10,6 +10,7 @@ noinst_PROGRAMS = \ test_ismounted \ test_mangle \ test_procutils \ + test_randutils \ test_strutils \ test_tt \ test_wholedisk @@ -30,6 +31,7 @@ test_at_SOURCES = at.c test_at_CFLAGS = -DTEST_PROGRAM_AT test_strutils_SOURCES = strutils.c +test_randutils_SOURCES = randutils.c test_procutils_SOURCES = procutils.c if LINUX diff --git a/lib/randutils.c b/lib/randutils.c new file mode 100644 index 000000000..b90c88691 --- /dev/null +++ b/lib/randutils.c @@ -0,0 +1,120 @@ +/* + * General purpose random utilities + */ + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include <sys/syscall.h> + +#include "randutils.h" + +#ifdef HAVE_TLS +#define THREAD_LOCAL static __thread +#else +#define THREAD_LOCAL static +#endif + +#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) +#define DO_JRAND_MIX +THREAD_LOCAL unsigned short ul_jrand_seed[3]; +#endif + +int random_get_fd(void) +{ + int i, fd; + struct timeval tv; + + gettimeofday(&tv, 0); + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + fd = open("/dev/random", O_RDONLY | O_NONBLOCK); + if (fd >= 0) { + i = fcntl(fd, F_GETFD); + if (i >= 0) + fcntl(fd, F_SETFD, i | FD_CLOEXEC); + } + srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); + +#ifdef DO_JRAND_MIX + ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); + ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); + ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; +#endif + /* Crank the random number generator a few times */ + gettimeofday(&tv, 0); + for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) + rand(); + return fd; +} + + +/* + * Generate a stream of random nbytes into buf. + * Use /dev/urandom if possible, and if not, + * use glibc pseudo-random functions. + */ +void random_get_bytes(void *buf, size_t nbytes) +{ + size_t i, n = nbytes; + int fd = random_get_fd(); + int lose_counter = 0; + unsigned char *cp = (unsigned char *) buf; + + if (fd >= 0) { + while (n > 0) { + ssize_t x = read(fd, cp, n); + if (x <= 0) { + if (lose_counter++ > 16) + break; + continue; + } + n -= x; + cp += x; + lose_counter = 0; + } + + close(fd); + } + + /* + * We do this all the time, but this is the only source of + * randomness if /dev/random/urandom is out to lunch. + */ + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (rand() >> 7) & 0xFF; + +#ifdef DO_JRAND_MIX + { + unsigned short tmp_seed[3]; + + memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed)); + ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid); + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; + memcpy(ul_jrand_seed, tmp_seed, + sizeof(ul_jrand_seed)-sizeof(unsigned short)); + } +#endif + + return; +} + +#ifdef TEST_PROGRAM +int main(int argc, char *argv[]) +{ + unsigned int v, i; + + /* generate and print 10 random numbers */ + for (i = 0; i < 10; i++) { + random_get_bytes(&v, sizeof(v)); + printf("%d\n", v); + } + + return EXIT_SUCCESS; +} +#endif /* TEST_PROGRAM */ |