From 22ade138c4e83b7c0b0c702c38c0ca00a9948d4b Mon Sep 17 00:00:00 2001 From: bryan Date: Wed, 26 Aug 2026 15:16:23 +0200 Subject: Replace the placeholder with a suckless C rg. rg prints n cryptographically random strings of length l, matching rg.veltar.systems. Bytes come from getrandom(2) on Linux and rand_s on Windows. make selects clang and .exe when OS=Windows_NT. --- rg.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 rg.c (limited to 'rg.c') diff --git a/rg.c b/rg.c new file mode 100644 index 0000000..9191956 --- /dev/null +++ b/rg.c @@ -0,0 +1,185 @@ +/* See LICENSE file for copyright and license details. */ +#ifdef __linux__ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#endif +#ifdef _WIN32 +#ifndef _CRT_RAND_S +#define _CRT_RAND_S +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#endif + +#include "arg.h" +#include "config.h" + +char *argv0; + +static unsigned char rbuf[256]; +static size_t rpos = sizeof rbuf; + +static void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-v] [-n n] [-l l]\n", argv0 ? argv0 : "rg"); + exit(1); +} + +static int +fillrand(unsigned char *buf, size_t n) +{ +#ifdef _WIN32 + size_t i; + unsigned int r; + int k; + + for (i = 0; i < n; ) { + if (rand_s(&r) != 0) + return -1; + for (k = 0; k < 4 && i < n; k++) + buf[i++] = (unsigned char)(r >> (8 * k)); + } + return 0; +#else + size_t off; + ssize_t r; + + off = 0; + while (off < n) { + r = getrandom(buf + off, n - off, 0); + if (r < 0) { + if (errno == EINTR) + continue; + return -1; + } + if (r == 0) + return -1; + off += (size_t)r; + } + return 0; +#endif +} + +static unsigned char +randbyte(void) +{ + if (rpos >= sizeof rbuf) { + if (fillrand(rbuf, sizeof rbuf) < 0) + die("rg: rng:"); + rpos = 0; + } + return rbuf[rpos++]; +} + +static uint32_t +randu32(void) +{ + return ((uint32_t)randbyte() << 24) | + ((uint32_t)randbyte() << 16) | + ((uint32_t)randbyte() << 8) | + (uint32_t)randbyte(); +} + +static uint32_t +randbelow(uint32_t n) +{ + uint32_t x, min; + + if (n <= 1) + return 0; + /* reject [0, 2^32 % n) so x % n is unbiased */ + min = (uint32_t)(-n) % n; + do { + x = randu32(); + } while (x < min); + return x % n; +} + +static int +eint(const char *s) +{ + char *end; + long v; + + if (s == NULL || s[0] == '\0') + usage(); + errno = 0; + v = strtol(s, &end, 10); + if (errno || end == s || *end != '\0' || v < INT_MIN || v > INT_MAX) + die("rg: invalid number '%s'", s); + return (int)v; +} + +int +main(int argc, char *argv[]) +{ + int i, j, n, l, alen; + + n = defn; + l = defl; + + ARGBEGIN { + case 'n': + n = eint(EARGF(usage())); + break; + case 'l': + l = eint(EARGF(usage())); + break; + case 'v': + puts("rg-" VERSION); + return 0; + default: + usage(); + } ARGEND + + if (argc) + usage(); + if (n < minn || n > maxn) + die("rg: n must be %d..%d", minn, maxn); + if (l < minl || l > maxl) + die("rg: l must be %d..%d", minl, maxl); + + alen = (int)strlen(alphabet); + if (alen < 1) + die("rg: empty alphabet"); + + for (i = 0; i < n; i++) { + for (j = 0; j < l; j++) + putchar(alphabet[randbelow((uint32_t)alen)]); + putchar('\n'); + } + + return 0; +} -- cgit v1.2.3