/* See LICENSE file for copyright and license details. */ #include "common.h" static char *reservoir; static size_t reservoir_off; static size_t reservoir_size; static int random_fd; static const char *random_fname; void init_random(int fd, const char *fname, off_t blksize) { struct stat st; if (blksize <= 0) { blksize = (off_t)64 << 20; } else if (blksize > (off_t)1 << 30) { weprintf("limiting block size to 1G"); blksize = 1; blksize <<= 30; } random_fname = fname; random_fd = fd; reservoir_size = (size_t)blksize; reservoir = emalloc(reservoir_size); errno = 0; if (isatty(random_fd) || errno == EBADF) { use_builtin_generator: random_fd = -1; libsimple_srand(); } else if (fstat(random_fd, &st)) { if (errno == EBADF) goto use_builtin_generator; eprintf("fstat %s:", random_fname); } else if (S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode)) { eprintf("%s is of a unsupported inode type (must be TTY, character device, FIFO, or socket)", fname); } } void destroy_random(void) { free(reservoir); } size_t max_blksize(void) { return reservoir_size; } const char * get_random(size_t needed) { size_t off; ssize_t r; if (reservoir_size - reservoir_off >= needed) return &reservoir[reservoir_off]; if (random_fd < 0) { libsimple_random_bytes(&libsimple_random_bits, NULL, reservoir, reservoir_off); reservoir_off = 0; return reservoir; } for (off = 0; off < reservoir_off;) { r = read(random_fd, &reservoir[off], reservoir_off - off); if (r <= 0) { if (!r) eprintf("random source depleted"); if (errno == EINTR) continue; eprintf("read %s:", random_fname); } off += (size_t)r; } reservoir_off = 0; return reservoir; } void used_random(ssize_t amount) { reservoir_off += (size_t)amount; }