1 /* random.c -- Functions for managing 16-bit and 32-bit random numbers. */
3 /* Copyright (C) 2020 Free Software Foundation, Inc.
5 This file is part of GNU Bush, the Bourne Again SHell.
7 Bush is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bush is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bush. If not, see <http://www.gnu.org/licenses/>.
23 #include "bushtypes.h"
25 #if defined (HAVE_SYS_RANDOM_H)
26 # include <sys/random.h>
29 #if defined (HAVE_UNISTD_H)
39 extern time_t shell_start_time
;
41 extern int last_random_value
;
43 static u_bits32_t intrand32
PARAMS((u_bits32_t
));
44 static u_bits32_t genseed
PARAMS((void));
46 static u_bits32_t brand32
PARAMS((void));
47 static void sbrand32
PARAMS((u_bits32_t
));
48 static void perturb_rand32
PARAMS((void));
50 /* The random number seed. You can change this by setting RANDOM. */
51 static u_bits32_t rseed
= 1;
53 /* Returns a 32-bit pseudo-random number. */
58 /* Minimal Standard generator from
59 "Random number generators: good ones are hard to find",
60 Park and Miller, Communications of the ACM, vol. 31, no. 10,
61 October 1988, p. 1195. Filtered through FreeBSD.
63 x(n+1) = 16807 * x(n) mod (m).
65 We split up the calculations to avoid overflow.
67 h = last / q; l = x - h * q; t = a * l - h * r
68 m = 2147483647, a = 16807, q = 127773, r = 2836
70 There are lots of other combinations of constants to use; look at
71 https://www.gnu.org/software/gsl/manual/html_node/Other-random-number-generators.html#Other-random-number-generators */
76 /* Can't seed with 0. */
77 ret
= (last
== 0) ? 123459876 : last
;
79 l
= ret
- (127773 * h
);
80 t
= 16807 * l
- 2836 * h
;
81 ret
= (t
< 0) ? t
+ 0x7fffffff : t
;
92 gettimeofday (&tv
, NULL
);
93 iv
= (u_bits32_t
)seedrand
; /* let the compiler truncate */
94 iv
= tv
.tv_sec
^ tv
.tv_usec
^ getpid () ^ getppid () ^ current_user
.uid
^ iv
;
98 #define BUSH_RAND_MAX 32767 /* 0x7fff - 16 bits */
100 /* Returns a pseudo-random number between 0 and 32767. */
106 rseed
= intrand32 (rseed
);
107 if (shell_compatibility_level
> 50)
108 ret
= (rseed
>> 16) ^ (rseed
& 65535);
111 return (ret
& BUSH_RAND_MAX
);
114 /* Set the random number generator seed to SEED. */
120 last_random_value
= 0;
132 static u_bits32_t rseed32
= 1073741823;
133 static int last_rand32
;
135 static int urandfd
= -1;
137 #define BUSH_RAND32_MAX 0x7fffffff /* 32 bits */
139 /* Returns a 32-bit pseudo-random number between 0 and 4294967295. */
145 rseed32
= intrand32 (rseed32
);
146 return (rseed32
& BUSH_RAND32_MAX
);
153 last_rand32
= rseed32
= seed
;
168 rseed32
^= genseed ();
171 /* Force another attempt to open /dev/urandom on the next call to get_urandom32 */
180 #if !defined (HAVE_GETRANDOM)
181 /* Imperfect emulation of getrandom(2). */
182 #ifndef GRND_NONBLOCK
183 # define GRND_NONBLOCK 1
184 # define GRND_RANDOM 2
188 getrandom (buf
, len
, flags
)
195 static int urand_unavail
= 0;
198 r
= getentropy (buf
, len
);
199 return (r
== 0) ? len
: -1;
202 if (urandfd
== -1 && urand_unavail
== 0)
205 if (flags
& GRND_NONBLOCK
)
206 oflags
|= O_NONBLOCK
;
207 urandfd
= open ("/dev/urandom", oflags
, 0);
209 SET_CLOSE_ON_EXEC (urandfd
);
216 if (urandfd
>= 0 && (r
= read (urandfd
, buf
, len
)) == len
)
227 if (getrandom ((void *)&ret
, sizeof (ret
), GRND_NONBLOCK
) == sizeof (ret
))
228 return (last_rand32
= ret
);
230 #if defined (HAVE_ARC4RANDOM)
233 if (subshell_environment
)
237 while (ret
== last_rand32
);
239 return (last_rand32
= ret
);