/* See LICENSE file for copyright and license details. */ #include "common.h" static char reservoir[128U << 10]; static size_t reservoir_off = sizeof(reservoir); static int random_fd; static const char *random_fname; size_t max_blksize(void) { size_t ret = sizeof(reservoir); while (ret & (ret - 1U)) ret &= ret - 1U; return ret; } void init_random(int fd, const char *fname) { struct stat st; random_fname = fname; random_fd = fd; 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); } } const char * get_random(size_t needed) { size_t off; ssize_t r; if (sizeof(reservoir) - 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; }