// this file: // https://dataswamp.org/~incal/emacs-init/random-urandom/random-urandom.c #include "random-urandom.h" #include #include #include #include #include #include #include #include int plugin_is_GPL_compatible; int emacs_module_init(struct emacs_runtime* runtime) { if (runtime->size < (long int)sizeof(*runtime)) { return 1; // incompatible Emacs binary } emacs_env* env = runtime->get_environment(runtime); if (env->size < (long int)sizeof(*env)) { return 2; // incompatible module API } int __attribute__((unused)) emacs_version; if ((long int)sizeof(struct emacs_env_29) <= env->size) { emacs_version = 29; } else { return 3; // too old Emacs } emacs_value rur_func = env->make_function(env, 0, 0, random_urandom, NULL, NULL); emacs_value rur_symbol = env->intern(env, "random-urandom"); emacs_value args[] = {rur_symbol, rur_func}; env->funcall(env, env->intern(env, "defalias"), 2, args); return 0; } // originally from pwgen(1) version 2.08, Debian 11 // https://github.com/tytso/pwgen static int get_random_fd() { struct timeval tv; static int fd = -2; if (fd == -2) { gettimeofday(&tv, 0); fd = open("/dev/urandom", O_RDONLY); if (fd == -1) { fd = open("/dev/random", O_RDONLY | O_NONBLOCK); } } return fd; } unsigned int pw_random_number() { unsigned int rnd_num; unsigned int max_num = UINT_MAX; int fd = get_random_fd(); int lose_counter = 0; long unsigned int nbytes = sizeof(rnd_num); char* cp = (char*)&rnd_num; int i; 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 (close(fd) != 0) { fprintf(stderr, "Error closing file.\n"); exit(1); } if (nbytes == 0) { return (rnd_num % max_num); } else { fprintf(stderr, "No entropy available.\n"); exit(1); } } emacs_value random_urandom(emacs_env* env, ptrdiff_t nargs __attribute__((unused)), emacs_value* args __attribute__((unused)), void* data __attribute__((unused))) { emacs_value rnd_num = env->make_integer(env, pw_random_number()); return rnd_num; }