diff options
| author | Philipp Klaus <philipp.klaus@gmail.com> | 2011-06-21 17:12:21 +0200 |
|---|---|---|
| committer | Philipp Klaus <philipp.klaus@gmail.com> | 2011-06-21 17:12:21 +0200 |
| commit | 4535ac486ce87b6a7257a7959426138405b7ecf8 (patch) | |
| tree | 2b397f1430e62032aa696dd8fe0b91fd8b6a3269 /randnum.c | |
| download | pwgen-4535ac486ce87b6a7257a7959426138405b7ecf8.zip | |
automatic commit for pwgen-2.0
Diffstat (limited to 'randnum.c')
| -rw-r--r-- | randnum.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/randnum.c b/randnum.c new file mode 100644 index 0000000..3f22cfe --- /dev/null +++ b/randnum.c @@ -0,0 +1,92 @@ +/* + * randnum.c -- generate (good) randum numbers. + * + * Copyright (C) 2001 by Theodore Ts'o + * + * This file may be distributed under the terms of the GNU Public + * License. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include "pwgen.h" + +#ifdef HAVE_DRAND48 +extern double drand48(); +#endif + +/* Borrowed/adapted from e2fsprogs's UUID generation code */ +static int get_random_fd(void) +{ + struct timeval tv; + static int fd = -2; + int i; + + if (fd == -2) { + gettimeofday(&tv, 0); + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + fd = open("/dev/random", O_RDONLY | O_NONBLOCK); +#ifdef HAVE_DRAND48 + srand48((tv.tv_sec<<9) ^ (getpgrp()<<15) ^ + (getpid()) ^ (tv.tv_usec>>11)); +#else + srandom((getpid() << 16) ^ (getpgrp() << 8) ^ getuid() + ^ tv.tv_sec ^ tv.tv_usec); +#endif + } + /* Crank the random number generator a few times */ + gettimeofday(&tv, 0); + for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) +#ifdef HAVE_DRAND48 + drand48(); +#else + rand(); +#endif + return fd; +} + +/* + * Generate a random number n, where 0 <= n < max_num, using + * /dev/urandom if possible. + */ +int pw_random_number(int max_num) +{ + int i, fd = get_random_fd(); + int lose_counter = 0, nbytes=4; + unsigned int rand; + char *cp = (char *) &rand; + + if (fd >= 0) { + while (nbytes > 0) { + i = read(fd, cp, nbytes); + if ((i < 0) && + ((errno == EINTR) || (errno == EAGAIN))) + continue; + if (i <= 0) { + if (lose_counter++ == 8) + break; + continue; + } + nbytes -= i; + cp += i; + lose_counter = 0; + } + } + if (nbytes == 0) + return (rand % max_num); + + /* OK, we weren't able to use /dev/random, fall back to rand/rand48 */ + +#ifdef RAND48 + return ((int) ((drand48() * max_num))); +#else + return ((int) (random() / ((float) RAND_MAX) * max_num)); +#endif +} |