doc: reference fmt(1) from fold(1)
[coreutils.git] / gl / lib / randread.c
blob3eaf19e1580e632c31de4bd5b59b063a8bbcdebb
1 /* Generate buffers of random data.
3 Copyright (C) 2006-2022 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert. */
20 /* FIXME: Improve performance by adding support for the RDRAND machine
21 instruction if available (e.g., Ivy Bridge processors). */
23 #include <config.h>
25 #include "randread.h"
27 #include <errno.h>
28 #include <error.h>
29 #include <exitfail.h>
30 #include <fcntl.h>
31 #include <quote.h>
32 #include <stdalign.h>
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/random.h>
40 #include "gettext.h"
41 #define _(msgid) gettext (msgid)
43 #include "minmax.h"
44 #include "rand-isaac.h"
45 #include "stdio-safer.h"
46 #include "unlocked-io.h"
47 #include "xalloc.h"
49 #if _STRING_ARCH_unaligned || _STRING_INLINE_unaligned
50 # define ALIGNED_POINTER(ptr, type) true
51 #else
52 # define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0)
53 #endif
55 /* The maximum buffer size used for reads of random data. Using the
56 value 2 * ISAAC_BYTES makes this the largest power of two that
57 would not otherwise cause struct randread_source to grow. */
58 #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
60 /* A source of random data for generating random buffers. */
61 struct randread_source
63 /* Stream to read random bytes from. If null, the current
64 implementation uses an internal PRNG (ISAAC). */
65 FILE *source;
67 /* Function to call, and its argument, if there is an input error or
68 end of file when reading from the stream; errno is nonzero if
69 there was an error. If this function returns, it should fix the
70 problem before returning. The default handler assumes that
71 handler_arg is the file name of the source. */
72 void (*handler) (void const *);
73 void const *handler_arg;
75 /* The buffer for SOURCE. It's kept here to simplify storage
76 allocation and to make it easier to clear out buffered random
77 data. */
78 union
80 /* The stream buffer, if SOURCE is not null. */
81 char c[RANDREAD_BUFFER_SIZE];
83 /* The buffered ISAAC pseudorandom buffer, if SOURCE is null. */
84 struct isaac
86 /* The number of bytes that are buffered at the end of data.b. */
87 size_t buffered;
89 /* State of the ISAAC generator. */
90 struct isaac_state state;
92 /* Up to a buffer's worth of pseudorandom data. */
93 union
95 isaac_word w[ISAAC_WORDS];
96 unsigned char b[ISAAC_BYTES];
97 } data;
98 } isaac;
99 } buf;
103 /* The default error handler. */
105 static void
106 randread_error (void const *file_name)
108 if (file_name)
109 error (exit_failure, errno,
110 errno == 0 ? _("%s: end of file") : _("%s: read error"),
111 quote (file_name));
112 abort ();
115 /* Simply return a new randread_source object with the default error
116 handler. */
118 static struct randread_source *
119 simple_new (FILE *source, void const *handler_arg)
121 struct randread_source *s = xmalloc (sizeof *s);
122 s->source = source;
123 s->handler = randread_error;
124 s->handler_arg = handler_arg;
125 return s;
128 /* Put a nonce value into BUFFER, with size BUFSIZE.
129 Return true on success, false (setting errno) on failure. */
131 static bool
132 get_nonce (void *buffer, size_t bufsize)
134 char *buf = buffer, *buflim = buf + bufsize;
135 while (buf < buflim)
137 ssize_t nbytes = getrandom (buf, buflim - buf, 0);
138 if (0 <= nbytes)
139 buf += nbytes;
140 else if (errno != EINTR)
141 return false;
143 return true;
146 /* Body of randread_free, broken out to pacify gcc -Wmismatched-dealloc. */
148 static int
149 randread_free_body (struct randread_source *s)
151 FILE *source = s->source;
152 explicit_bzero (s, sizeof *s);
153 free (s);
154 return source ? fclose (source) : 0;
157 /* Create and initialize a random data source from NAME, or use a
158 reasonable default source if NAME is null. BYTES_BOUND is an upper
159 bound on the number of bytes that will be needed. If zero, it is a
160 hard bound; otherwise it is just an estimate.
162 If NAME is not null, NAME is saved for use as the argument of the
163 default handler. Unless a non-default handler is used, NAME's
164 lifetime should be at least that of the returned value.
166 Return NULL (setting errno) on failure. */
168 struct randread_source *
169 randread_new (char const *name, size_t bytes_bound)
171 if (bytes_bound == 0)
172 return simple_new (NULL, NULL);
173 else
175 FILE *source = NULL;
176 struct randread_source *s;
178 if (name)
179 if (! (source = fopen_safer (name, "rb")))
180 return NULL;
182 s = simple_new (source, name);
184 if (source)
185 setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
186 else
188 s->buf.isaac.buffered = 0;
189 if (! get_nonce (s->buf.isaac.state.m,
190 MIN (sizeof s->buf.isaac.state.m, bytes_bound)))
192 int e = errno;
193 randread_free_body (s);
194 errno = e;
195 return NULL;
197 isaac_seed (&s->buf.isaac.state);
200 return s;
205 /* Set S's handler and its argument. HANDLER (HANDLER_ARG) is called
206 when there is a read error or end of file from the random data
207 source; errno is nonzero if there was an error. If HANDLER
208 returns, it should fix the problem before returning. The default
209 handler assumes that handler_arg is the file name of the source; it
210 does not return. */
212 void
213 randread_set_handler (struct randread_source *s, void (*handler) (void const *))
215 s->handler = handler;
218 void
219 randread_set_handler_arg (struct randread_source *s, void const *handler_arg)
221 s->handler_arg = handler_arg;
225 /* Place SIZE random bytes into the buffer beginning at P, using
226 the stream in S. */
228 static void
229 readsource (struct randread_source *s, unsigned char *p, size_t size)
231 while (true)
233 size_t inbytes = fread (p, sizeof *p, size, s->source);
234 int fread_errno = errno;
235 p += inbytes;
236 size -= inbytes;
237 if (size == 0)
238 break;
239 errno = (ferror (s->source) ? fread_errno : 0);
240 s->handler (s->handler_arg);
245 /* Place SIZE pseudorandom bytes into the buffer beginning at P, using
246 the buffered ISAAC generator in ISAAC. */
248 static void
249 readisaac (struct isaac *isaac, void *p, size_t size)
251 size_t inbytes = isaac->buffered;
253 while (true)
255 char *char_p = p;
257 if (size <= inbytes)
259 memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
260 isaac->buffered = inbytes - size;
261 return;
264 memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
265 p = char_p + inbytes;
266 size -= inbytes;
268 /* If P is aligned, write to *P directly to avoid the overhead
269 of copying from the buffer. */
270 if (ALIGNED_POINTER (p, isaac_word))
272 isaac_word *wp = p;
273 while (ISAAC_BYTES <= size)
275 isaac_refill (&isaac->state, wp);
276 wp += ISAAC_WORDS;
277 size -= ISAAC_BYTES;
278 if (size == 0)
280 isaac->buffered = 0;
281 return;
284 p = wp;
287 isaac_refill (&isaac->state, isaac->data.w);
288 inbytes = ISAAC_BYTES;
293 /* Consume random data from *S to generate a random buffer BUF of size
294 SIZE. */
296 void
297 randread (struct randread_source *s, void *buf, size_t size)
299 if (s->source)
300 readsource (s, buf, size);
301 else
302 readisaac (&s->buf.isaac, buf, size);
306 /* Clear *S so that it no longer contains undelivered random data, and
307 deallocate any system resources associated with *S. Return 0 if
308 successful, a negative number (setting errno) if not (this is rare,
309 but can occur in theory if there is an input error). */
312 randread_free (struct randread_source *s)
314 return randread_free_body (s);